gah i give up for now. need sleep

pull/10960/head
Rich Harris 8 months ago
parent 6368b5da6a
commit 217210cca8

@ -206,16 +206,93 @@ export function client_component(source, analysis, options) {
} }
} }
for (const [node] of analysis.reactive_statements) { const legacy_reactive_statements = Array.from(analysis.reactive_statements.keys()).map(
const statement = [...state.legacy_reactive_statements].find(([n]) => n === node); (node) =>
if (statement === undefined) { /** @type {import('./types').LegacyReactiveStatement} */ (
error(node, 'INTERNAL', 'Could not find reactive statement'); state.legacy_reactive_statements.get(node)
)
);
/** @type {import('#compiler').Binding[]} */
const dependencies = [];
for (const statement of legacy_reactive_statements) {
if (statement.dependencies.length === 0) {
instance.body.push(statement.body);
} else {
for (const dep of statement.dependencies) {
if (!dependencies.includes(dep)) {
dependencies.push(dep);
} }
instance.body.push(statement[1]); }
}
}
if (dependencies.length > 0) {
instance.body.push(b.var('$$deps', b.array(dependencies.map((dep) => b.literal(-1)))));
/** @type {import('estree').Statement[]} */
const body = [
b.stmt(
b.sequence(
dependencies.map((binding) =>
binding.kind === 'bindable_prop' || binding.kind === 'rest_prop'
? b.call(
'$.deep_read_state',
serialize_get_binding(b.id(binding.node.name), instance_state)
)
: serialize_get_binding(b.id(binding.node.name), instance_state)
)
)
)
];
const versions = dependencies.map((binding) => {
if (
binding.kind === 'state' ||
binding.kind === 'frozen_state' ||
binding.kind === 'derived'
) {
return b.member(binding.node, b.id('version'));
}
return b.call(
'$.get_version',
b.thunk(serialize_get_binding(b.id(binding.node.name), instance_state))
);
});
for (const statement of legacy_reactive_statements) {
const { dependencies } = statement;
if (dependencies.length === 0) continue;
let condition = null;
for (const binding of dependencies) {
const index = dependencies.indexOf(binding);
const version = versions[index];
const comparison = b.binary(
'!==',
version,
b.member(b.id('$$deps'), b.literal(index), true)
);
condition = condition ? b.logical('||', condition, comparison) : comparison;
}
body.push(
b.if(/** @type {import('estree').Expression} */ (condition), b.block([statement.body]))
);
}
for (let i = 0; i < dependencies.length; i += 1) {
body.push(
b.stmt(b.assignment('=', b.member(b.id('$$deps'), b.literal(i), true), versions[i]))
);
} }
if (analysis.reactive_statements.size > 0) { instance.body.push(b.stmt(b.call('$.render_effect', b.thunk(b.block(body)))));
instance.body.push(b.stmt(b.call('$.legacy_pre_effect_reset')));
} }
/** /**

@ -5,10 +5,15 @@ import type {
Identifier, Identifier,
PrivateIdentifier PrivateIdentifier
} from 'estree'; } from 'estree';
import type { Namespace, SvelteNode, ValidatedCompileOptions } from '#compiler'; import type { Binding, Namespace, SvelteNode, ValidatedCompileOptions } from '#compiler';
import type { TransformState } from '../types.js'; import type { TransformState } from '../types.js';
import type { ComponentAnalysis } from '../../types.js'; import type { ComponentAnalysis } from '../../types.js';
export interface LegacyReactiveStatement {
dependencies: Binding[];
body: Statement;
}
export interface ClientTransformState extends TransformState { export interface ClientTransformState extends TransformState {
readonly private_state: Map<string, StateField>; readonly private_state: Map<string, StateField>;
readonly public_state: Map<string, StateField>; readonly public_state: Map<string, StateField>;
@ -20,7 +25,7 @@ export interface ClientTransformState extends TransformState {
readonly in_constructor: boolean; readonly in_constructor: boolean;
/** The $: calls, which will be ordered in the end */ /** The $: calls, which will be ordered in the end */
readonly legacy_reactive_statements: Map<LabeledStatement, Statement>; readonly legacy_reactive_statements: Map<LabeledStatement, LegacyReactiveStatement>;
} }
export interface ComponentClientTransformState extends ClientTransformState { export interface ComponentClientTransformState extends ClientTransformState {

@ -148,44 +148,19 @@ export const javascript_visitors_legacy = {
if (!reactive_stmt) return; // not the instance context if (!reactive_stmt) return; // not the instance context
const { dependencies } = reactive_stmt; /** @type {import('#compiler').Binding[]} */
const dependencies = [];
let serialized_body = /** @type {import('estree').Statement} */ (context.visit(node.body)); for (const dependency of reactive_stmt.dependencies) {
if (dependency.kind !== 'normal') {
if (serialized_body.type !== 'BlockStatement') { dependencies.push(dependency);
serialized_body = b.block([serialized_body]);
} }
const body = serialized_body.body;
/** @type {import('estree').Expression[]} */
const sequence = [];
for (const binding of dependencies) {
if (binding.kind === 'normal') continue;
const name = binding.node.name;
let serialized = serialize_get_binding(b.id(name), state);
// If the binding is a prop, we need to deep read it because it could be fine-grained $state
// from a runes-component, where mutations don't trigger an update on the prop as a whole.
if (name === '$$props' || name === '$$restProps' || binding.kind === 'bindable_prop') {
serialized = b.call('$.deep_read_state', serialized);
}
sequence.push(serialized);
} }
// these statements will be topologically ordered later // these statements will be topologically ordered later
state.legacy_reactive_statements.set( state.legacy_reactive_statements.set(node, {
node, dependencies,
b.stmt( body: /** @type {import('estree').Statement} */ (context.visit(node.body))
b.call( });
'$.legacy_pre_effect',
sequence.length > 0 ? b.thunk(b.sequence(sequence)) : b.thunk(b.block([])),
b.thunk(b.block(body))
)
)
);
return b.empty; return b.empty;
}, },

@ -135,7 +135,7 @@ var uses_version_sum = false;
export function get_version(fn) { export function get_version(fn) {
version_sum = 0; version_sum = 0;
uses_version_sum = true; uses_version_sum = true;
fn(); deep_read_state(untrack(fn));
return version_sum; return version_sum;
} }
@ -1177,6 +1177,7 @@ export function deep_read(value, visited = new Set()) {
proto !== Date.prototype proto !== Date.prototype
) { ) {
const descriptors = get_descriptors(proto); const descriptors = get_descriptors(proto);
for (let key in descriptors) { for (let key in descriptors) {
const get = descriptors[key].get; const get = descriptors[key].get;
if (get) { if (get) {

@ -1,6 +1,6 @@
export { export {
get, get,
get_version_sum, get_version,
invalidate_inner_signals, invalidate_inner_signals,
flushSync, flushSync,
tick, tick,

Loading…
Cancel
Save