3.2 KiB
06 — Load order
The rule
Export order in src/index.ts is load-bearing. A component that listens
for a bubbling announcement from another tag must be exported — and therefore
customElements.define()d — before that other tag.
Why
customElements.define(name, Class) upgrades every matching element already
in the document immediately and synchronously, running
connectedCallback right then for elements that are already connected.
On a real static-HTML page the markup is fully parsed before the deferred
module script runs, so at define() time the elements already exist. The
first define() for a given tag wins the race:
- If a child tag is defined before its listening parent tag, every
instance of that child in the page upgrades and fires its one-shot
connect-time announcement (
leaflet-register,icon-changed,leaflet-line-sync,leaflet-crs-changed) into a parent element that has no listener attached yet — because the parent class isn't defined, so itsconnectedCallbackhasn't run. - That announcement is gone for good:
connectedCallbackdoes not fire again for an element that stays connected.
So parents must be defined first.
The ordering in src/index.ts
Root to leaf (this is the comment at the top of the file, kept in sync):
LeafletMap ← nothing can register before the root exists
LeafletControlLayers, LeafletLayerGroup,
LeafletFeatureGroup ← listen for leaflet-register from arbitrary layers
every concrete layer type (Marker, Circle,
Polygon, TileLayer, …)
LeafletLine ← child of Polygon/Polyline
LeafletPopup, LeafletTooltip ← child of any layer
LeafletIcon, LeafletDivIcon ← child of Marker
Standalone controls (LeafletControlZoom, LeafletControlAttribution,
LeafletControlScale) have no such relationship and can go anywhere.
The core re-exports (register.ts, props.ts, with-props.ts,
shared-props.ts, event-types.ts) come first and carry no
customElements.define, so their order is free.
The HTMLElementTagNameMap augmentation
At the bottom of src/index.ts. Because export { X } from '…' re-exports
X without binding it locally, the tag map needs its own import type of
every component class alongside the re-export. Those imports are type-only,
erased at build, back no define() — their order doesn't matter.
The test that guards this
test/load-order.test.ts is structurally unlike every other test file on
purpose: it never statically imports a component module, so nothing is
customElements.defined until it dynamically import()s src/index.ts
partway through — after building a DOM tree out of plain, undefined
elements. That's the only test reproducing a real page's actual order (markup
first, module script second).
Every other test file imports components up front, so components are already
defined before any element is created — they structurally cannot catch an
ordering regression. If you add a component with a "parent listens for a
child's announcement" relationship, extend load-order.test.ts.