diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 1c4a75fb16..d1348a9e5e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -496,7 +496,7 @@ export function build_class_directives_object( * @param {ComponentContext} context * @param {MemoizedExpression[]} async_expressions * @param {MemoizedExpression[]} expressions - * @return {ObjectExpression | ArrayExpression}} + * @return {ObjectExpression | ArrayExpression | Identifier}} */ export function build_style_directives_object( style_directives, @@ -506,28 +506,33 @@ export function build_style_directives_object( ) { let normal_properties = []; let important_properties = []; + let has_call_or_state = false; + let has_await = false; - for (const directive of style_directives) { + for (const d of style_directives) { const expression = - directive.value === true - ? build_getter({ name: directive.name, type: 'Identifier' }, context.state) - : build_attribute_value(directive.value, context, (value, metadata) => - metadata.has_call - ? get_expression_id(metadata.has_await ? async_expressions : expressions, value) - : value - ).value; - const property = b.init(directive.name, expression); + d.value === true + ? build_getter({ name: d.name, type: 'Identifier' }, context.state) + : build_attribute_value(d.value, context).value; + const property = b.init(d.name, expression); - if (directive.modifiers.includes('important')) { + if (d.modifiers.includes('important')) { important_properties.push(property); } else { normal_properties.push(property); } + + has_call_or_state ||= d.metadata.expression.has_call || d.metadata.expression.has_state; + has_await ||= d.metadata.expression.has_await; } - return important_properties.length + const directives = important_properties.length ? b.array([b.object(normal_properties), b.object(important_properties)]) : b.object(normal_properties); + + return has_call_or_state || has_await + ? get_expression_id(has_await ? async_expressions : expressions, directives) + : directives; } /** 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 b1b1a8fae4..868cfe2946 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 @@ -87,18 +87,24 @@ export function build_attribute_effect( ); } + const all = [...expressions, ...async_expressions]; + + for (let i = 0; i < all.length; i += 1) { + all[i].id.name = `$${i}`; + } + context.state.init.push( b.stmt( b.call( '$.attribute_effect', element_id, b.arrow( - expressions.map(({ id }) => id), + all.map(({ id }) => id), b.object(values) ), expressions.length > 0 && b.array(expressions.map(({ expression }) => b.thunk(expression))), async_expressions.length > 0 && - b.array(async_expressions.map(({ expression }) => b.thunk(expression))), + b.array(async_expressions.map(({ expression }) => b.thunk(expression, true))), element.metadata.scoped && context.state.analysis.css.hash !== '' && b.literal(context.state.analysis.css.hash), @@ -182,7 +188,9 @@ export function build_set_class(element, node_id, attribute, class_directives, c if (class_directives.length) { next = build_class_directives_object(class_directives, context); - has_state ||= class_directives.some((d) => d.metadata.expression.has_state); + has_state ||= class_directives.some( + (d) => d.metadata.expression.has_state || d.metadata.expression.has_await + ); if (has_state) { previous_id = b.id(context.state.scope.generate('classes')); @@ -255,7 +263,9 @@ export function build_set_style(node_id, attribute, style_directives, context) { if (style_directives.length) { next = build_style_directives_object(style_directives, context); - has_state ||= style_directives.some((d) => d.metadata.expression.has_state); + has_state ||= style_directives.some( + (d) => d.metadata.expression.has_state || d.metadata.expression.has_await + ); if (has_state) { previous_id = b.id(context.state.scope.generate('styles')); diff --git a/packages/svelte/tests/runtime-runes/samples/async-class-directive/_config.js b/packages/svelte/tests/runtime-runes/samples/async-class-directive/_config.js new file mode 100644 index 0000000000..3186ed2069 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-class-directive/_config.js @@ -0,0 +1,20 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `loading`, + + async test({ assert, target }) { + await tick(); + + assert.htmlEqual( + target.innerHTML, + ` +