Skip to content

chore: update sequencing inside blocks #10939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ export function client_component(source, analysis, options) {
hoisted: [b.import_all('$', 'svelte/internal')],
node: /** @type {any} */ (null), // populated by the root node
// these should be set by create_block - if they're called outside, it's a bug
get before_init() {
/** @type {any[]} */
const a = [];
a.push = () => error(null, 'INTERNAL', 'before_init.push should not be called outside create_block');
return a;
},
get init() {
/** @type {any[]} */
const a = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly hoisted: Array<Statement | ModuleDeclaration>;
readonly events: Set<string>;

/** Stuff that happens before the render effect(s) */
readonly before_init: Statement[];
/** Stuff that happens before the render effect(s) */
readonly init: Statement[];
/** Stuff that happens inside the render effect */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@ function create_block(parent, name, nodes, context) {
/** @type {import('../types').ComponentClientTransformState} */
const state = {
...context.state,
before_init: [],
init: [],
update: [],
after_update: [],
Expand Down Expand Up @@ -1050,11 +1051,11 @@ function create_block(parent, name, nodes, context) {
args.push(b.false);
}

body.push(b.var(id, b.call('$.open', ...args)), ...state.init);
body.push(b.var(id, b.call('$.open', ...args)), ...state.before_init, ...state.init);
close = b.stmt(b.call('$.close', b.id('$$anchor'), id));
} else if (is_single_child_not_needing_template) {
context.visit(trimmed[0], state);
body.push(...state.init);
body.push(...state.before_init, ...state.init);
} else if (trimmed.length > 0) {
const id = b.id(context.state.scope.generate('fragment'));

Expand All @@ -1071,7 +1072,11 @@ function create_block(parent, name, nodes, context) {
state
});

body.push(b.var(id, b.call('$.space_frag', b.id('$$anchor'))), ...state.init);
body.push(
b.var(id, b.call('$.space_frag', b.id('$$anchor'))),
...state.before_init,
...state.init
);
close = b.stmt(b.call('$.close', b.id('$$anchor'), id));
} else {
/** @type {(is_text: boolean) => import('estree').Expression} */
Expand Down Expand Up @@ -1107,12 +1112,12 @@ function create_block(parent, name, nodes, context) {
body.push(b.var(id, b.call('$.open_frag', ...args)));
}

body.push(...state.init);
body.push(...state.before_init, ...state.init);

close = b.stmt(b.call('$.close_frag', b.id('$$anchor'), id));
}
} else {
body.push(...state.init);
body.push(...state.before_init, ...state.init);
}

