Skip to content

Commit 2b22060

Browse files
committed
add in element to debug render tree
My learnings from hacking on this in inspector https://github.com/emberjs/ember-inspector/pull/2549/files Adding modifiers is also easy, will add it in another pr
1 parent dc76897 commit 2b22060

File tree

5 files changed

+88
-14
lines changed

5 files changed

+88
-14
lines changed

packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts

+51-3
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,54 @@ class DebugRenderTreeTest extends RenderTest {
253253
]);
254254
}
255255

256+
@test 'in-element in tree'() {
257+
this.registerComponent('Glimmer', 'HiWorld', 'Hi World');
258+
this.registerComponent(
259+
'Glimmer',
260+
'HelloWorld',
261+
'{{#in-element this.destinationElement}}<HiWorld />{{/in-element}}',
262+
class extends GlimmerishComponent {
263+
get destinationElement() {
264+
return document.getElementById('target');
265+
}
266+
}
267+
);
268+
269+
this.render(`<div id='target'></div><HelloWorld @arg="first"/>`);
270+
271+
this.assertRenderTree([
272+
{
273+
type: 'component',
274+
name: 'HelloWorld',
275+
args: { positional: [], named: { arg: 'first' } },
276+
instance: (instance: GlimmerishComponent) => instance.args['arg'] === 'first',
277+
template: '(unknown template module)',
278+
bounds: this.nodeBounds(this.element.firstChild!.nextSibling),
279+
children: [
280+
{
281+
type: 'keyword',
282+
name: 'in-element',
283+
args: { positional: [this.element.firstChild], named: {} },
284+
instance: (instance: GlimmerishComponent) => instance === null,
285+
template: null,
286+
bounds: this.nodeBounds(this.element.firstChild!.firstChild, this.element),
287+
children: [
288+
{
289+
type: 'component',
290+
name: 'HiWorld',
291+
args: { positional: [], named: {} },
292+
instance: (instance: GlimmerishComponent) => instance,
293+
template: '(unknown template module)',
294+
bounds: this.nodeBounds(this.element.firstChild!.firstChild),
295+
children: [],
296+
},
297+
],
298+
},
299+
],
300+
},
301+
]);
302+
}
303+
256304
@test 'getDebugCustomRenderTree works'() {
257305
let bucket1 = {};
258306
let instance1 = {};
@@ -441,12 +489,12 @@ class DebugRenderTreeTest extends RenderTest {
441489
assert.deepEqual(this.delegate.getCapturedRenderTree(), [], 'there was no output');
442490
}
443491

444-
nodeBounds(_node: SimpleNode | null): CapturedBounds {
492+
nodeBounds(_node: SimpleNode | null, parent?: SimpleNode): CapturedBounds {
445493
let node = expect(_node, 'BUG: Expected node');
446494

447495
return {
448496
parentElement: expect(
449-
node.parentNode,
497+
parent || node.parentNode,
450498
'BUG: detached node'
451499
) as unknown as SimpleNode as SimpleElement,
452500
firstNode: node as unknown as SimpleNode,
@@ -502,7 +550,7 @@ class DebugRenderTreeTest extends RenderTest {
502550
this.assertRenderNode(actualNode, expected, `${actualNode.type}:${actualNode.name}`);
503551
});
504552
} else {
505-
this.assert.deepEqual(actual, [], path);
553+
this.assert.deepEqual(actual, expectedNodes, path);
506554
}
507555
}
508556

packages/@glimmer/interfaces/lib/runtime/debug-render-tree.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { SimpleElement, SimpleNode } from '@simple-dom/interface';
33
import type { Bounds } from '../dom/bounds.js';
44
import type { Arguments, CapturedArguments } from './arguments.js';
55

6-
export type RenderNodeType = 'outlet' | 'engine' | 'route-template' | 'component';
6+
export type RenderNodeType = 'outlet' | 'engine' | 'route-template' | 'component' | 'keyword';
77

88
export interface RenderNode {
99
type: RenderNodeType;

packages/@glimmer/node/lib/serialize-builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class SerializeBuilder extends NewElementBuilder implements ElementBuilder {
129129
element: SimpleElement,
130130
cursorId: string,
131131
insertBefore: Maybe<SimpleNode> = null
132-
): Nullable<RemoteLiveBlock> {
132+
): RemoteLiveBlock {
133133
let { dom } = this;
134134
let script = dom.createElement('script');
135135
script.setAttribute('glmr', cursorId);

packages/@glimmer/runtime/lib/vm/element-builder.ts

+34-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type {
22
AttrNamespace,
33
Bounds,
4+
CapturedArguments,
45
Cursor,
56
CursorStackSymbol,
67
ElementBuilder,
@@ -12,6 +13,7 @@ import type {
1213
Maybe,
1314
ModifierInstance,
1415
Nullable,
16+
Reference,
1517
SimpleComment,
1618
SimpleDocumentFragment,
1719
SimpleElement,
@@ -20,6 +22,7 @@ import type {
2022
UpdatableBlock,
2123
} from '@glimmer/interfaces';
2224
import { destroy, registerDestructor } from '@glimmer/destroyable';
25+
import { createConstRef } from '@glimmer/reference';
2326
import { assert, expect, Stack } from '@glimmer/util';
2427

2528
import type { DynamicAttribute } from './attributes/dynamic';
@@ -100,7 +103,6 @@ export class NewElementBuilder implements ElementBuilder {
100103

101104
constructor(env: Environment, parentNode: SimpleElement, nextSibling: Nullable<SimpleNode>) {
102105
this.pushElement(parentNode, nextSibling);
103-
104106
this.env = env;
105107
this.dom = env.getAppendOperations();
106108
this.updateOperations = env.getDOM();
@@ -214,15 +216,31 @@ export class NewElementBuilder implements ElementBuilder {
214216
element: SimpleElement,
215217
guid: string,
216218
insertBefore: Maybe<SimpleNode>
217-
): Nullable<RemoteLiveBlock> {
218-
return this.__pushRemoteElement(element, guid, insertBefore);
219+
): RemoteLiveBlock {
220+
const block = this.__pushRemoteElement(element, guid, insertBefore);
221+
if (this.env.debugRenderTree) {
222+
const namedArgs: Record<string, Reference> = {};
223+
if (insertBefore) {
224+
namedArgs['insertBefore'] = createConstRef(insertBefore, false);
225+
}
226+
this.env.debugRenderTree.create(block, {
227+
type: 'keyword',
228+
name: 'in-element',
229+
args: {
230+
named: namedArgs,
231+
positional: [createConstRef(element, false)],
232+
} as CapturedArguments,
233+
instance: null,
234+
});
235+
}
236+
return block;
219237
}
220238

221239
__pushRemoteElement(
222240
element: SimpleElement,
223241
_guid: string,
224242
insertBefore: Maybe<SimpleNode>
225-
): Nullable<RemoteLiveBlock> {
243+
): RemoteLiveBlock {
226244
this.pushElement(element, insertBefore);
227245

228246
if (insertBefore === undefined) {
@@ -236,12 +254,20 @@ export class NewElementBuilder implements ElementBuilder {
236254
return this.pushLiveBlock(block, true);
237255
}
238256

239-
popRemoteElement() {
240-
this.popBlock();
257+
popRemoteElement(): void {
258+
const block = this.popBlock();
241259
this.popElement();
260+
const parentElement = this.element;
261+
if (this.env.debugRenderTree) {
262+
this.env.debugRenderTree?.didRender(block, {
263+
parentElement: () => parentElement,
264+
firstNode: () => block.firstNode(),
265+
lastNode: () => block.lastNode(),
266+
});
267+
}
242268
}
243269

244-
protected pushElement(element: SimpleElement, nextSibling: Maybe<SimpleNode> = null) {
270+
protected pushElement(element: SimpleElement, nextSibling: Maybe<SimpleNode> = null): void {
245271
this[CURSOR_STACK].push(new CursorImpl(element, nextSibling));
246272
}
247273

@@ -268,7 +294,7 @@ export class NewElementBuilder implements ElementBuilder {
268294
return element;
269295
}
270296

271-
willCloseElement() {
297+
willCloseElement(): void {
272298
this.block().closeElement();
273299
}
274300

packages/@glimmer/runtime/lib/vm/rehydrate-builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ export class RehydrateBuilder extends NewElementBuilder implements ElementBuilde
455455
element: SimpleElement,
456456
cursorId: string,
457457
insertBefore: Maybe<SimpleNode>
458-
): Nullable<RemoteLiveBlock> {
458+
): RemoteLiveBlock {
459459
const marker = this.getMarker(castToBrowser(element, 'HTML'), cursorId);
460460

461461
assert(

0 commit comments

Comments
 (0)