Skip to content

perf(extensions): clean sandbox lifecycle handles#550

Closed
JustYannicc wants to merge 1 commit into
SuperCmdLabs:mainfrom
JustYannicc:codex/perf-extension-sandbox-lifecycle-pr
Closed

perf(extensions): clean sandbox lifecycle handles#550
JustYannicc wants to merge 1 commit into
SuperCmdLabs:mainfrom
JustYannicc:codex/perf-extension-sandbox-lifecycle-pr

Conversation

@JustYannicc

Copy link
Copy Markdown
Collaborator

What changed

  • Added a per-ExtensionView lifecycle scope that gives extension bundles scoped window and document objects during evaluation.
  • Routed window.setInterval, window.setTimeout, window.requestAnimationFrame, window.addEventListener, and matching document listener APIs through the existing cleanup registry.
  • Preserved bare timer cleanup and added cleanup metadata so handles are cleared through the host object that created them.
  • Added a lifecycle harness that reproduces the pre-fix window.* leak and verifies cleanup on unmount and re-evaluation.

Why

Extension bundles could bypass the existing bare timer registry by calling window.* APIs from module scope or effects. No-view/background runs and remounted menu-bar extensions could then leave renderer DOM timers/listeners alive after the ExtensionView instance was gone.

Compatibility impact

  • The scoped objects delegate ordinary reads and methods to the host window/document, including window.document, window.navigator, window.location, and window.electron.
  • window, self, global, and globalThis resolve to the same scoped object inside the extension wrapper.
  • Host renderer globals are not mutated; the scope is passed only as wrapper lexical arguments.
  • Extensions that clean up their own timers/listeners still work: clear/remove calls untrack the registry before delegating.

Lifecycle evidence

node --test scripts/test-extension-lifecycle-sandbox.mjs:

  • Pre-fix simulation: cleanup leaves intervals=1, windowListeners=1, documentListeners=1, total=3.
  • Scoped cleanup: starts with the same total=3, registry sees intervals=1 and eventListeners=2, cleanup ends at total=0.
  • Re-evaluation: 3 -> 0 -> 3 -> 0 across prior evaluation cleanup and final unmount.

How tested

  • node --test scripts/test-extension-lifecycle-sandbox.mjs
  • ./node_modules/.bin/vite build
  • LSP diagnostics for src/renderer/src/ExtensionView.tsx: no errors
  • ./node_modules/.bin/tsc -p tsconfig.renderer.json --noEmit was run and still fails on existing unrelated origin/main renderer type errors, including App.tsx, CameraExtension.tsx, raycast-api, settings, and quicklink icon typings.

Stack validation

@JustYannicc

Copy link
Copy Markdown
Collaborator Author

Superseded by consolidated runtime lifecycle/icon churn PR #558: #558

@JustYannicc JustYannicc closed this Jul 3, 2026
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.

1 participant