Skip to content

Commit 838f881

Browse files
7nik7nik
andauthored
fix: avoid shadowing a variable in dynamic components (#16185)
* fix: avoid shadowing a variable in dynamic components * split component name and intermediate name --------- Co-authored-by: 7nik <kifiranet@gmail.com>
1 parent 061ab31 commit 838f881

File tree

6 files changed

+43
-13
lines changed

6 files changed

+43
-13
lines changed

.changeset/short-mails-know.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: avoid shadowing a variable in dynamic components

packages/svelte/src/compiler/phases/3-transform/client/visitors/Component.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ import { build_component } from './shared/component.js';
88
* @param {ComponentContext} context
99
*/
1010
export function Component(node, context) {
11-
const component = build_component(
12-
node,
13-
// if it's not dynamic we will just use the node name, if it is dynamic we will use the node name
14-
// only if it's a valid identifier, otherwise we will use a default name
15-
!node.metadata.dynamic || regex_is_valid_identifier.test(node.name) ? node.name : '$$component',
16-
context
17-
);
11+
const component = build_component(node, node.name, context);
1812
context.state.init.push(component);
1913
}

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ export function build_component(node, component_name, context) {
5252
/** @type {ExpressionStatement[]} */
5353
const binding_initializers = [];
5454

55+
const is_component_dynamic =
56+
node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic);
57+
58+
// The variable name used for the component inside $.component()
59+
const intermediate_name =
60+
node.type === 'Component' && node.metadata.dynamic
61+
? context.state.scope.generate(node.name)
62+
: '$$component';
63+
5564
/**
5665
* If this component has a slot property, it is a named slot within another component. In this case
5766
* the slot scope applies to the component itself, too, and not just its children.
@@ -199,7 +208,7 @@ export function build_component(node, component_name, context) {
199208
b.call(
200209
'$$ownership_validator.binding',
201210
b.literal(binding.node.name),
202-
b.id(component_name),
211+
b.id(is_component_dynamic ? intermediate_name : component_name),
203212
b.thunk(expression)
204213
)
205214
)
@@ -414,8 +423,8 @@ export function build_component(node, component_name, context) {
414423
// TODO We can remove this ternary once we remove legacy mode, since in runes mode dynamic components
415424
// will be handled separately through the `$.component` function, and then the component name will
416425
// always be referenced through just the identifier here.
417-
node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)
418-
? component_name
426+
is_component_dynamic
427+
? intermediate_name
419428
: /** @type {Expression} */ (context.visit(b.member_id(component_name))),
420429
node_id,
421430
props_expression
@@ -432,7 +441,7 @@ export function build_component(node, component_name, context) {
432441

433442
const statements = [...snippet_declarations];
434443

435-
if (node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)) {
444+
if (is_component_dynamic) {
436445
const prev = fn;
437446

438447
fn = (node_id) => {
@@ -441,11 +450,11 @@ export function build_component(node, component_name, context) {
441450
node_id,
442451
b.thunk(
443452
/** @type {Expression} */ (
444-
context.visit(node.type === 'Component' ? b.member_id(node.name) : node.expression)
453+
context.visit(node.type === 'Component' ? b.member_id(component_name) : node.expression)
445454
)
446455
),
447456
b.arrow(
448-
[b.id('$$anchor'), b.id(component_name)],
457+
[b.id('$$anchor'), b.id(intermediate_name)],
449458
b.block([...binding_initializers, b.stmt(prev(b.id('$$anchor')))])
450459
)
451460
);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
const { children } = $props()
3+
</script>
4+
5+
{@render children()}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
import { flushSync } from 'svelte';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
assert.htmlEqual(target.innerHTML, 'test');
7+
}
8+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import A from './A.svelte';
3+
4+
const B = $derived(A);
5+
</script>
6+
7+
<B>
8+
<B>test</B>
9+
</B>

0 commit comments

Comments
 (0)