diff --git a/.changeset/nervous-ties-sin.md b/.changeset/nervous-ties-sin.md new file mode 100644 index 0000000000..40cc478a9a --- /dev/null +++ b/.changeset/nervous-ties-sin.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: hoist else-if block closures diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 1afe2058b6..513631b7b3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -93,7 +93,8 @@ export function client_component(source, analysis, options) { preserve_whitespace: options.preserveWhitespace, public_state: new Map(), private_state: new Map(), - in_constructor: false + in_constructor: false, + else_if_init: null }; const module = /** @type {import('estree').Program} */ ( @@ -466,7 +467,8 @@ export function client_module(analysis, options) { legacy_reactive_statements: new Map(), public_state: new Map(), private_state: new Map(), - in_constructor: false + in_constructor: false, + else_if_init: null }; const module = /** @type {import('estree').Program} */ ( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index ef9b466bad..2b5305d4c5 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -19,6 +19,12 @@ export interface ClientTransformState extends TransformState { */ readonly in_constructor: boolean; + /** + * `true` if the current lexical scope belongs to the alternate of an IfBlock. This + * allows us to hoist alternate if-blocks to the same scope as the original IfBlock. + */ + readonly else_if_init: null | Statement[]; + /** The $: calls, which will be ordered in the end */ readonly legacy_reactive_statements: Map; } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 09adde9d27..a40d110229 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -2298,6 +2298,28 @@ export const template_visitors = { const consequent = /** @type {import('estree').BlockStatement} */ ( context.visit(node.consequent) ); + const in_else_if = + node.alternate !== null && + node.alternate.nodes.length === 1 && + node.alternate.nodes[0].type === 'IfBlock'; + const else_if_init = in_else_if ? context.state.else_if_init || context.state.init : null; + const else_if_block_id = in_else_if ? context.state.scope.generate('else_if') : null; + + const alternate = node.alternate + ? b.arrow( + [b.id('$$anchor')], + /** @type {import('estree').BlockStatement} */ ( + context.visit(node.alternate, { + ...context.state, + else_if_init + }) + ) + ) + : null; + + if (else_if_block_id && else_if_init && alternate) { + else_if_init.push(b.var(else_if_block_id, alternate)); + } context.state.after_update.push( b.stmt( @@ -2306,12 +2328,7 @@ export const template_visitors = { context.state.node, b.thunk(/** @type {import('estree').Expression} */ (context.visit(node.test))), b.arrow([b.id('$$anchor')], consequent), - node.alternate - ? b.arrow( - [b.id('$$anchor')], - /** @type {import('estree').BlockStatement} */ (context.visit(node.alternate)) - ) - : b.literal(null) + alternate ? (else_if_block_id ? b.id(else_if_block_id) : alternate) : b.literal(null) ) ) );