fix: bypass third-party custom-elements-es5-adapter that breaks native class constructors (#1458)#1459
Merged
Merged
Conversation
…1458) Problem ------- Pages that ship custom-elements-es5-adapter.js (notably YouTube) monkey-patch customElements.define(). The adapter wraps every registered constructor, assuming it was transpiled to ES5. When our native ES6 class (VSCControllerElement extends HTMLElement) passes through the wrapper, the wrapper tries to call the constructor without `new`, producing: "Class constructor _VSCControllerElement cannot be invoked without 'new'" The previous mitigation (f5c463d) captured the native define() reference in constants.js before the adapter could patch it. This fails because inject.js loads via an async <script src> tag — the page's adapter can execute first, so the "saved" reference is already the patched version. Root cause ---------- There is no way to guarantee our inject.js runs before arbitrary page scripts when using the <script src="chrome-extension://..."> injection pattern. The load order depends on network timing and browser scheduling, making this a non-deterministic race condition. Solution -------- Stop calling customElements.define() entirely. The <vsc-controller> tag name requires no registration to function correctly: - document.createElement('vsc-controller') returns a valid HTMLElement for any hyphenated name, registered or not - CSS tag selectors (vsc-controller { ... }) match by tag name, not registration status - querySelector('vsc-controller') is a pure DOM query, unaffected - element.attachShadow() works on any valid custom element name - element.tagName === 'VSC-CONTROLLER' is set at creation time The removed VSCControllerElement class had no functional lifecycle logic — connectedCallback and disconnectedCallback only emitted debug log messages. This eliminates the entire class of es5-adapter conflicts because the adapter's monkey-patch of customElements.define() is never invoked.
igrigorik
force-pushed
the
claude/diagnose-audit-1458-6E4RD
branch
from
March 27, 2026 16:38
ebd1a9f to
040353e
Compare
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.
Capture the native customElements.define() early in the bundle before
any third-party ES5 adapter can monkey-patch it. Use the saved reference
when registering the vsc-controller custom element, preventing the
"Class constructor _VSCControllerElement cannot be invoked without 'new'"
error caused by the adapter's incompatible wrapper around native ES6 classes.