fix async directives

pull/15844/head
Rich Harris 3 months ago
parent 7144f11b5b
commit d7a99b6548

@ -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;
}
/**

@ -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'));

@ -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,
`
<div class="one">one</div>
<div class="two">two</div>
<div style="color: red;">red</div>
<div style="color: blue;">blue</div>
`
);
}
});

@ -0,0 +1,11 @@
<svelte:boundary>
<div class:one={await true} {...{}}>one</div>
<div class:two={await true}>two</div>
<div style:color={await 'red'} {...{}}>red</div>
<div style:color={await 'blue'}>blue</div>
{#snippet pending()}
loading
{/snippet}
</svelte:boundary>
Loading…
Cancel
Save