We've hit this a few times over the years with perspective.
Affected versions
What happens
Unguarded customElements.define throws when a second bundle inlines the engine. The engine registers its three elements at module import. If two independently-built bundles on the same page each inline regular-layout (a common bundler outcome — e.g. Perspective's viewer bundles its own copy), whichever bundle loads second throws NotSupportedError from customElements.define at import time, and that entire bundle dies — not just the layout registration, everything downstream of the import.
Root cause
src/extensions.ts lines 17–19 run unconditionally at import:
customElements.define("regular-layout", RegularLayout);
customElements.define("regular-layout-frame", RegularLayoutFrame);
customElements.define("regular-layout-tab", RegularLayoutTab);
The CustomElementRegistry is a page-global; a second define for an already-registered name throws NotSupportedError, and because these calls are top-level module side effects, the throw aborts evaluation of the whole importing bundle.
Reproduction
Build two separate bundles that each import "regular-layout" (or import anything that inlines it) and load both on one page with <script> tags. The second script throws NotSupportedError: the name "regular-layout" has already been used with this registry and none of its remaining top-level code runs.
Downstream impact
Perspective 5.x's @perspective-dev/viewer pins and inlines regular-layout "=0.6.1" in its CDN bundle (its dist/cdn/perspective-viewer.js contains all three customElements.define("regular-layout*") calls). Any page combining that bundle with our own regular-layout-based bundle dies.
Suggested fix
Guard each registration:
if (!customElements.get("regular-layout")) {
customElements.define("regular-layout", RegularLayout);
}
(and likewise for the other two), or move registration into an exported defineElements() so bundle authors decide when/whether to register. The guard is the smaller change and matches what most component libraries do for exactly this dual-bundle case. However, as we've discussed in various channels over the years, it raises the question/possibility of having incompatible versions racing to register first.
We've hit this a few times over the years with perspective.
Affected versions
regular-layout0.6.1What happens
Unguarded
customElements.definethrows when a second bundle inlines the engine. The engine registers its three elements at module import. If two independently-built bundles on the same page each inlineregular-layout(a common bundler outcome — e.g. Perspective's viewer bundles its own copy), whichever bundle loads second throwsNotSupportedErrorfromcustomElements.defineat import time, and that entire bundle dies — not just the layout registration, everything downstream of the import.Root cause
src/extensions.tslines 17–19 run unconditionally at import:The
CustomElementRegistryis a page-global; a seconddefinefor an already-registered name throwsNotSupportedError, and because these calls are top-level module side effects, the throw aborts evaluation of the whole importing bundle.Reproduction
Build two separate bundles that each
import "regular-layout"(or import anything that inlines it) and load both on one page with<script>tags. The second script throwsNotSupportedError: the name "regular-layout" has already been used with this registryand none of its remaining top-level code runs.Downstream impact
Perspective 5.x's
@perspective-dev/viewerpins and inlinesregular-layout "=0.6.1"in its CDN bundle (itsdist/cdn/perspective-viewer.jscontains all threecustomElements.define("regular-layout*")calls). Any page combining that bundle with our ownregular-layout-based bundle dies.Suggested fix
Guard each registration:
(and likewise for the other two), or move registration into an exported
defineElements()so bundle authors decide when/whether to register. The guard is the smaller change and matches what most component libraries do for exactly this dual-bundle case. However, as we've discussed in various channels over the years, it raises the question/possibility of having incompatible versions racing to register first.