From f91ccc6b0ac98c50851f6343f31afa6dcac257ee Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 26 Oct 2025 08:07:47 -0400 Subject: [PATCH] WIP --- .../3-transform/client/visitors/Program.js | 17 +++++++++++++---- .../3-transform/server/visitors/Program.js | 17 +++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js index bd07e4bd07..fdda4c9b2e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js @@ -252,6 +252,8 @@ function transform_body(program, context) { } } + var promises = b.id('$$promises'); // TODO if we use this technique for fragments, need to deconflict + if (statements.length > 0) { var declarations = statements.map((s) => s.declarations).flat(); @@ -322,14 +324,12 @@ function transform_body(program, context) { return b.thunk(b.block([/** @type {Statement} */ (context.visit(s.node))]), s.has_await); }); - var id = b.id('$$promises'); // TODO if we use this technique for fragments, need to deconflict - - out.push(b.var(id, b.call('$.run', b.array(thunks)))); + out.push(b.var(promises, b.call('$.run', b.array(thunks)))); for (let i = 0; i < statements.length; i += 1) { const s = statements[i]; - var blocker = b.member(id, b.literal(i), true); + var blocker = b.member(promises, b.literal(i), true); for (const binding of s.declarations) { binding.blocker = blocker; @@ -341,6 +341,15 @@ function transform_body(program, context) { // a synchronous `{obj.foo}` will fail } + for (const binding of context.state.scope.declarations.values()) { + // if the binding is updated (TODO or passed to a function, in which case it + // could be mutated), play it safe and block until the end. In future we + // could develop more sophisticated static analysis to optimise further + if (binding.updated) { + binding.blocker = b.member(promises, b.literal(statements.length - 1), true); + } + } + // console.log('statements', statements); // console.log('deriveds', deriveds); diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/Program.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/Program.js index 5f3fa33394..7bbe40db4f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/Program.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/Program.js @@ -122,6 +122,8 @@ function transform_body(program, context) { } } + var promises = b.id('$$promises'); // TODO if we use this technique for fragments, need to deconflict + if (statements.length > 0) { var declarations = statements.map((s) => s.declarations).flat(); @@ -192,14 +194,12 @@ function transform_body(program, context) { return b.thunk(b.block([/** @type {Statement} */ (context.visit(s.node))]), s.has_await); }); - var id = b.id('$$promises'); // TODO if we use this technique for fragments, need to deconflict - - out.push(b.var(id, b.call('$$renderer.run', b.array(thunks)))); + out.push(b.var(promises, b.call('$$renderer.run', b.array(thunks)))); for (let i = 0; i < statements.length; i += 1) { const s = statements[i]; - var blocker = b.member(id, b.literal(i), true); + var blocker = b.member(promises, b.literal(i), true); for (const binding of s.declarations) { binding.blocker = blocker; @@ -211,6 +211,15 @@ function transform_body(program, context) { // a synchronous `{obj.foo}` will fail } + for (const binding of context.state.scope.declarations.values()) { + // if the binding is updated (TODO or passed to a function, in which case it + // could be mutated), play it safe and block until the end. In future we + // could develop more sophisticated static analysis to optimise further + if (binding.updated) { + binding.blocker = b.member(promises, b.literal(statements.length - 1), true); + } + } + // console.log('statements', statements); // console.log('deriveds', deriveds);