Skip to content

Commit 6589aa2

Browse files
authored
warn module variables are nonreactive and make them truly nonreactive (#5847)
1 parent dd7403a commit 6589aa2

File tree

7 files changed

+79
-10
lines changed

7 files changed

+79
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
* Warn when using `module` variables reactively, and close weird reactivity loophole ([#5847](https://github.com/sveltejs/svelte/pull/5847))
56
* Throw a parser error for `class:` directives with an empty class name ([#5858](https://github.com/sveltejs/svelte/issues/5858))
67
* Fix extraneous store subscription in SSR mode ([#5883](https://github.com/sveltejs/svelte/issues/5883))
78
* Don't emit update code for `class:` directives whose expression is not dynamic ([#5919](https://github.com/sveltejs/svelte/issues/5919))

src/compiler/compile/Component.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,15 +1175,20 @@ export default class Component {
11751175
extract_reactive_declarations() {
11761176
const component = this;
11771177

1178-
const unsorted_reactive_declarations = [];
1178+
const unsorted_reactive_declarations: Array<{
1179+
assignees: Set<string>;
1180+
dependencies: Set<string>;
1181+
node: Node;
1182+
declaration: Node;
1183+
}> = [];
11791184

11801185
this.ast.instance.content.body.forEach(node => {
11811186
if (node.type === 'LabeledStatement' && node.label.name === '$') {
11821187
this.reactive_declaration_nodes.add(node);
11831188

1184-
const assignees = new Set();
1189+
const assignees = new Set<string>();
11851190
const assignee_nodes = new Set();
1186-
const dependencies = new Set();
1191+
const dependencies = new Set<string>();
11871192

11881193
let scope = this.instance_scope;
11891194
const map = this.instance_scope_map;
@@ -1214,10 +1219,22 @@ export default class Component {
12141219
const { name } = identifier;
12151220
const owner = scope.find_owner(name);
12161221
const variable = component.var_lookup.get(name);
1217-
if (variable) variable.is_reactive_dependency = true;
1222+
let should_add_as_dependency = true;
1223+
1224+
if (variable) {
1225+
variable.is_reactive_dependency = true;
1226+
if (variable.module) {
1227+
should_add_as_dependency = false;
1228+
component.warn(node as any, {
1229+
code: 'module-script-reactive-declaration',
1230+
message: `"${name}" is declared in a module script and will not be reactive`
1231+
});
1232+
}
1233+
}
12181234
const is_writable_or_mutated =
12191235
variable && (variable.writable || variable.mutated);
12201236
if (
1237+
should_add_as_dependency &&
12211238
(!owner || owner === component.instance_scope) &&
12221239
(name[0] === '$' || is_writable_or_mutated)
12231240
) {

test/js/samples/reactive-class-optimized/expected.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,7 @@ function instance($$self, $$props, $$invalidate) {
148148
reactiveConst.x += 1;
149149
}
150150

151-
$$self.$$.update = () => {
152-
if ($$self.$$.dirty & /*reactiveModuleVar*/ 0) {
153-
$: $$subscribe_reactiveDeclaration($$invalidate(1, reactiveDeclaration = reactiveModuleVar * 2));
154-
}
155-
};
156-
151+
$: $$subscribe_reactiveDeclaration($$invalidate(1, reactiveDeclaration = reactiveModuleVar * 2));
157152
return [reactiveConst, reactiveDeclaration, $reactiveStoreVal, $reactiveDeclaration];
158153
}
159154

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export default {
2+
html: `
3+
a: moduleA
4+
b: moduleB
5+
moduleA: moduleA
6+
moduleB: moduleB
7+
`,
8+
async test({ assert, target, component }) {
9+
await component.updateModuleA();
10+
11+
assert.htmlEqual(target.innerHTML, `
12+
a: moduleA
13+
b: moduleB
14+
moduleA: moduleA
15+
moduleB: moduleB
16+
`);
17+
}
18+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script context="module">
2+
let moduleA = 'moduleA';
3+
let moduleB = 'moduleB';
4+
</script>
5+
<script>
6+
export function updateModuleA() {
7+
moduleA = 'something else';
8+
}
9+
$: a = moduleA;
10+
$: b = moduleB;
11+
</script>
12+
a: {a}
13+
b: {b}
14+
moduleA: {moduleA}
15+
moduleB: {moduleB}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script context="module">
2+
let foo;
3+
</script>
4+
<script>
5+
$: bar = foo;
6+
</script>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[
2+
{
3+
"code": "module-script-reactive-declaration",
4+
"message": "\"foo\" is declared in a module script and will not be reactive",
5+
"pos": 65,
6+
"start": {
7+
"character": 65,
8+
"column": 10,
9+
"line": 5
10+
},
11+
"end": {
12+
"character": 68,
13+
"column": 13,
14+
"line": 5
15+
}
16+
}
17+
]

0 commit comments

Comments
 (0)