-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat: add parent hierarchy to __svelte_meta
objects at dev time
#16255
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
base: main
Are you sure you want to change the base?
Conversation
This adds a `parent` property to the `__svelte_meta` properties that are added to elements at dev time. This property represents the closest non-element parent the element is related to. For example for `{#if ...}<div>foo</div>{/if}` the `parent` of the div would be the line/column of the if block. The parent is recursive and goes upwards (through component boundaries) until the root component is reached, which has no parent. part of #11389
🦋 Changeset detectedLatest commit: 3e3d20c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
how does that work? components are compiled in isolation so the dev runtime would have to calculate these for blocks outside of that component. If the runtime can calculate it, the devtool can do that 🤔 everything would have to be updated on hot updates too, think adding or removing block. could this information be obtained from/attached to comment nodes we already have instead? |
How would componentTag look for renamed things like if every element had all parents attached i hope data is deduplicated/just linked, otherwise that could be a lot extra on long lists that are deeply nested. |
Everything is compiled in isolation. The compiler wraps block/component creations with the info where they are within the file, and the runtime creates sort of a stack from it. You can only go upwards not downward - is HMR smart enough to keep children around when a component higher up the tree is reloaded? If not then this doesn't leak or get outdated. If it does we should be able to add logic to our HMR to handle it. What would attaching it to comments give us? Right now component tags are what the compiler will use under the hood I think. We should be able to adjust that to show the original name |
attaching it to comment nodes was just an idea of how it could be possible to put the information of locations where they actually are instead of adding it to all nodes they wrap. |
What exactly is your concern with the deeply nested example? |
time spent & memory consumed. right now svelte_meta is linear, one information about the source code location per node. with this, it becomes exponential and adding blocks at the root level or adding many deeply nested components can quickly escalate things. Why is the full info on each node? |
This is a shared stack, it's not recreated for every node. So the overhead is basically zero. The reference to the parent (think about it as a reference, not as a value) is there because it's very convenient for anyone not wanting to build their own tree, you can just get a node and traverse upwards from there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small simplification
I think maybe we should rename |
packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
Outdated
Show resolved
Hide resolved
packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
Outdated
Show resolved
Hide resolved
packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js
Outdated
Show resolved
Hide resolved
Co-authored-by: Rich Harris <rich.harris@vercel.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks great — I think it would make sense to add an entry for RenderTag
, but otherwise LGTM
{
type: 'snippet',
line: ...,
column: ...,
file: ...,
renderedAt: {
type: 'component' / 'each' / wherever the render tag is,
line: ...,
column: ...,
file: ...,
parent: <not sure if this would work out, but could be nice to get that tree aswell>
}
} |
Why doesn't it make sense? For me 'parent' means 'the |
It's not a block though, it renders a block. It also gets fuzzy because when |
Syntactically a render tag isn't a 'block', but in terms of the effect tree it absolutely is |
And what about b) ? |
I still don't think it makes sense. You should be able to keep tracing {#snippet hello()}
<span>hello</span>
{/snippet}
{#if a}
{#if b}
{#if c}
{#if x}
{@render hello()}
{/if}
{#if foo}
{@render hello()}
{/if}
{/if}
{/if}
{/if} The 'parent' is the thing that is rendering the child. Here, that is the |
This will not work for snippets which are passed indirectly. Imagine a <script>
import { openModal } from '$lib/modal.svelte';
</script>
<button onclick={() => openModal(content)}>open</button>
{#snippet content()}
<p>will start here but not be able to retrieve the parent of this snippet/component</p>
{/snippet} Essentially there are two trees and both are of interest depending on your use case (sometimes I want to know the actually-rendered tree, sometimes I want to get the virtual tree and jump the snippet/render "portals") hence the |
I guess this is the bit I'm stuck on — what does going up from there mean? It doesn't really make sense to speak of the snippet as belonging to any given instance of the surrounding component (it could be hoisted/exported), but nor does it really make sense to speak of it as belonging to (say) I think perhaps I'm not understanding the concrete use case. What information do you gain from including snippets in the tree? My (possibly incorrect) understanding was that this metadata was meant to allow tooling to map the render tree (i.e. what actually appears in the DOM) to source code |
This adds a
parent
property to the__svelte_meta
properties that are added to elements at dev time. This property represents the closest non-element parent the element is related to. For example for{#if ...}<div>foo</div>{/if}
theparent
of the div would be the line/column of the if block. The parent is recursive and goes upwards (through component boundaries) until the root component is reached, which has no parent.part of #11389 - I believe the hierarchy structure along with the line/column/block type info will make things much easier for tooling wanting to represent hierarchies. This deliberately doesn't include any firing of events yet, that can happen later once we've figured out at which times we want/need it (my guess is we want it to fire it exactly when those parent relationships are established).
cc @jacob-8
Before submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.packages/svelte/src
, add a changeset (npx changeset
).Tests and linting
pnpm test
and lint the project withpnpm lint