From f85aff43c8ca9d2d6bba9040870ccc8c2234853f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 27 Oct 2025 19:05:55 +0100 Subject: [PATCH] WIP --- .../2-analyze/visitors/BindDirective.js | 1 + .../client/visitors/BindDirective.js | 25 +++++++++++++------ .../svelte/src/compiler/types/template.d.ts | 1 + 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js index 995d251a2e..38eab5d36e 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/BindDirective.js @@ -172,6 +172,7 @@ export function BindDirective(node, context) { } const binding = context.state.scope.get(left.name); + node.metadata.binding = binding; if (assignee.type === 'Identifier') { // reassignment diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js index 506fd4aafd..9a264facce 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/BindDirective.js @@ -243,18 +243,29 @@ export function BindDirective(node, context) { } } + const defer = + node.name !== 'this' && + parent.type === 'RegularElement' && + parent.attributes.find((a) => a.type === 'UseDirective'); + + let statement = defer ? b.stmt(b.call('$.effect', b.thunk(call))) : b.stmt(call); + + // TODO this doesn't account for function bindings + if (node.metadata.binding?.blocker) { + statement = b.stmt( + b.call(b.member(node.metadata.binding.blocker, b.id('then')), b.thunk(b.block([statement]))) + ); + } + // Bindings need to happen after attribute updates, therefore after the render effect, and in order with events/actions. // bind:this is a special case as it's one-way and could influence the render effect. if (node.name === 'this') { - context.state.init.push(b.stmt(call)); + context.state.init.push(statement); } else { - const has_use = - parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective'); - - if (has_use) { - context.state.init.push(b.stmt(b.call('$.effect', b.thunk(call)))); + if (defer) { + context.state.init.push(statement); } else { - context.state.after_update.push(b.stmt(call)); + context.state.after_update.push(statement); } } } diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index 5c7f8cdb13..9cf498d187 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -207,6 +207,7 @@ export namespace AST { expression: Identifier | MemberExpression | SequenceExpression; /** @internal */ metadata: { + binding?: Binding | null; binding_group_name: Identifier; parent_each_blocks: EachBlock[]; };