diff --git a/.changeset/eight-brooms-exist.md b/.changeset/eight-brooms-exist.md new file mode 100644 index 0000000000..648df509a3 --- /dev/null +++ b/.changeset/eight-brooms-exist.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: no inlining for conditionals inside legacy template expressions diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index a96652d60b..da85444b64 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -67,6 +67,7 @@ import { TransitionDirective } from './visitors/TransitionDirective.js'; import { UpdateExpression } from './visitors/UpdateExpression.js'; import { UseDirective } from './visitors/UseDirective.js'; import { VariableDeclarator } from './visitors/VariableDeclarator.js'; +import { ConditionalExpression } from './visitors/ConditionalExpression.js'; import is_reference from 'is-reference'; import { mark_subtree_dynamic } from './visitors/shared/fragment.js'; @@ -177,7 +178,8 @@ const visitors = { TitleElement, UpdateExpression, UseDirective, - VariableDeclarator + VariableDeclarator, + ConditionalExpression }; /** diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js index ca0ea55d1f..ec48414bf6 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Attribute.js @@ -30,6 +30,10 @@ export function Attribute(node, context) { } } + if (node.name === 'autofocus' || node.name === 'muted') { + mark_subtree_dynamic(context.path); + } + if (node.name.startsWith('on')) { mark_subtree_dynamic(context.path); } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/ConditionalExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/ConditionalExpression.js new file mode 100644 index 0000000000..0544ba6ee3 --- /dev/null +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/ConditionalExpression.js @@ -0,0 +1,17 @@ +/** @import { ConditionalExpression } from 'estree' */ +/** @import { Context } from '../types' */ + +import { mark_subtree_dynamic } from './shared/fragment'; + +/** + * @param {ConditionalExpression} node + * @param {Context} context + */ +export function ConditionalExpression(node, context) { + // In legacy mode, we treat conditionals inside the template as not inlinable so patterns + // such as BROWSER ? foo : bar, continue to work during hydration + if (context.state.expression && !context.state.analysis.runes) { + context.state.expression.can_inline = false; + mark_subtree_dynamic(context.path); + } +} diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js index 60bd1dd0c5..7d1c4aaeaa 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js @@ -75,16 +75,6 @@ export function RegularElement(node, context) { node.attributes.push(create_attribute('value', child.start, child.end, [child])); } - if ( - node.attributes.some( - (attribute) => - attribute.type === 'Attribute' && - (attribute.name === 'autofocus' || attribute.name === 'muted') - ) - ) { - mark_subtree_dynamic(context.path); - } - const binding = context.state.scope.get(node.name); if ( binding !== null && diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js index 1b0737e31e..dc7bc9452d 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js @@ -3,7 +3,7 @@ /** @import { ComponentClientTransformState, ComponentContext } from '../../types' */ import { normalize_attribute } from '../../../../../../utils.js'; import { is_ignored } from '../../../../../state.js'; -import { get_attribute_expression, is_event_attribute } from '../../../../../utils/ast.js'; +import { is_event_attribute } from '../../../../../utils/ast.js'; import * as b from '../../../../../utils/builders.js'; import { build_getter, create_derived } from '../../utils.js'; import { build_template_chunk, build_update } from './utils.js'; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js index ac6e0f8f9f..ef2746f083 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js @@ -142,10 +142,6 @@ function is_static_element(node) { return false; } - if (attribute.name === 'autofocus' || attribute.name === 'muted') { - return false; - } - if (node.name === 'option' && attribute.name === 'value') { return false; } diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-4/_config.js new file mode 100644 index 0000000000..688c2f3232 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-4/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `