separate sync from async expressions

aaa
Rich Harris 8 months ago
parent 6ea6e2d724
commit 5ae974f47d

@ -175,6 +175,7 @@ export function client_component(analysis, options) {
init: /** @type {any} */ (null),
update: /** @type {any} */ (null),
expressions: /** @type {any} */ (null),
async_expressions: /** @type {any} */ (null),
after_update: /** @type {any} */ (null),
template: /** @type {any} */ (null),
locations: /** @type {any} */ (null)

@ -53,7 +53,9 @@ export interface ComponentClientTransformState extends ClientTransformState {
/** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */
readonly after_update: Statement[];
/** Expressions used inside the render effect */
readonly expressions: Array<{ id: Identifier; expression: Expression; is_async: boolean }>;
readonly expressions: Array<{ id: Identifier; expression: Expression }>;
/** Expressions used inside the render effect */
readonly async_expressions: Array<{ id: Identifier; expression: Expression }>;
/** The HTML template string */
readonly template: Array<string | Expression>;
readonly locations: SourceLocation[];
@ -113,3 +115,8 @@ export type ComponentVisitors = import('zimmerframe').Visitors<
AST.SvelteNode,
ComponentClientTransformState
>;
export interface MemoizedExpression {
id: Identifier;
expression: Expression;
}

@ -64,6 +64,7 @@ export function Fragment(node, context) {
init: [],
update: [],
expressions: [],
async_expressions: [],
after_update: [],
template: [],
locations: [],

@ -543,7 +543,7 @@ function build_element_attribute_update_assignment(
let { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(state, value, metadata.is_async)
? get_expression_id(metadata.is_async ? state.async_expressions : state.expressions, value)
: value
);
@ -673,7 +673,7 @@ function build_element_special_value_attribute(element, node_id, attribute, cont
const state = context.state;
const { value, has_state } = build_attribute_value(attribute.value, context, (value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(state, value, metadata.is_async)
? get_expression_id(metadata.is_async ? state.async_expressions : state.expressions, value)
: value
);

@ -48,6 +48,7 @@ export function SvelteElement(node, context) {
init: [],
update: [],
expressions: [],
async_expressions: [],
after_update: []
}
};

@ -40,7 +40,10 @@ export function build_set_attributes(
context,
(value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(context.state, value, metadata.is_async)
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
value
)
: value
);
@ -64,7 +67,12 @@ export function build_set_attributes(
let value = /** @type {Expression} */ (context.visit(attribute));
if (attribute.metadata.expression.has_call || attribute.metadata.expression.is_async) {
value = get_expression_id(context.state, value, attribute.metadata.expression.is_async);
value = get_expression_id(
attribute.metadata.expression.is_async
? context.state.async_expressions
: context.state.expressions,
value
);
}
values.push(b.spread(value));
@ -117,7 +125,10 @@ export function build_style_directives(
? build_getter({ name: directive.name, type: 'Identifier' }, context.state)
: build_attribute_value(directive.value, context, (value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(context.state, value, metadata.is_async)
? get_expression_id(
metadata.is_async ? context.state.async_expressions : context.state.expressions,
value
)
: value
).value;
@ -159,7 +170,7 @@ export function build_class_directives(
let value = /** @type {Expression} */ (context.visit(directive.expression));
if (has_call || is_async) {
value = get_expression_id(state, value, is_async);
value = get_expression_id(is_async ? state.async_expressions : state.expressions, value);
}
const update = b.stmt(b.call('$.toggle_class', element_id, b.literal(directive.name), value));

@ -1,6 +1,6 @@
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, SequenceExpression, Statement, Super } from 'estree' */
/** @import { Expression, ExpressionStatement, Identifier, MemberExpression, SequenceExpression, Super } from 'estree' */
/** @import { AST, ExpressionMetadata } from '#compiler' */
/** @import { ComponentClientTransformState } from '../../types' */
/** @import { ComponentClientTransformState, MemoizedExpression } from '../../types' */
import { walk } from 'zimmerframe';
import { object } from '../../../../../utils/ast.js';
import * as b from '../../../../../utils/builders.js';
@ -22,19 +22,18 @@ export function memoize_expression(state, value) {
/**
*
* @param {ComponentClientTransformState} state
* @param {MemoizedExpression[]} expressions
* @param {Expression} expression
* @param {boolean} is_async
*/
export function get_expression_id(state, expression, is_async) {
for (let i = 0; i < state.expressions.length; i += 1) {
if (compare_expressions(state.expressions[i].expression, expression)) {
return state.expressions[i].id;
export function get_expression_id(expressions, expression) {
for (let i = 0; i < expressions.length; i += 1) {
if (compare_expressions(expressions[i].expression, expression)) {
return expressions[i].id;
}
}
const id = b.id(''); // filled in later
state.expressions.push({ id, expression, is_async });
const id = b.id('~'); // filled in later
expressions.push({ id, expression });
return id;
}
@ -92,7 +91,7 @@ export function build_template_chunk(
state,
memoize = (value, metadata) =>
metadata.has_call || metadata.is_async
? get_expression_id(state, value, metadata.is_async)
? get_expression_id(metadata.is_async ? state.async_expressions : state.expressions, value)
: value
) {
/** @type {Expression[]} */
@ -163,8 +162,8 @@ export function build_template_chunk(
* @param {ComponentClientTransformState} state
*/
export function build_render_statement(state) {
const sync = state.expressions.filter(({ is_async }) => !is_async);
const async = state.expressions.filter(({ is_async }) => is_async);
const sync = state.expressions;
const async = state.async_expressions;
const all = [...sync, ...async];

Loading…
Cancel
Save