diff --git a/.changeset/warm-planets-cry.md b/.changeset/warm-planets-cry.md new file mode 100644 index 0000000000..ee7e92d95f --- /dev/null +++ b/.changeset/warm-planets-cry.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +feat: make `` unnecessary in runes mode diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 4e5a03089c..d797703e92 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -1551,7 +1551,10 @@ const common_visitors = { node.name.includes('.') ? node.name.slice(0, node.name.indexOf('.')) : node.name ); - node.metadata.dynamic = binding !== null && binding.kind !== 'normal'; + node.metadata.dynamic = + context.state.analysis.runes && // Svelte 4 required you to use svelte:component to switch components + binding !== null && + (binding.kind !== 'normal' || node.name.includes('.')); }, RenderTag(node, context) { context.next({ ...context.state, render_tag: node }); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index dcfa23a99d..fb995b4e90 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -933,7 +933,16 @@ function serialize_inline_component(node, component_name, context, anchor = cont /** @param {Expression} node_id */ let fn = (node_id) => { - return b.call(component_name, node_id, props_expression); + return b.call( + // TODO We can remove this ternary once we remove legacy mode, since in runes mode dynamic components + // will be handled separately through the `$.component` function, and then the component name will + // always be referenced through just the identifier here. + node.type === 'SvelteComponent' + ? component_name + : /** @type {Expression} */ (context.visit(b.member_id(component_name))), + node_id, + props_expression + ); }; if (bind_this !== null) { diff --git a/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component1.svelte b/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component1.svelte new file mode 100644 index 0000000000..32751f7c94 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component1.svelte @@ -0,0 +1 @@ +Component1 diff --git a/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component2.svelte b/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component2.svelte new file mode 100644 index 0000000000..aab0454088 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/dynamic-component/Component2.svelte @@ -0,0 +1 @@ +Component2 diff --git a/packages/svelte/tests/runtime-runes/samples/dynamic-component/_config.js b/packages/svelte/tests/runtime-runes/samples/dynamic-component/_config.js new file mode 100644 index 0000000000..f6471f510b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/dynamic-component/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: ' Component1 Component1', + async test({ assert, target }) { + const btn = target.querySelector('button'); + + btn?.click(); + flushSync(); + + assert.htmlEqual(target.innerHTML, ' Component2 Component2'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/dynamic-component/main.svelte b/packages/svelte/tests/runtime-runes/samples/dynamic-component/main.svelte new file mode 100644 index 0000000000..2b2d7c4b72 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/dynamic-component/main.svelte @@ -0,0 +1,16 @@ + + + + + + diff --git a/packages/svelte/tests/validator/samples/component-dynamic/_config.js b/packages/svelte/tests/validator/samples/component-dynamic/_config.js deleted file mode 100644 index 64fdc120d6..0000000000 --- a/packages/svelte/tests/validator/samples/component-dynamic/_config.js +++ /dev/null @@ -1,3 +0,0 @@ -import { test } from '../../test'; - -export default test({ skip: true }); diff --git a/packages/svelte/tests/validator/samples/component-dynamic/input.svelte b/packages/svelte/tests/validator/samples/component-dynamic/input.svelte deleted file mode 100644 index 7f52353e36..0000000000 --- a/packages/svelte/tests/validator/samples/component-dynamic/input.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - -
- - -
- - -
-
diff --git a/packages/svelte/tests/validator/samples/component-dynamic/warnings.json b/packages/svelte/tests/validator/samples/component-dynamic/warnings.json deleted file mode 100644 index 49fb9e4334..0000000000 --- a/packages/svelte/tests/validator/samples/component-dynamic/warnings.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "code": "reactive_component", - "message": " will not be reactive if Let changes. Use if you want this reactivity.", - "end": { - "column": 7, - "line": 15 - }, - "start": { - "column": 0, - "line": 15 - } - }, - { - "message": " will not be reactive if ExportLet changes. Use if you want this reactivity.", - "code": "reactive_component", - "end": { - "column": 13, - "line": 16 - }, - "start": { - "column": 0, - "line": 16 - } - }, - { - "message": " will not be reactive if Reactive changes. Use if you want this reactivity.", - "code": "reactive_component", - "end": { - "column": 12, - "line": 17 - }, - "start": { - "column": 0, - "line": 17 - } - } -] diff --git a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md index 029b2ba688..95469ccbaf 100644 --- a/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md +++ b/sites/svelte-5-preview/src/routes/docs/content/03-appendix/02-breaking-changes.md @@ -198,6 +198,30 @@ In Svelte 4, doing the following triggered reactivity: This is because the Svelte compiler treated the assignment to `foo.value` as an instruction to update anything that referenced `foo`. In Svelte 5, reactivity is determined at runtime rather than compile time, so you should define `value` as a reactive `$state` field on the `Foo` class. Wrapping `new Foo()` with `$state(...)` will have no effect — only vanilla objects and arrays are made deeply reactive. +### `` is no longer necessary + +In Svelte 4, components are _static_ — if you render ``, and the value of `Thing` changes, [nothing happens](https://svelte.dev/repl/7f1fa24f0ab44c1089dcbb03568f8dfa?version=4.2.18). To make it dynamic you must use ``. + +This is [no longer true in Svelte 5](/#H4sIAAAAAAAAE4WQwU7DMAyGX8VESANpXe8lq9Q8AzfGobQujZQmWeJOQlXenaQB1sM0bnG-379_e2GDVOhZ9bYw3U7IKtZYy_aMvmwq_AUVYay9mV2XfrjvnLRUn_SJ5GSNI2hgcGaC3aFsDrlh97LB4g-LLY4ChQSvo9SfcIRHTy3h03NEvLzO0Nyjwo7gQ-q-urRqxuOy9oQ1AjeWpNHwQ5pQN7zMf7e4CLXY8Dhpdc-THooCaESP0DoEPM8ydqEmKIqkzUnL9MxrVJ2JG-qkoFH631xREg82mV4OEntWkZsx7K_3vXtdm_LbuwbiHwNx2-A9fANfmchv7QEAAA==): + +```svelte + + + + + + + +``` + ## Other breaking changes ### Stricter `@const` assignment validation