if (state.update.length > 0) {
Expand Down Expand Up @@ -1256,6 +1261,9 @@ function serialize_event_handler(node, { state, visit }) {
function serialize_event(node, context) {
const state = context.state;

/** @type {import('estree').Statement} */
let statement;

if (node.expression) {
let handler = serialize_event_handler(node, context);
const event_name = node.name;
Expand Down Expand Up @@ -1291,7 +1299,7 @@ function serialize_event(node, context) {
delegated_assignment = handler;
}

state.after_update.push(
state.init.push(
b.stmt(
b.assignment(
'=',
Expand Down Expand Up @@ -1323,14 +1331,19 @@ function serialize_event(node, context) {
}

// Events need to run in order with bindings/actions
state.after_update.push(b.stmt(b.call('$.event', ...args)));
statement = b.stmt(b.call('$.event', ...args));
} else {
state.after_update.push(
b.stmt(
b.call('$.event', b.literal(node.name), state.node, serialize_event_handler(node, context))
)
statement = b.stmt(
b.call('$.event', b.literal(node.name), state.node, serialize_event_handler(node, context))
);
}

const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1));
if (parent.type === 'SvelteDocument' || parent.type === 'SvelteWindow') {
state.before_init.push(statement);
} else {
state.after_update.push(statement);
}
}

/**
Expand Down Expand Up @@ -1720,11 +1733,9 @@ export const template_visitors = {
}

if (is_reactive) {
context.state.after_update.push(
b.stmt(b.call('$.snippet', b.thunk(snippet_function), ...args))
);
context.state.init.push(b.stmt(b.call('$.snippet', b.thunk(snippet_function), ...args)));
} else {
context.state.after_update.push(
context.state.init.push(
b.stmt(
(node.expression.type === 'CallExpression' ? b.call : b.maybe_call)(
snippet_function,
Expand Down Expand Up @@ -2029,6 +2040,7 @@ export const template_visitors = {
state: {
...context.state,
node: element_id,
before_init: [],
init: [],
update: [],
after_update: []
Expand Down Expand Up @@ -2091,7 +2103,7 @@ export const template_visitors = {
}
})
);
context.state.after_update.push(
context.state.init.push(
b.stmt(
b.call(
'$.element',
Expand Down Expand Up @@ -2372,7 +2384,7 @@ export const template_visitors = {
);
}

context.state.after_update.push(b.stmt(b.call(callee, ...args)));
context.state.init.push(b.stmt(b.call(callee, ...args)));
},
IfBlock(node, context) {
context.state.template.push('<!>');
Expand Down Expand Up @@ -2423,12 +2435,12 @@ export const template_visitors = {
args.push(b.literal(true));
}

context.state.after_update.push(b.stmt(b.call('$.if', ...args)));
context.state.init.push(b.stmt(b.call('$.if', ...args)));
},
AwaitBlock(node, context) {
context.state.template.push('<!>');

context.state.after_update.push(
context.state.init.push(
b.stmt(
b.call(
'$.await',
Expand Down Expand Up @@ -2470,7 +2482,7 @@ export const template_visitors = {
context.state.template.push('<!>');
const key = /** @type {import('estree').Expression} */ (context.visit(node.expression));
const body = /** @type {import('estree').Expression} */ (context.visit(node.fragment));
context.state.after_update.push(
context.state.init.push(
b.stmt(b.call('$.key', context.state.node, b.thunk(key), b.arrow([b.id('$$anchor')], body)))
);
},
Expand Down Expand Up @@ -2791,7 +2803,7 @@ export const template_visitors = {
if (binding !== null && binding.kind !== 'normal') {
// Handle dynamic references to what seems like static inline components
const component = serialize_inline_component(node, '$$component', context);
context.state.after_update.push(
context.state.init.push(
b.stmt(
b.call(
'$.component',
Expand All @@ -2808,12 +2820,12 @@ export const template_visitors = {
return;
}
const component = serialize_inline_component(node, node.name, context);
context.state.after_update.push(component);
context.state.init.push(component);
},
SvelteSelf(node, context) {
context.state.template.push('<!>');
const component = serialize_inline_component(node, context.state.analysis.name, context);
context.state.after_update.push(component);
context.state.init.push(component);
},
SvelteComponent(node, context) {
context.state.template.push('<!>');
Expand All @@ -2822,7 +2834,7 @@ export const template_visitors = {
if (context.state.options.dev) {
component = b.stmt(b.call('$.validate_dynamic_component', b.thunk(b.block([component]))));
}
context.state.after_update.push(
context.state.init.push(
b.stmt(
b.call(
'$.component',
Expand Down Expand Up @@ -2974,7 +2986,7 @@ export const template_visitors = {
: b.member(b.member(b.id('$$props'), b.id('$$slots')), name, true, true);

const slot = b.call('$.slot', context.state.node, expression, props_expression, fallback);
context.state.after_update.push(b.stmt(slot));
context.state.init.push(b.stmt(slot));
},
SvelteHead(node, context) {
// TODO attributes?
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/hydration.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export function capture_fragment_from_node(node) {
if (
node.nodeType === 8 &&
/** @type {Comment} */ (node).data === '[' &&
hydrate_nodes[hydrate_nodes.length - 1] !== node
hydrate_nodes?.[hydrate_nodes.length - 1] !== node
) {
const nodes = /** @type {Node[]} */ (get_hydrate_nodes(node));
const last_child = nodes[nodes.length - 1] || node;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ export default test({
};
},
test({ assert }) {
assert.deepEqual(result, ['import_action', 'each_action']);
assert.deepEqual(result, ['each_action', 'import_action']); // ideally this would be reversed, but it doesn't matter a whole lot
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export default function State_proxy_literal($$anchor, $$props) {

var button = $.sibling($.sibling(input_1, true));

button.__click = [reset, str, tpl];
$.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value));
$.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value));
button.__click = [reset, str, tpl];
$.close_frag($$anchor, fragment);
$.pop();
}
Expand Down