From f911483b9e5332cd7040d9f9f844eba75ccdf8f3 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Sep 2025 21:26:33 -0400 Subject: [PATCH] fix --- .../server/visitors/RegularElement.js | 39 +++++++++++++++---- .../server/visitors/shared/element.js | 28 ++++++------- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js index 3ae9e9ce88..9440719abc 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js @@ -28,23 +28,38 @@ export function RegularElement(node, context) { ...context.state, namespace, preserve_whitespace: - context.state.preserve_whitespace || node.name === 'pre' || node.name === 'textarea' + context.state.preserve_whitespace || node.name === 'pre' || node.name === 'textarea', + init: [], + template: [] }; const node_is_void = is_void(node.name); const optimiser = new PromiseOptimiser(); - context.state.template.push(b.literal(`<${node.name}`)); + state.template.push(b.literal(`<${node.name}`)); const body = build_element_attributes(node, { ...context, state }, optimiser.transform); - context.state.template.push(b.literal(node_is_void ? '/>' : '>')); // add `/>` for XHTML compliance + state.template.push(b.literal(node_is_void ? '/>' : '>')); // add `/>` for XHTML compliance if ((node.name === 'script' || node.name === 'style') && node.fragment.nodes.length === 1) { - context.state.template.push( + state.template.push( b.literal(/** @type {AST.Text} */ (node.fragment.nodes[0]).data), b.literal(``) ); + // TODO this is a real edge case, would be good to DRY this out + if (optimiser.expressions.length > 0) { + context.state.template.push( + call_child_renderer( + b.block([optimiser.apply(), ...state.init, ...build_template(state.template)]), + true + ) + ); + } else { + context.state.init.push(...state.init); + context.state.template.push(...state.template); + } + return; } @@ -96,7 +111,7 @@ export function RegularElement(node, context) { select_with_value = true; select_with_value_async ||= spread.metadata.expression.has_await; - const { object, has_await } = build_spread_object( + const object = build_spread_object( node, node.attributes.filter( (attribute) => @@ -108,8 +123,6 @@ export function RegularElement(node, context) { optimiser.transform ); - // TODO use has_await - state.template.push( b.stmt( b.assignment( @@ -236,4 +249,16 @@ export function RegularElement(node, context) { if (dev) { state.template.push(b.stmt(b.call('$.pop_element'))); } + + if (optimiser.expressions.length > 0) { + context.state.template.push( + call_child_renderer( + b.block([optimiser.apply(), ...state.init, ...build_template(state.template)]), + true + ) + ); + } else { + context.state.init.push(...state.init); + context.state.template.push(...state.template); + } } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js index ae71faf60b..fd651e113c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js @@ -219,7 +219,7 @@ export function build_element_attributes(node, context, transform) { if (node.name === 'option') { // TODO this is all wrong, it inlines the spread twice - const { object, has_await } = build_spread_object( + const object = build_spread_object( node, node.attributes.filter( (attribute) => @@ -231,8 +231,6 @@ export function build_element_attributes(node, context, transform) { transform ); - // TODO use has_await? - context.state.template.push( b.call('$.maybe_selected', b.id('$$renderer'), b.member(object, 'value', false, true)) ); @@ -348,8 +346,6 @@ function get_attribute_name(element, attribute) { * @param {(expression: Expression, metadata: ExpressionMetadata) => Expression} transform */ export function build_spread_object(element, attributes, context, transform) { - let has_await = false; - const object = b.object( attributes.map((attribute) => { if (attribute.type === 'Attribute') { @@ -375,13 +371,16 @@ export function build_spread_object(element, attributes, context, transform) { return b.prop('init', b.key(name), value); } - has_await ||= attribute.metadata.expression.has_await; - - return b.spread(/** @type {Expression} */ (context.visit(attribute))); + return b.spread( + transform( + /** @type {Expression} */ (context.visit(attribute)), + attribute.metadata.expression + ) + ); }) ); - return { object, has_await }; + return object; } /** @@ -445,23 +444,18 @@ function build_element_spread_attributes( flags |= ELEMENT_IS_INPUT; } - const spread = build_spread_object(element, attributes, context, transform); + const object = build_spread_object(element, attributes, context, transform); const css_hash = element.metadata.scoped && context.state.analysis.css.hash ? b.literal(context.state.analysis.css.hash) : undefined; - const args = [spread.object, css_hash, classes, styles, flags ? b.literal(flags) : undefined]; + const args = [object, css_hash, classes, styles, flags ? b.literal(flags) : undefined]; let call = b.call('$.attributes', ...args); - if (spread.has_await) { - call = b.call('$$renderer.push', b.thunk(call, true)); - context.state.template.push(b.stmt(call)); - } else { - context.state.template.push(call); - } + context.state.template.push(call); } /**