Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cold-dingos-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: use fine grained for template if the component is not explicitly in legacy mode
23 changes: 23 additions & 0 deletions packages/svelte/src/compiler/phases/2-analyze/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,29 @@ export function analyze_component(root, source, options) {
template,
elements: [],
runes,
// if we are not in runes mode but we have no reserved references ($$props, $$restProps)
// and no `export let` we might be in a wannabe runes component that is using runes in an external
// module...we need to fallback to the runic behavior
maybe_runes:
!runes &&
// if they explicitly disabled runes, use the legacy behavior
options.runes !== false &&
![...module.scope.references.keys()].some((name) =>
['$$props', '$$restProps'].includes(name)
) &&
!instance.ast.body.some(
(node) =>
node.type === 'LabeledStatement' ||
(node.type === 'ExportNamedDeclaration' &&
((node.declaration &&
node.declaration.type === 'VariableDeclaration' &&
node.declaration.kind === 'let') ||
node.specifiers.some(
(specifier) =>
specifier.local.type === 'Identifier' &&
instance.scope.get(specifier.local.name)?.declaration_kind === 'let'
)))
),
tracing: false,
classes: new Map(),
immutable: runes || options.immutable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,10 @@ export function validate_mutation(node, context, expression) {
export function build_expression(context, expression, metadata, state = context.state) {
const value = /** @type {Expression} */ (context.visit(expression, state));

if (context.state.analysis.runes) {
// Components not explicitly in legacy mode might be expected to be in runes mode (especially since we didn't
// adjust this behavior until recently, which broke people's existing components), so we also bail in this case.
// Kind of an in-between-mode.
if (context.state.analysis.runes || context.state.analysis.maybe_runes) {
return value;
}

Expand Down
1 change: 1 addition & 0 deletions packages/svelte/src/compiler/phases/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface ComponentAnalysis extends Analysis {
/** Used for CSS pruning and scoping */
elements: Array<AST.RegularElement | AST.SvelteElement>;
runes: boolean;
maybe_runes: boolean;
tracing: boolean;
exports: Array<{ name: string; alias: string | null }>;
/** Whether the component uses `$$props` */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client'],
async test({ assert, target }) {
const p = target.querySelector('p');
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.equal(p?.innerHTML, '0');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<svelte:options runes={false} />
<script>
import { get, set } from "./test.svelte.js";
</script>

<p>{get()}</p>

<button onclick={()=>set()}></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let count = $state(0);

export function get() {
return count;
}

export function set() {
count++;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client'],
async test({ assert, target }) {
const p = target.querySelector('p');
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.equal(p?.innerHTML, '1');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { get, set } from "./test.svelte.js";

export const x = 42;
</script>

<p>{get()}</p>

<button onclick={()=>set()}></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let count = $state(0);

export function get() {
return count;
}

export function set() {
count++;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client'],
async test({ assert, target }) {
const p = target.querySelector('p');
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.equal(p?.innerHTML, '1');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script>
import { get, set } from "./test.svelte.js";

let x = 42;

export { x };
</script>

{x}
<p>{get()}</p>

<button onclick={()=>set()}></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let count = $state(0);

export function get() {
return count;
}

export function set() {
count++;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
mode: ['client'],
async test({ assert, target }) {
const p = target.querySelector('p');
const btn = target.querySelector('button');
flushSync(() => {
btn?.click();
});
assert.equal(p?.innerHTML, '1');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
import { get, set } from "./test.svelte.js";
</script>

<p>{get()}</p>

<button onclick={()=>set()}></button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
let count = $state(0);

export function get() {
return count;
}

export function set() {
count++;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ export default function Purity($$anchor) {
var fragment = root();
var p = $.first_child(fragment);

p.textContent = (
$.untrack(() => Math.max(0, Math.min(0, 100)))
);
p.textContent = '0';

var p_1 = $.sibling(p, 2);

p_1.textContent = ($.untrack(() => location.href));
p_1.textContent = location.href;

var node = $.sibling(p_1, 2);

Expand Down