[BUGFIX] Shadow DOM support — {{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM#21217
[BUGFIX] Shadow DOM support — {{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM#21217
{{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM#21217Conversation
Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
{{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM
📊 Package size report 0.1%↑
🤖 This report was automatically generated by pkg-size-action |
|
@copilot tests linting doesn't pass, and tests won't run unless linting passes |
Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
{{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM{{#in-element}} with ShadowRoot/DocumentFragment and enable declarative shadow DOM
There was a problem hiding this comment.
@copilot extract these shadowroot tests to a sibling test file, in-element-shadow-root.ts
we have more shadowdom tests to add including:
- class-based component with tracked properties where the whole dom isn't replaced each update
- sibling components in one shadowdom
- sibling shadowdoms, multiple components
- multiple-in-element calls to the same shadow-dom
- multilpe-in-element calls to the same shadow-dom with the insertBefore=null arg
There was a problem hiding this comment.
Done in 69f7254. Extracted the ShadowRoot/DocumentFragment tests from in-element.ts into a new in-element-shadow-root.ts (InElementShadowRootSuite) and added the following new tests:
- Class-based component with
@trackedproperty renders into shadow root without full DOM replacement on update - Sibling components rendered into the same shadow root (via
insertBefore=null) - Sibling shadow roots, each receiving their own component
- Multiple
{{#in-element}}calls to the same shadow root - Multiple
{{#in-element}}calls to the same shadow root withinsertBefore=null
The suite is exported from suites.ts and registered in jit-suites-test.ts.
…add new tests Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
| import { test } from '../test-decorator'; | ||
| import { tracked } from '../test-helpers/tracked'; | ||
|
|
||
| function hasShadowDom() { |
There was a problem hiding this comment.
@copilot do any of our test environments not support shadow dom? we test in the browser, so I would think we can clean up tests by getting rid of this check
There was a problem hiding this comment.
Removed in 9870259 — since InElementShadowRootSuite is only registered via jitSuite (browser-only), Shadow DOM is always available and the hasShadowDom() guards are unnecessary.
There was a problem hiding this comment.
@copilot we should also have an in-element-document-fragment.ts test that tests rendering in to document fragments (non-elements, may or may not be in the DOM)
There was a problem hiding this comment.
Done in 9870259 — added in-element-document-fragment.ts (InElementDocumentFragmentSuite) with tests for: detached DocumentFragment, template.content fragment, a fragment later attached to the DOM, and multiple {{#in-element}} calls to the same fragment (both with and without insertBefore=null).
|
|
||
| constructor(owner: Owner, args: Dict) { | ||
| super(owner, args); | ||
| this.count = (args['initial'] as number) ?? 0; |
There was a problem hiding this comment.
@copilot don't set data like this -- either derive it and delete the constructor, or set the initial value in the property initialization line (and still delete the constructor)
There was a problem hiding this comment.
Fixed in 9870259 — removed the constructor and the unused @tracked count property. Since the template renders {{@count}} (the arg), the class just extends GlimmerishComponent with no extra state.
…d document fragment suite Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Glimmer's element builder and debug type system blocked two common Shadow DOM patterns: using
{{#in-element}}with aShadowRootorDocumentFragment, and the declarative<template shadowrootmode="open">syntax (which Glimmer creates via DOM APIs, bypassing the browser's native declarative processing).{{#in-element}}with ShadowRoot / DocumentFragmentVM_PUSH_REMOTE_ELEMENT_OPchecked the target element withCheckElement, which requiresnodeType: 1. BothShadowRootandDocumentFragmenthavenodeType: 11, causing an assertion failure in debug builds.packages/@glimmer/runtime/lib/compiled/opcodes/dom.tsCheckElementtoCheckOr(CheckElement, CheckDocumentFragment), allowing both element types as{{#in-element}}targetsDeclarative Shadow DOM (
<template shadowrootmode="...">)When Glimmer renders
<template shadowrootmode="open">via DOM APIs, the browser never triggers its native declarative shadow DOM behavior, so no shadow root is created and children render into the template element's light DOM.packages/@glimmer/runtime/lib/vm/element-builder.tsflushElement(): detects<template shadowrootmode="open|closed">, callsattachShadow()on the parent element, pushes the shadow root as the active cursor, and pushes a remote block (not tracked in parent bounds) so shadow content doesn't pollute parent bound trackingcloseElement(): detects shadow root/document fragment cursors (vianodeType: 11) and pops the remote block instead of callingwillCloseElement()attachShadowis unavailableTests
InElementShadowRootSuite(in-element-shadow-root.ts) — dedicated suite for{{#in-element}}withShadowRoot:ShadowRoot@trackedarg renders into shadow root without full DOM replacement on update{{#in-element}}calls to the same shadow root{{#in-element insertBefore=null}}calls to the same shadow rootInElementDocumentFragmentSuite(in-element-document-fragment.ts) — dedicated suite for{{#in-element}}withDocumentFragment:DocumentFragmenttemplate.contentfragment{{#in-element}}calls to the sameDocumentFragment{{#in-element insertBefore=null}}calls to the sameDocumentFragmentShadowDOMSuite(shadow-dom.ts) — covers declarative shadow DOM rendering:<template shadowrootmode="open">attaches a shadow root and renders children into itOriginal prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.