Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add in element to debug render tree #1560

Merged

Conversation

patricklx
Copy link
Contributor

@patricklx patricklx commented Feb 5, 2024

My learnings from hacking on this in inspector
emberjs/ember-inspector#2549

Adding modifiers is also easy, will add it in another pr

@patricklx patricklx force-pushed the add-in-element-debug-render-tree branch 5 times, most recently from 15c6cee to 3f5b0d6 Compare February 5, 2024 12:42
Copy link
Contributor

@NullVoxPopuli NullVoxPopuli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

Let's give @chancancode or @wycats a chance to review tho (couple days?)

Comment on lines 224 to 234
this.env.debugRenderTree.create(state, {
type: 'remote-element',
name: 'in-element',
args: {
positional: [],
named: {
destination: ref,
},
} as any,
instance: {
args: {
destination: ref,
},
constructor: {
name: 'InElement',
},
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.env.debugRenderTree.create(state, {
type: 'remote-element',
name: 'in-element',
args: {
positional: [],
named: {
destination: ref,
},
} as any,
instance: {
args: {
destination: ref,
},
constructor: {
name: 'InElement',
},
},
});
this.env.debugRenderTree.create(state, {
type: 'keyword',
name: 'in-element',
args: createCapturedArgs(
// not sure why the order is backwards, but it's named then positional
{ insertBefore: createConstRef(insertBefore, false) },
[createConstRef(element, false)],
),
instance: null,
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*see the other comment regarding state

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wasn't able to use createCapturedArgs, because importing ./arguments would cause recursive imports

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, let's see how we can resolve that, what was the cycle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure

I think

  • arguments
  • stack
  • low-level
  • opcodes
  • element-builder

But i also saw this:

  • arguments
  • compiled/opcodes/-debug-strip
  • ../vm/arguments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error happens in glimmer/runtime/lib/compiled/opcodes/vm.ts:38:1
APPEND_OPCODES is not defined

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look when I get a chance 👌🏼

firstNode: () => element,
lastNode: () => element,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.popBlock() returns the bounds so you would just call it first, store it in a local variable, and then pass that to didRender, rather than having to make your own

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for "state", it just have to be a stable object that uniquely identify this node, and so it actually works to just use the "block" object – the one you get back from calling pushLiveBlock and popBlock (regarding my comment above, Block implements Bounds), which would be the same object, because that is already stored in a stack, which is why I said it would be unnecessary for you to maintain yet another parallel stack just to track the same.

However, it looks like something is currently wrong with the types so you would have to fix it before you can do that.

First of all, you should have access to the block returned by pushLiveBlock (so you can pass it to debugRenderTree.create from within pushRemoteElement). However, that is happening from with __pushRemoteElement, which currently has a return type of Nullable<RemoteLiveBlock>. I think that is wrong – specifically, the Nullable<...> is not accurate, as far as I can tell, there is no code path that would return null, and if there is, it would be a bug to unconditionally call popBlock here in popRemoteElement.

So you'll have to fix that return type, and then do the same in the rehydration builder, then, you should have everything you need to implement the feature without having to add your own parallel stack.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And – while you are in this file, we really shouldn't be inferring the return types of these methods in this file (ie. a bunch of methods does not have : ... here). It seems like most of them are just : void and we should have typed that explicitly.

Ideally we should fix that in a separate PR, either just in this file, or across the whole codebase and enforce it with a lint, that would be great. It will probably give @NullVoxPopuli some rebase nightmares though, so you may want to coordinate with them on Discord about how to approach it; I think it is ultimately a rather mechanical fix that should be possible to do, but @NullVoxPopuli can figure that out with you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block seems to have the bounds set to the children of the remote element. so I reverted to pass custom bounds

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the correct usage of bounds though. It is what each node has rendered. A component’s bounds is its content. And you need that if you want to draw the bounding box if the inspector

Copy link
Contributor Author

@patricklx patricklx Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, it will not work with insertAfter, otherwise this would work.
Would it be okay to still have custom bounds where parentElement is the parent of the in-element, like how it is now? I would like to have that link for the inspector.
first&last would use the block bounds.
From the code in glimmer i think parent element is checked to verify if a node was removed or moved to another block.
In the inspector it was only used to check if a node is still in the dom. It uses node.isConnected now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@patricklx I don't really understand this, but no, something sounds off. The bounds represents a range in the DOM, denoted by (element, firstChild, lastChild) where first/last child belongs to the element. You should expect to be able to find a sub-slice in element.childNodes that matches (firstChild, lastChild). The inspector should be using this to highlight (bounding rect overlay). So something seems fishy about what you wanted, can you link to the code?

Copy link
Contributor Author

@patricklx patricklx Mar 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, first and last child is the same .
And inspector only uses those:
https://github.com/emberjs/ember-inspector/blob/56575c08bcd3228d830ace596ebb778af2dd4824/ember_debug/libs/render-tree.js#L326

For another use case i would like to have parentElement of in-element to point to the previous parent. Or another way to get it.
Basically with modifiers i am putting them under an html element in inspector. Also all components that are under that element are also put under it. But i cannot know if the in-element was also under that element because it's disconnected

Copy link
Contributor

@chancancode chancancode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see all of the above

@patricklx patricklx force-pushed the add-in-element-debug-render-tree branch from 0e4340f to 2b22060 Compare February 7, 2024 08:56
@patricklx patricklx force-pushed the add-in-element-debug-render-tree branch from b9b8015 to 94d42ee Compare February 12, 2024 09:46
patricklx and others added 2 commits March 8, 2024 14:12
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
@chancancode chancancode force-pushed the add-in-element-debug-render-tree branch 3 times, most recently from 15f2452 to 6502c08 Compare March 8, 2024 22:19
@chancancode chancancode force-pushed the add-in-element-debug-render-tree branch from 6502c08 to b472b00 Compare March 8, 2024 22:20
@NullVoxPopuli NullVoxPopuli merged commit ed002cc into glimmerjs:main Mar 8, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants