pull/15844/head
Rich Harris 2 months ago
parent 2b4410007d
commit 25855163bf

@ -3,7 +3,6 @@
/** @import { ComponentContext } from '../types' */
import { unwrap_optional } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
import { create_derived } from '../utils.js';
import { build_expression, Memoizer } from './shared/utils.js';
/**
@ -36,9 +35,7 @@ export function RenderTag(node, context) {
memoizer.apply();
/** @type {Statement[]} */
const statements = memoizer.sync.map((memo) =>
b.var(memo.id, create_derived(context.state, b.thunk(memo.expression)))
);
const statements = memoizer.deriveds();
let snippet_function = build_expression(
context,
@ -67,17 +64,16 @@ export function RenderTag(node, context) {
);
}
if (memoizer.async.length > 0) {
const async_values = memoizer.async_values();
if (async_values) {
context.state.init.push(
b.stmt(
b.call(
'$.async',
context.state.node,
b.array(memoizer.async.map((memo) => b.thunk(memo.expression, true))),
b.arrow(
[context.state.node, ...memoizer.async.map((memo) => memo.id)],
b.block(statements)
)
async_values,
b.arrow([context.state.node, ...memoizer.async_ids()], b.block(statements))
)
)
);

@ -2,7 +2,6 @@
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import * as b from '#compiler/builders';
import { create_derived } from '../utils.js';
import { build_attribute_value } from './shared/element.js';
import { Memoizer } from './shared/utils.js';
@ -60,9 +59,7 @@ export function SlotElement(node, context) {
context.state.init.push(...lets);
/** @type {Statement[]} */
const statements = memoizer.sync.map((memo) =>
b.var(memo.id, create_derived(context.state, b.thunk(memo.expression)))
);
const statements = memoizer.deriveds();
const props_expression =
spreads.length === 0 ? b.object(props) : b.call('$.spread_props', b.object(props), ...spreads);
@ -76,17 +73,16 @@ export function SlotElement(node, context) {
b.stmt(b.call('$.slot', context.state.node, b.id('$$props'), name, props_expression, fallback))
);
if (memoizer.async.length > 0) {
const async_values = memoizer.async_values();
if (async_values) {
context.state.init.push(
b.stmt(
b.call(
'$.async',
context.state.node,
b.array(memoizer.async.map((memo) => b.thunk(memo.expression, true))),
b.arrow(
[context.state.node, ...memoizer.async.map((memo) => memo.id)],
b.block(statements)
)
async_values,
b.arrow([context.state.node, ...memoizer.async_ids()], b.block(statements))
)
)
);

@ -8,7 +8,6 @@ import { build_bind_this, Memoizer, validate_binding } from '../shared/utils.js'
import { build_attribute_value } from '../shared/element.js';
import { build_event_handler } from './events.js';
import { determine_slot } from '../../../../../utils/slot.js';
import { create_derived } from '../../utils.js';
/**
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
@ -447,12 +446,7 @@ export function build_component(node, component_name, context) {
};
}
const statements = [
...snippet_declarations,
...memoizer.sync.map((memo) =>
b.let(memo.id, create_derived(context.state, b.thunk(memo.expression)))
)
];
const statements = [...snippet_declarations, ...memoizer.deriveds()];
if (is_component_dynamic) {
const prev = fn;
@ -501,13 +495,15 @@ export function build_component(node, component_name, context) {
memoizer.apply();
if (memoizer.async.length > 0) {
const async_values = memoizer.async_values();
if (async_values) {
return b.stmt(
b.call(
'$.async',
anchor,
b.array(memoizer.async.map(({ expression }) => b.thunk(expression, true))),
b.arrow([b.id('$$anchor'), ...memoizer.async.map(({ id }) => id)], b.block(statements))
async_values,
b.arrow([b.id('$$anchor'), ...memoizer.async_ids()], b.block(statements))
)
);
}

@ -78,21 +78,16 @@ export function build_attribute_effect(
);
}
const all = memoizer.apply();
memoizer.apply();
context.state.init.push(
b.stmt(
b.call(
'$.attribute_effect',
element_id,
b.arrow(
all.map(({ id }) => id),
b.object(values)
),
memoizer.sync.length > 0 &&
b.array(memoizer.sync.map(({ expression }) => b.thunk(expression))),
memoizer.async.length > 0 &&
b.array(memoizer.async.map(({ expression }) => b.thunk(expression, true))),
b.arrow(memoizer.all_ids(), b.object(values)),
memoizer.sync_values(),
memoizer.async_values(),
element.metadata.scoped &&
context.state.analysis.css.hash !== '' &&
b.literal(context.state.analysis.css.hash),

@ -12,10 +12,10 @@ import { build_getter } from '../../utils.js';
export class Memoizer {
/** @type {Array<{ id: Identifier, expression: Expression }>} */
sync = [];
#sync = [];
/** @type {Array<{ id: Identifier, expression: Expression }>} */
async = [];
#async = [];
/**
* @param {Expression} expression
@ -24,19 +24,39 @@ export class Memoizer {
add(expression, has_await) {
const id = b.id(`#`); // filled in later
(has_await ? this.async : this.sync).push({ id, expression });
(has_await ? this.#async : this.#sync).push({ id, expression });
return id;
}
apply() {
const all = [...this.async, ...this.sync];
all.forEach((memo, i) => {
[...this.#async, ...this.#sync].forEach((memo, i) => {
memo.id.name = `$${i}`;
});
}
all_ids() {
return [...this.#async, ...this.#sync].map((memo) => memo.id);
}
async_ids() {
return this.#async.map((memo) => memo.id);
}
async_values() {
if (this.#async.length === 0) return;
return b.array(this.#async.map((memo) => b.thunk(memo.expression, true)));
}
deriveds(runes = true) {
return this.#sync.map((memo) =>
b.let(memo.id, b.call(runes ? '$.derived' : '$.derived_safe_equal', b.thunk(memo.expression)))
);
}
return all;
sync_values() {
if (this.#sync.length === 0) return;
return b.array(this.#sync.map((memo) => b.thunk(memo.expression)));
}
}
@ -143,20 +163,19 @@ export function build_template_chunk(
export function build_render_statement(state) {
const { memoizer } = state;
const all = state.memoizer.apply();
state.memoizer.apply();
return b.stmt(
b.call(
'$.template_effect',
b.arrow(
all.map(({ id }) => id),
memoizer.all_ids(),
state.update.length === 1 && state.update[0].type === 'ExpressionStatement'
? state.update[0].expression
: b.block(state.update)
),
all.length > 0 && b.array(memoizer.sync.map(({ expression }) => b.thunk(expression))),
memoizer.async.length > 0 &&
b.array(memoizer.async.map(({ expression }) => b.thunk(expression, true)))
memoizer.sync_values(),
memoizer.async_values()
)
);
}

Loading…
Cancel
Save