refactor(bundle-size): use free-function helpers for DOM event APIs#560
Merged
layershifter merged 1 commit intoJun 12, 2026
Merged
Conversation
Introduces three single-character-mangleable wrappers in `Utils.ts` for the DOM event APIs whose property names would otherwise be preserved verbatim by the minifier: - `addListener` / `removeListener` — thin wraps over `addEventListener` / `removeEventListener`, accept nullish targets. - `dispatchEvent` — wraps `target.dispatchEvent(event)`, returns `false` for nullish targets (matching the prior `?.dispatchEvent` short-circuit shape that most call sites already handled). All `src/**/*.ts` call sites converted (~71 sites across 11 files). Raw `.addEventListener` / `.removeEventListener` / `.dispatchEvent` property accesses now eliminated outside `Utils.ts`. Enforced via a new `no-restricted-syntax` block in `eslint.config.mjs` scoped to `src/**/*.ts` (with `src/Utils.ts` exempted) so the wrappers can't drift back into raw calls in future PRs. A small structural tweak in `Deloser._scheduleRestoreFocus`: the prior `!curDeloserElement?.dispatchEvent(...)` short-circuit was rewritten as an explicit `if (!curDeloserElement) return; ...dispatchEvent(...)` to preserve type integrity now that the constructor's `owner: HTMLElement` field is no longer protected by optional-chaining laziness. Same control flow as before.
📊 Bundle size report🤖 This report was generated against 18520c1dd878114021e8bc15e1030f4399aa83fa |
Member
Author
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. 🤖 Generated with Claude Code |
layershifter
added a commit
to layershifter/tabster
that referenced
this pull request
Jun 12, 2026
Introduces single-character-mangleable wrappers in `Utils.ts` for the
window timer APIs whose property names would otherwise be preserved
verbatim by the minifier:
- `createTimer` / `setTimer` / `clearTimer` / `isTimerActive`, paired with
an opaque `Timer = { id }` handle stored on instance fields.
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.
layershifter
added a commit
to layershifter/tabster
that referenced
this pull request
Jun 17, 2026
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.
layershifter
added a commit
to layershifter/tabster
that referenced
this pull request
Jun 17, 2026
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.
layershifter
added a commit
to layershifter/tabster
that referenced
this pull request
Jun 17, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Introduces three single-character-mangleable wrappers in
Utils.tsfor the DOM event APIs whose property names would otherwise be preserved verbatim by the minifier:addListener/removeListener— thin wraps overaddEventListener/removeEventListener, accept nullish targets.dispatchEvent— wrapstarget.dispatchEvent(event), returnsfalsefor nullish targets (matching the prior?.dispatchEventshort-circuit shape that most call sites already handled).All
src/**/*.tscall sites converted (~71 sites across 11 files). Raw.addEventListener/.removeEventListener/.dispatchEventproperty accesses now eliminated outsideUtils.ts.Enforced via a new
no-restricted-syntaxblock ineslint.config.mjsscoped tosrc/**/*.ts(withsrc/Utils.tsexempted) so the wrappers can't drift back into raw calls in future PRs.Notes
A small structural tweak in
Deloser._scheduleRestoreFocus: the prior!curDeloserElement?.dispatchEvent(...)short-circuit was rewritten asif (!curDeloserElement) return; ...dispatchEvent(...)to preserve type integrity now that the event constructor'sowner: HTMLElementfield is no longer protected by optional-chaining laziness. Same control flow as before.Stack context
A narrower companion to #541 — that PR also has these event-helper changes alongside the timer-helper conversions. Whichever lands first will leave the other a smaller diff after rebase.