#109: Custom Elements — OwnCustomElementRegistry + Parser-Integration + Lifecycle #109
Labels
No labels
bug
docs
feature
housekeeping
html-spec
performance
react-compat
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
glow-all/true-headless-browser#109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problembeschreibung
CustomElementRegistry (
customElements) ist aktuell ein leeres Objekt ohne Funktionalitat. Viele moderne Frameworks und Bibliotheken nutzen Custom Elements:@customElement('my-el')registriert + definiert<my-component>viacustomElements.define()Ohne Custom Elements: Framework-Crash beim
customElements.define(), keine Lifecycle-Callbacks, keinconnectedCallback.Architektur-Analyse
Aktueller Stand
Ziel-Architektur — Non-Visual-Optimized
Non-Visual Optimierungen
formAssociated: trueindefine()wird ignoriert — keinformAssociatedCallback,formResetCallback,formDisabledCallbackattachShadow()arbeiten mit normalem DOM (frameworks tun das)define()lost sofort Upgrades fur bereits existierende Elemente aus — kein Microtask-Queueing (einfacher, spec-konform fur Promise-basierte define-Aufrufe)is-Attribut:extends: "button"indefine()wird ignoriert (selten genutzt, fur Headless irrelevant)Root Causes
define():customElements.define(name, constructor)registriert nichtget()/whenDefined(): Framework-checks schlagen fehlupgrade(): Existierende Elemente werden nicht upgradedobservedAttributes-Check:attributeChangedCallbackfeuert nie<my-component>wird als generic Element statt als Custom-Element-Konstruktor erzeugtLosungsansatze
Option A (empfohlen): Spec-konformes CustomElementRegistry mit Parser-Integration
Kernidee: CustomElementRegistry speichert name→constructor in einer Map. Parser-Callback erzeugt bei bekannten Custom-Element-Namen den registrierten Konstruktor statt des generischen Elements. Lifecycle-Callbacks werden bei appendChild/removeChild/setAttribute aufgerufen.
Teil 1: CustomElementRegistry
Teil 2: Parser-Integration
Teil 3: Lifecycle-Hooks in Node/Element
Teil 4: attributeChangedCallback-Trigger
Vorteile:
<my-el>und erzeugt korrekten KonstruktorwhenDefined()Promise-basiert fur Framework-Async-InitNachteile:
is-Attribut-Support (selten genutzt)define()verwendet synchrones Tree-Walk (kann bei großem DOM langsam sein)Option B: Happy DOMs CustomElementRegistry recyceln
Happy DOM hat
window.customElements. Dieses Objekt direkt importieren.Problem: Happy DOMs Registry erwartet Happy-DOM-Elemente als Konstruktor-Basis. Unser OwnDocument.createElement() erzeugt OwnElement — keine Kompatibilitat.
Option C: Kein CustomElement-Support
Alle Frameworks die Custom Elements nutzen (Lit, Stencil, etc.) wurden absturzen beim ersten
customElements.define().Entscheidung: Option A
customElements.define()+observedAttributes. Option A liefert das.<my-el>als generische Elemente erzeugt.isConnected === falseundconnectedCallback()feuert nie. Option A lost dies.Akzeptanzkriterien
customElements.define("my-el", MyElement)registriertcustomElements.get("my-el")gibt Constructor zuruckcustomElements.get("unknown")gibtundefinedzuruckcustomElements.whenDefined("my-el")resolved PromisecustomElements.define()mit Name ohne Bindestrich wirft SyntaxErrordefine()wirft NotSupportedErrorconnectedCallback()feuert bei appendChilddisconnectedCallback()feuert bei removeChildattributeChangedCallback(name, old, new)feuert bei setAttributeattributeChangedCallbackfeuert NICHT fur nicht-observed AttributesobservedAttributesstatische Getter wird korrekt abgefragt<my-el>im HTMLisConnectedProperty auf Custom Element korrektBetroffene Dateien
src/custom-elements/registry.tssrc/dom/node.tssrc/html/HTMLParser.tssrc/runtime-isolation.tstests/unit/dom-custom-elements.test.tsDependencies
adoptedCallbackerfordert adoptNode)Technische Risiken
doc.createElement(tagName). Fur Custom Elements mussdoc.createElement()die Registry checken. Losung:createElementin OwnDocument pruftcustomElements.get(tagName).isConnected-Tracking: Ein Element kann ohne parentNode connected sein (DocumentFragment). Losung:isConnectedCheck bis zum root-Document traversieren (O(h) mit h=DOM-Tiefe).adoptedCallback: BeiimportNode()oderadoptNode()mussadoptedCallback()feuern. Losung: Hook inadoptNode().Performance-Impact
Map<string, {ctor, observed}>— observedAttributes einmal bei define() cachenTestplan
Unit-Tests (20+)
Integration-Tests (3+)
@customElement('my-el')✅ Resolved in commit
440573b#106: MutationObserver vollstandig implementiert — MutationRecord, MutationObserver, MutationRegistry mit Mikrotask-Queueing, Node-Hooks fur childList/attributes/characterData
#109: Custom Elements Lifecycle — connectedCallback/disconnectedCallback/attributeChangedCallback, Parser-Integration via _customElementsRegistry, attachShadow in OwnDOM
#105/#107/#108/#110: Bereits implementiert (99 Tests grun)
Tests: 247 pass, 0 fail