diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 5a480f0fe7..8507eccbf8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -532,17 +532,20 @@ function get_hoistable_params(node, context) { ); } + const expression = context.state.getters[reference] ?? binding.expression; + if ( // If it's a destructured derived binding, then we can extract the derived signal reference and use that. - binding.expression !== null && - typeof binding.expression !== 'function' && - binding.expression.type === 'MemberExpression' && - binding.expression.object.type === 'CallExpression' && - binding.expression.object.callee.type === 'Identifier' && - binding.expression.object.callee.name === '$.get' && - binding.expression.object.arguments[0].type === 'Identifier' + // TODO this code is bad, we need to kill it + expression != null && + typeof expression !== 'function' && + expression.type === 'MemberExpression' && + expression.object.type === 'CallExpression' && + expression.object.callee.type === 'Identifier' && + expression.object.callee.name === '$.get' && + expression.object.arguments[0].type === 'Identifier' ) { - push_unique(b.id(binding.expression.object.arguments[0].name)); + push_unique(b.id(expression.object.arguments[0].name)); } else if ( // If we are referencing a simple $$props value, then we need to reference the object property instead (binding.kind === 'prop' || binding.kind === 'bindable_prop') && diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index d470bc3b87..68f236d919 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -1355,7 +1355,7 @@ function process_children(nodes, expression, is_element, { visit, state }) { const text_id = get_node_id(expression(true), state, 'text'); const update = b.stmt( - b.call('$.set_text', text_id, /** @type {Expression} */ (visit(node.expression))) + b.call('$.set_text', text_id, /** @type {Expression} */ (visit(node.expression, state))) ); if (node.metadata.contains_call_expression && !within_bound_contenteditable) { @@ -1615,6 +1615,7 @@ export const template_visitors = { after_update: [], template: [], locations: [], + getters: { ...context.state.getters }, metadata: { context: { template_needs_import_node: false, @@ -1777,6 +1778,8 @@ export const template_visitors = { ) ); + state.getters[declaration.id.name] = b.call('$.get', declaration.id); + // we need to eagerly evaluate the expression in order to hit any // 'Cannot access x before initialization' errors if (state.options.dev) { @@ -1818,8 +1821,7 @@ export const template_visitors = { } for (const node of identifiers) { - const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(node.name)); - binding.expression = b.member(b.call('$.get', tmp), node); + state.getters[node.name] = b.member(b.call('$.get', tmp), node); } } },