[BUGFIX] DocumentFragment support — {{#in-element}} with DocumentFragment targets#21253
Open
[BUGFIX] DocumentFragment support — {{#in-element}} with DocumentFragment targets#21253
{{#in-element}} with DocumentFragment targets#21253Conversation
Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/b223b6e1-6551-4db1-bb11-99dac1313bec Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
NullVoxPopuli
March 26, 2026 16:34
View session
Contributor
📊 Package size report 0.03%↑
🤖 This report was automatically generated by pkg-size-action |
17 tasks
packages/@glimmer-workspace/integration-tests/lib/suites/in-element-document-fragment.ts
Outdated
Show resolved
Hide resolved
Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/275deab3-7e86-4ba6-b5a1-928e8a952707 Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
Contributor
|
I'm impressed that adding document-fragment support is such a small change it doesn't bust past our noise filter on the size comment (the map files do tho haha) |
lifeart
reviewed
Mar 27, 2026
packages/@glimmer-workspace/integration-tests/lib/suites/in-element-document-fragment.ts
Show resolved
Hide resolved
… appended to DOM Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/aec4e27c-bdb9-4439-8efe-a010eef96826 Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
packages/@glimmer-workspace/integration-tests/lib/suites/in-element-document-fragment.ts
Outdated
Show resolved
Hide resolved
…sertions Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/509a66ed-dd19-4b09-aadc-523e8e19e5f6 Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
…ix verifySteps failures Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/8126c5ce-0399-4465-98ee-8b9eaf691b8c Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…ng to DOM Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/509016a2-4d3c-4fa7-9143-d386e636ec22 Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
- bounds.ts clear(): use first.parentNode (live parent) instead of stored parentElement(), so removal targets the real container after fragment append - element-builder.ts resume(): capture live parent from firstNode().parentNode before resetting, so new content renders into the container not the fragment - element-builder.ts RemoteBlock destructor: check firstNode().parentNode !== null (node still attached) instead of === parentElement() (node in original parent), so in-element/DocumentFragment targets get cleaned up correctly on destroy - Update test to attach fragment first, then rerender and verify updates work Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/6f1bf405-84ab-4bd5-b42d-f061fadcf4df Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Agent-Logs-Url: https://github.com/emberjs/ember.js/sessions/54039a52-25ed-4859-8971-19493ebbd060 Co-authored-by: NullVoxPopuli <199018+NullVoxPopuli@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
Contributor
|
I made a GH workflow for more easily testing these out: (including PR deploy) |
Contributor
import Component from '@glimmer/component';
import { on } from '@ember/modifier';
import { trackedObject } from '@ember/reactive/collections';
const state = trackedObject({
count: 0,
inc: () => staet.count++,
});
const fragment = document.createDocumentFragment();
setTimeout(() => {
console.log(fragment)
}, 100);
<template>
check the console
<hr>
as a separate PR we need to make fragments renderable
today, folks would need a modifier to append the fragment to the DOM,
which could cause Glimmer to get confused by someone else managing DOM:
{{fragment}}
{{#in-element fragment}}
text in a fragment
{{log "in-element body"}}
{{state.count}}
<button onclick={{state.inc}}>inc</button>
{{/in-element}}
</template> |
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.
Adds full
DocumentFragmentsupport to{{#in-element}}, including correct behaviour after the fragment's children have been moved into a real DOM container viaappendChild().Runtime Fixes (
@glimmer/runtime)bounds.ts—clear(): UsefirstNode().parentNode(the live current parent) instead of the storedparentElement(). After aDocumentFragmentis appended to the DOM, the rendered nodes' actual parent is the container, not the now-empty fragment.element-builder.ts—NewTreeBuilder.resume(): Capture the live parent fromfirstNode().parentNodebefore resetting the block, so subsequent renders are inserted into the real container rather than the detached fragment.element-builder.ts—RemoteBlockdestructor: Changed the guard fromparentElement() === firstNode().parentNode(alwaysfalseafter fragment attachment, silently skipping cleanup) tofirstNode().parentNode !== null(node is still attached to some parent), so content is correctly cleaned up on destroy in both the normal and DocumentFragment cases.Test
Added a test (
InElementDocumentFragmentSuite) that:DocumentFragmentvia{{#in-element}}.container.appendChild(fragment).rerenderand verifies that text-node updates and new conditional elements both appear correctly in the container — usingassert.stepcalled from within the template andassert.verifyStepsto document each reactive update.💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.