diff --git a/.changeset/angry-plums-punch.md b/.changeset/angry-plums-punch.md new file mode 100644 index 0000000000..22af9d313b --- /dev/null +++ b/.changeset/angry-plums-punch.md @@ -0,0 +1,5 @@ +--- +"svelte": patch +--- + +chore: improve should_proxy_or_freeze logic internally 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 c5ff3866d1..49ca618ada 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -293,7 +293,7 @@ export function serialize_set_binding(node, context, fallback, options) { if ( context.state.analysis.runes && !options?.skip_proxy_and_freeze && - should_proxy_or_freeze(value) + should_proxy_or_freeze(value, context.state.scope) ) { const assignment = fallback(); if (assignment.type === 'AssignmentExpression') { @@ -310,7 +310,7 @@ export function serialize_set_binding(node, context, fallback, options) { left, context.state.analysis.runes && !options?.skip_proxy_and_freeze && - should_proxy_or_freeze(value) + should_proxy_or_freeze(value, context.state.scope) ? private_state.kind === 'frozen_state' ? b.call('$.freeze', value) : b.call('$.proxy', value) @@ -330,7 +330,7 @@ export function serialize_set_binding(node, context, fallback, options) { context.state.analysis.runes && public_state !== undefined && !options?.skip_proxy_and_freeze && - should_proxy_or_freeze(value) + should_proxy_or_freeze(value, context.state.scope) ) { const assignment = fallback(); if (assignment.type === 'AssignmentExpression') { @@ -398,7 +398,7 @@ export function serialize_set_binding(node, context, fallback, options) { b.id(left_name), context.state.analysis.runes && !options?.skip_proxy_and_freeze && - should_proxy_or_freeze(value) + should_proxy_or_freeze(value, context.state.scope) ? b.call('$.proxy', value) : value ); @@ -408,7 +408,7 @@ export function serialize_set_binding(node, context, fallback, options) { b.id(left_name), context.state.analysis.runes && !options?.skip_proxy_and_freeze && - should_proxy_or_freeze(value) + should_proxy_or_freeze(value, context.state.scope) ? b.call('$.freeze', value) : value ); @@ -623,8 +623,11 @@ export function get_prop_source(binding, state, name, initial) { return b.call('$.prop', ...args); } -/** @param {import('estree').Expression} node */ -export function should_proxy_or_freeze(node) { +/** + * @param {import('estree').Expression} node + * @param {import("../../scope.js").Scope | null} scope + */ +export function should_proxy_or_freeze(node, scope) { if ( !node || node.type === 'Literal' || @@ -637,5 +640,20 @@ export function should_proxy_or_freeze(node) { ) { return false; } + if (node.type === 'Identifier' && scope !== null) { + const binding = scope.get(node.name); + // Let's see if the reference is something that can be proxied or frozen + if ( + binding !== null && + !binding.reassigned && + binding.initial !== null && + binding.initial.type !== 'FunctionDeclaration' && + binding.initial.type !== 'ClassDeclaration' && + binding.initial.type !== 'ImportDeclaration' && + binding.initial.type !== 'EachBlock' + ) { + return should_proxy_or_freeze(binding.initial, null); + } + } return true; } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js index 0150c30293..f4fc46ce81 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js @@ -85,11 +85,14 @@ export const javascript_visitors_runes = { value = field.kind === 'state' - ? b.call('$.source', should_proxy_or_freeze(init) ? b.call('$.proxy', init) : init) + ? b.call( + '$.source', + should_proxy_or_freeze(init, state.scope) ? b.call('$.proxy', init) : init + ) : field.kind === 'frozen_state' ? b.call( '$.source', - should_proxy_or_freeze(init) ? b.call('$.freeze', init) : init + should_proxy_or_freeze(init, state.scope) ? b.call('$.freeze', init) : init ) : b.call('$.derived', b.thunk(init)); } else { @@ -238,7 +241,7 @@ export const javascript_visitors_runes = { */ const create_state_declarator = (id, value) => { const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name)); - if (should_proxy_or_freeze(value)) { + if (should_proxy_or_freeze(value, state.scope)) { value = b.call(rune === '$state' ? '$.proxy' : '$.freeze', value); } if (is_state_source(binding, state)) {