From 27cfdde137c3bb44e9a5a3d30c9839d89ab084ad Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Sun, 7 Jan 2024 09:01:49 -0800 Subject: [PATCH] handle context=module variables --- .../phases/3-transform/client/utils.js | 26 +++++++++---------- .../_expected/client/index.svelte.js | 13 ++++++---- .../_expected/server/index.svelte.js | 5 ++-- .../samples/hoist-unmodified-var/index.svelte | 3 +++ 4 files changed, 27 insertions(+), 20 deletions(-) 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 86aa472dcd..a3450bdb26 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -543,12 +543,22 @@ export function should_proxy_or_freeze(node) { * @returns {boolean} */ export function can_inline_variable(binding, name) { + return can_hoist_declaration(binding, name) || (!!binding && !binding.scope.has_parent()); +} + +/** + * @param {import('#compiler').Binding | undefined} binding + * @param {string} name + * @returns {boolean} + */ +export function can_hoist_declaration(binding, name) { return ( !!binding && binding.kind === 'normal' && binding.scope.is_top_level && - // TODO: allow object expressions that are not passed to functions or components as props - // and expressions as long as they do not reference non-hoistable variables + // For now we just allow primitives for simplicity. We could allow object expressions that are + // not passed to functions or components as props and expressions as long as they do not + // reference functions, constructors, non-hoistable variables, etc. binding.initial?.type === 'Literal' && // Checking that it's not mutated or reassigned is a bit simplistic // If it's not state and thus not reactive, we could hoist the variable and mutation @@ -558,16 +568,6 @@ export function can_inline_variable(binding, name) { // Avoid conflicts. It would be nice to rename the variable, but keeping it simple for now !binding.scope.declared_in_outer_scope(name) && !GlobalBindings.has(name) - ); -} - -/** - * @param {import('#compiler').Binding | undefined} binding - * @param {string} name - * @returns {boolean} - */ -export function can_hoist_declaration(binding, name) { - return ( - can_inline_variable(binding, name) && !!binding && binding.scope.has_parent() // i.e. not when context="module" + && binding.scope.has_parent() // i.e. not when context="module" ); } diff --git a/packages/svelte/tests/snapshot/samples/hoist-unmodified-var/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/hoist-unmodified-var/_expected/client/index.svelte.js index 46e589c5c9..16368c4715 100644 --- a/packages/svelte/tests/snapshot/samples/hoist-unmodified-var/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/hoist-unmodified-var/_expected/client/index.svelte.js @@ -4,11 +4,12 @@ import "svelte/internal/disclose-version"; const o = 'o'; const d = 'd'; +const url = new URL('foobar.png', 'https://www.example.com/').href; import * as $ from "svelte/internal"; const boolean = false; -var frag = $.template(`
boolean is ${$.stringify(boolean)} and autocapitalize is w${$.stringify(o)}r${$.stringify(d)}s
`); +var frag = $.template(`boolean is ${$.stringify(boolean)} and autocapitalize is w${$.stringify(o)}r${$.stringify(d)}s
boolean is ${$.escape(boolean)} and autocapitalize is w${$.escape(o)}r${$.escape(d)}s
`; + $$payload.out += `boolean is ${$.escape(boolean)} and autocapitalize is w${$.escape(o)}r${$.escape(d)}s
boolean is {boolean} and autocapitalize is w{o}r{d}s
+ +