Skip to content

Commit 7a8cf3a

Browse files
trueadmRich-Harris
andauthored
fix: ensure directives run in sequential order (#12591)
Co-authored-by: Rich Harris <[email protected]>
1 parent c173140 commit 7a8cf3a

File tree

4 files changed

+35
-41
lines changed

4 files changed

+35
-41
lines changed

.changeset/plenty-turkeys-raise.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: ensure directives run in sequential order

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,8 +1233,8 @@ function serialize_event_handler(node, metadata, { state, visit }) {
12331233
function serialize_event(node, metadata, context) {
12341234
const state = context.state;
12351235

1236-
/** @type {Statement} */
1237-
let statement;
1236+
/** @type {Expression} */
1237+
let expression;
12381238

12391239
if (node.expression) {
12401240
let handler = serialize_event_handler(node, metadata, context);
@@ -1303,19 +1303,23 @@ function serialize_event(node, metadata, context) {
13031303
}
13041304

13051305
// Events need to run in order with bindings/actions
1306-
statement = b.stmt(b.call('$.event', ...args));
1306+
expression = b.call('$.event', ...args);
13071307
} else {
1308-
statement = b.stmt(
1309-
b.call(
1310-
'$.event',
1311-
b.literal(node.name),
1312-
state.node,
1313-
serialize_event_handler(node, metadata, context)
1314-
)
1308+
expression = b.call(
1309+
'$.event',
1310+
b.literal(node.name),
1311+
state.node,
1312+
serialize_event_handler(node, metadata, context)
13151313
);
13161314
}
13171315

13181316
const parent = /** @type {SvelteNode} */ (context.path.at(-1));
1317+
const has_action_directive =
1318+
parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective');
1319+
const statement = b.stmt(
1320+
has_action_directive ? b.call('$.effect', b.thunk(expression)) : expression
1321+
);
1322+
13191323
if (
13201324
parent.type === 'SvelteDocument' ||
13211325
parent.type === 'SvelteWindow' ||
@@ -3083,12 +3087,20 @@ export const template_visitors = {
30833087
}
30843088
}
30853089

3090+
const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1));
3091+
const has_action_directive =
3092+
parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective');
3093+
30863094
// Bindings need to happen after attribute updates, therefore after the render effect, and in order with events/actions.
30873095
// bind:this is a special case as it's one-way and could influence the render effect.
30883096
if (node.name === 'this') {
3089-
state.init.push(b.stmt(call_expr));
3097+
state.init.push(
3098+
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
3099+
);
30903100
} else {
3091-
state.after_update.push(b.stmt(call_expr));
3101+
state.after_update.push(
3102+
b.stmt(has_action_directive ? b.call('$.effect', b.thunk(call_expr)) : call_expr)
3103+
);
30923104
}
30933105
},
30943106
Component(node, context) {

packages/svelte/src/internal/client/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export {
101101
legacy_pre_effect_reset,
102102
render_effect,
103103
template_effect,
104+
effect,
104105
user_effect,
105106
user_pre_effect
106107
} from './reactivity/effects.js';

packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/_config.js

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,49 +21,25 @@ export default test({
2121
flushSync();
2222
}
2323

24-
// Svelte 5 breaking change, use:action now fires
25-
// in effect phase. So they will occur AFTER the others.
2624
assert.deepEqual(value, [
25+
'1',
2726
'2',
2827
'3',
29-
'1',
28+
'4',
3029
'5',
3130
'6',
32-
'4',
3331
'7',
34-
'9',
3532
'8',
33+
'9',
3634
'10',
3735
'11',
3836
'12',
3937
'13',
4038
'14',
4139
'15',
4240
'16',
43-
'18',
44-
'17'
41+
'17',
42+
'18'
4543
]);
46-
47-
// Previously
48-
// assert.deepEqual(value, [
49-
// '1',
50-
// '2',
51-
// '3',
52-
// '4',
53-
// '5',
54-
// '6',
55-
// '7',
56-
// '8',
57-
// '9',
58-
// '10',
59-
// '11',
60-
// '12',
61-
// '13',
62-
// '14',
63-
// '15',
64-
// '16',
65-
// '17',
66-
// '18',
67-
// ]);
6844
}
6945
});

0 commit comments

Comments
 (0)