Skip to content

Commit 53de73d

Browse files
authored
feat: simpler output for reactive vars if dependencies are all static (#7942)
1 parent c9a269c commit 53de73d

File tree

7 files changed

+101
-15
lines changed

7 files changed

+101
-15
lines changed

src/compiler/compile/Component.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import compiler_warnings from './compiler_warnings';
3838
import compiler_errors from './compiler_errors';
3939
import { extract_ignores_above_position, extract_svelte_ignore_from_comments } from '../utils/extract_svelte_ignore';
4040
import check_enable_sourcemap from './utils/check_enable_sourcemap';
41+
import is_dynamic from './render_dom/wrappers/shared/is_dynamic';
4142

4243
interface ComponentOptions {
4344
namespace?: string;
@@ -1380,12 +1381,11 @@ export default class Component {
13801381
module_dependencies.add(name);
13811382
}
13821383
}
1383-
const is_writable_or_mutated =
1384-
variable && (variable.writable || variable.mutated);
1384+
13851385
if (
13861386
should_add_as_dependency &&
13871387
(!owner || owner === component.instance_scope) &&
1388-
(name[0] === '$' || is_writable_or_mutated)
1388+
(name[0] === '$' || variable)
13891389
) {
13901390
dependencies.add(name);
13911391
}
@@ -1409,6 +1409,19 @@ export default class Component {
14091409
const { expression } = node.body as ExpressionStatement;
14101410
const declaration = expression && (expression as AssignmentExpression).left;
14111411

1412+
const is_dependency_static = Array.from(dependencies).every(
1413+
dependency => dependency !== '$$props' && dependency !== '$$restProps' && !is_dynamic(this.var_lookup.get(dependency))
1414+
);
1415+
1416+
if (is_dependency_static) {
1417+
assignees.forEach(assignee => {
1418+
const variable = component.var_lookup.get(assignee);
1419+
if (variable) {
1420+
variable.is_reactive_static = true;
1421+
}
1422+
});
1423+
}
1424+
14121425
unsorted_reactive_declarations.push({
14131426
assignees,
14141427
dependencies,

src/compiler/compile/render_dom/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -390,13 +390,13 @@ export default function dom(
390390
const resubscribable_reactive_store_unsubscribers = reactive_stores
391391
.filter(store => {
392392
const variable = component.var_lookup.get(store.name.slice(1));
393-
return variable && (variable.reassigned || variable.export_name);
393+
return variable && (variable.reassigned || variable.export_name) && !variable.is_reactive_static;
394394
})
395395
.map(({ name }) => b`$$self.$$.on_destroy.push(() => ${`$$unsubscribe_${name.slice(1)}`}());`);
396396

397397
if (has_definition) {
398-
const reactive_declarations: (Node | Node[]) = [];
399-
const fixed_reactive_declarations: Node[] = []; // not really 'reactive' but whatever
398+
const reactive_declarations: Node[] = [];
399+
const fixed_reactive_declarations: Array<Node | Node[]> = []; // not really 'reactive' but whatever
400400

401401
component.reactive_declarations.forEach(d => {
402402
const dependencies = Array.from(d.dependencies);
@@ -417,6 +417,15 @@ export default function dom(
417417
reactive_declarations.push(statement);
418418
} else {
419419
fixed_reactive_declarations.push(statement);
420+
for (const assignee of d.assignees) {
421+
const variable = component.var_lookup.get(assignee);
422+
if (variable && variable.subscribable) {
423+
fixed_reactive_declarations.push(b`
424+
${component.compile_options.dev && b`@validate_store(${assignee}, '${assignee}');`}
425+
@component_subscribe($$self, ${assignee}, $$value => $$invalidate(${renderer.context_lookup.get('$' + assignee).index}, ${'$' + assignee} = $$value));
426+
`);
427+
}
428+
}
420429
}
421430
});
422431

@@ -430,7 +439,7 @@ export default function dom(
430439
const name = $name.slice(1);
431440

432441
const store = component.var_lookup.get(name);
433-
if (store && (store.reassigned || store.export_name)) {
442+
if (store && (store.reassigned || store.export_name) && !store.is_reactive_static) {
434443
const unsubscribe = `$$unsubscribe_${name}`;
435444
const subscribe = `$$subscribe_${name}`;
436445
const i = renderer.context_lookup.get($name).index;

src/compiler/compile/render_dom/invalidate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export function invalidate(renderer: Renderer, scope: Scope, node: Node, names:
1919
!variable.hoistable &&
2020
!variable.global &&
2121
!variable.module &&
22+
!variable.is_reactive_static &&
2223
(
2324
variable.referenced ||
2425
variable.subscribable ||

src/compiler/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ export interface Var {
223223
subscribable?: boolean;
224224
is_reactive_dependency?: boolean;
225225
imported?: boolean;
226+
is_reactive_static?: boolean;
226227
}
227228

228229
export interface CssResult {

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
noop,
1010
safe_not_equal,
1111
space,
12-
subscribe,
1312
toggle_class
1413
} from "svelte/internal";
1514

@@ -133,13 +132,8 @@ let reactiveModuleVar = Math.random();
133132
function instance($$self, $$props, $$invalidate) {
134133
let reactiveDeclaration;
135134
let $reactiveStoreVal;
136-
137-
let $reactiveDeclaration,
138-
$$unsubscribe_reactiveDeclaration = noop,
139-
$$subscribe_reactiveDeclaration = () => ($$unsubscribe_reactiveDeclaration(), $$unsubscribe_reactiveDeclaration = subscribe(reactiveDeclaration, $$value => $$invalidate(3, $reactiveDeclaration = $$value)), reactiveDeclaration);
140-
135+
let $reactiveDeclaration;
141136
component_subscribe($$self, reactiveStoreVal, $$value => $$invalidate(2, $reactiveStoreVal = $$value));
142-
$$self.$$.on_destroy.push(() => $$unsubscribe_reactiveDeclaration());
143137
nonReactiveGlobal = Math.random();
144138
const reactiveConst = { x: Math.random() };
145139
reactiveModuleVar += 1;
@@ -148,7 +142,8 @@ function instance($$self, $$props, $$invalidate) {
148142
reactiveConst.x += 1;
149143
}
150144

151-
$: $$subscribe_reactiveDeclaration($$invalidate(1, reactiveDeclaration = reactiveModuleVar * 2));
145+
$: reactiveDeclaration = reactiveModuleVar * 2;
146+
component_subscribe($$self, reactiveDeclaration, $$value => $$invalidate(3, $reactiveDeclaration = $$value));
152147
return [reactiveConst, reactiveDeclaration, $reactiveStoreVal, $reactiveDeclaration];
153148
}
154149

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* generated by Svelte vX.Y.Z */
2+
import {
3+
SvelteComponent,
4+
detach,
5+
element,
6+
init,
7+
insert,
8+
noop,
9+
safe_not_equal,
10+
set_data,
11+
space,
12+
text
13+
} from "svelte/internal";
14+
15+
function create_fragment(ctx) {
16+
let h1;
17+
let t3;
18+
let t4;
19+
20+
return {
21+
c() {
22+
h1 = element("h1");
23+
h1.textContent = `Hello ${name}!`;
24+
t3 = space();
25+
t4 = text(/*foo*/ ctx[0]);
26+
},
27+
m(target, anchor) {
28+
insert(target, h1, anchor);
29+
insert(target, t3, anchor);
30+
insert(target, t4, anchor);
31+
},
32+
p(ctx, [dirty]) {
33+
if (dirty & /*foo*/ 1) set_data(t4, /*foo*/ ctx[0]);
34+
},
35+
i: noop,
36+
o: noop,
37+
d(detaching) {
38+
if (detaching) detach(h1);
39+
if (detaching) detach(t3);
40+
if (detaching) detach(t4);
41+
}
42+
};
43+
}
44+
45+
let name = 'world';
46+
47+
function instance($$self) {
48+
let foo;
49+
$: foo = name + name;
50+
return [foo];
51+
}
52+
53+
class Component extends SvelteComponent {
54+
constructor(options) {
55+
super();
56+
init(this, options, instance, create_fragment, safe_not_equal, {});
57+
}
58+
}
59+
60+
export default Component;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let name = 'world';
3+
$: foo = name + name;
4+
</script>
5+
6+
<h1>Hello {name}!</h1>
7+
{foo}

0 commit comments

Comments
 (0)