Skip to content

refactor(bundle-size): use free-function helpers for timers#541

Open
layershifter wants to merge 1 commit into
microsoft:masterfrom
layershifter:chore/bundle-size-stack-4
Open

refactor(bundle-size): use free-function helpers for timers#541
layershifter wants to merge 1 commit into
microsoft:masterfrom
layershifter:chore/bundle-size-stack-4

Conversation

@layershifter

@layershifter layershifter commented May 11, 2026

Copy link
Copy Markdown
Member

Summary

Introduces single-character-mangleable wrappers in Utils.ts for the window timer APIs whose property names would otherwise be preserved verbatim by the minifier:

  • setTimer / clearTimer / isTimerActive, operating on an opaque Timer = { id } handle stored on instance fields.

setTimer(t, window, callback, delay) lazily creates the Timer when passed undefined and returns it, so callers just write this._timer = setTimer(this._timer, …) — no separate constructor-time allocation. Timer.id is typed as ReturnType<typeof setTimeout> so the id round-trips through window.setTimeout / clearTimeout without a cast; undefined is the not-pending sentinel.

All src/**/*.ts call sites converted; raw .setTimeout / .clearTimeout property accesses now eliminated outside Utils.ts.

Enforced via two additional no-restricted-syntax entries in eslint.config.mjs (next to the existing event-helper rules from #560) so the wrappers can't drift back into raw timer calls in future PRs.

Stack context

Follow-up to #560 — same wrapper pattern applied to timer APIs.

@github-actions

github-actions Bot commented May 11, 2026

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
tabster
all exports
110.491 kB
29.988 kB
108.903 kB
29.92 kB
-1.588 kB
-68 B
tabster
createTabster (core)
38.098 kB
11.41 kB
37.689 kB
11.452 kB
-409 B
42 B
tabster
focusable.findAll
38.121 kB
11.418 kB
37.712 kB
11.46 kB
-409 B
42 B
tabster
focusable.findLast
38.122 kB
11.418 kB
37.713 kB
11.46 kB
-409 B
42 B
tabster
focusable.findNext
38.122 kB
11.418 kB
37.713 kB
11.46 kB
-409 B
42 B
tabster
focusable.findPrev
38.122 kB
11.418 kB
37.713 kB
11.46 kB
-409 B
42 B
tabster
getCrossOrigin
107.424 kB
29.275 kB
105.836 kB
29.194 kB
-1.588 kB
-81 B
tabster
getDeloser
47.459 kB
13.693 kB
46.87 kB
13.723 kB
-589 B
30 B
tabster
getGroupper
45.2 kB
13.071 kB
44.665 kB
13.109 kB
-535 B
38 B
tabster
getModalizer
47.125 kB
13.835 kB
46.631 kB
13.859 kB
-494 B
24 B
tabster
getMover
52.657 kB
15.331 kB
51.898 kB
15.332 kB
-759 B
1 B
tabster
getObservedElement
43.877 kB
12.978 kB
43.416 kB
13.02 kB
-461 B
42 B
tabster
getOutline
46.733 kB
13.653 kB
46.132 kB
13.682 kB
-601 B
29 B
tabster
getRestorer
40.683 kB
12.006 kB
40.275 kB
12.054 kB
-408 B
48 B

🤖 This report was generated against 711667861375e72636f73d33df9c8d8644ae45cd

@layershifter
layershifter force-pushed the chore/bundle-size-stack-4 branch 3 times, most recently from a844939 to c86ee2e Compare June 11, 2026 13:37
@layershifter
layershifter force-pushed the chore/bundle-size-stack-4 branch from c86ee2e to 14a3875 Compare June 12, 2026 09:55
@layershifter layershifter changed the title refactor(bundle-size): use free-function helpers for events and timers refactor(bundle-size): use free-function helpers for timers Jun 12, 2026
@layershifter
layershifter force-pushed the chore/bundle-size-stack-4 branch 2 times, most recently from 33ec628 to fe69479 Compare June 17, 2026 14:21
@layershifter
layershifter requested a review from Copilot June 17, 2026 14:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors Tabster’s internal use of window timer APIs to route through new free-function helpers in src/Utils.ts, allowing minification to mangle helper names (and avoid preserving .setTimeout/.clearTimeout property names) while enforcing the pattern via ESLint.

Changes:

  • Added Timer handle type plus setTimer, clearTimer, and isTimerActive helpers in src/Utils.ts.
  • Converted timer usage across src/**/*.ts to use the new helpers instead of direct .setTimeout/.clearTimeout calls.
  • Updated eslint.config.mjs to restrict .setTimeout/.clearTimeout usage outside src/Utils.ts.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Utils.ts Introduces Timer and the timer helper functions; updates existing instance-context timer usage.
src/Tabster.ts Migrates core init/cleanup timers to Timer + helpers.
src/State/ObservedElement.ts Converts waiting/condition timers to Timer handles and helper calls.
src/State/FocusedElement.ts Migrates async focus and tabbing timers to helper API.
src/Root.ts Converts focus/blur debounce timer to helper API.
src/Outline.ts Converts outline update scheduling timer to helper API.
src/Mover.ts Migrates mover scheduling/update timers and ignored-input timer to helper API.
src/Modalizer.ts Converts hidden update and restore-focus timers to helper API.
src/Groupper.ts Converts groupper update timer to helper API.
src/DummyInput.ts Migrates dummy-input disposal and observer scheduling timers to helper API.
src/Deloser.ts Converts restore-focus timer to helper API.
src/CrossOrigin.ts Migrates cross-origin transaction, ping, and blur timers to helper API.
eslint.config.mjs Adds no-restricted-syntax rules to prevent raw .setTimeout/.clearTimeout calls in src/**.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Utils.ts
Comment on lines +620 to +622
export interface Timer {
id: ReturnType<typeof setTimeout> | undefined;
}
Comment thread eslint.config.mjs
Introduces single-character-mangleable wrappers in `Utils.ts` for the
window timer APIs whose property names would otherwise be preserved
verbatim by the minifier:

- `setTimer` / `clearTimer` / `isTimerActive`, operating on an opaque
  `Timer = { id }` handle stored on instance fields.

`setTimer(t, window, callback, delay)` lazily creates the `Timer` when
passed `undefined` and returns it, so callers just write
`this._timer = setTimer(this._timer, ...)` — no separate constructor-time
allocation. `Timer.id` is typed as `ReturnType<typeof setTimeout>` so the
id round-trips through `window.setTimeout` / `clearTimeout` without a cast;
`undefined` is the not-pending sentinel.

All `src/**/*.ts` call sites converted; raw `.setTimeout` / `.clearTimeout`
property accesses now eliminated outside `Utils.ts`.

Enforced via two additional `no-restricted-syntax` entries in
`eslint.config.mjs` (next to the existing event-helper rules from microsoft#560)
so the wrappers can't drift back into raw timer calls in future PRs.

Follow-up to microsoft#560 — same pattern applied to timer APIs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@layershifter
layershifter force-pushed the chore/bundle-size-stack-4 branch from 0a9db99 to bb51db4 Compare June 17, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants