From ea90084a05ea5983e7cafb2091342099a262782a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 17 Feb 2024 12:07:56 -0500 Subject: [PATCH 1/3] make store subscriptions treeshakeable on the server --- .../3-transform/server/transform-server.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index e6fc43a26999..0c5c4d1fc433 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -322,7 +322,7 @@ function serialize_get_binding(node, state) { const store_id = b.id(node.name.slice(1)); return b.call( state.options.dev ? '$.store_get_dev' : '$.store_get', - b.id('$$store_subs'), + b.assignment('??=', b.id('$$store_subs'), b.object([])), b.literal(node.name), serialize_get_binding(store_id, state) ); @@ -460,7 +460,7 @@ function serialize_set_binding(node, context, fallback) { } else if (is_store) { return b.call( '$.mutate_store', - b.id('$$store_subs'), + b.assignment('??=', b.id('$$store_subs'), b.object([])), b.literal(left.name), b.id(left_name), b.assignment(node.operator, /** @type {import('estree').Pattern} */ (visit(node.left)), value) @@ -506,7 +506,11 @@ const global_visitors = { if (node.prefix) fn += '_pre'; /** @type {import('estree').Expression[]} */ - const args = [b.id('$$store_subs'), b.literal(argument.name), b.id(argument.name.slice(1))]; + const args = [ + b.assignment('??=', b.id('$$store_subs'), b.object([])), + b.literal(argument.name), + b.id(argument.name.slice(1)) + ]; if (node.operator === '--') { args.push(b.literal(-1)); } @@ -2094,8 +2098,10 @@ export function server_component(analysis, options) { (binding) => binding.kind === 'store_sub' ) ) { - instance.body.unshift(b.const('$$store_subs', b.object([]))); - template.body.push(b.stmt(b.call('$.unsubscribe_stores', b.id('$$store_subs')))); + instance.body.unshift(b.var('$$store_subs')); + template.body.push( + b.if(b.id('$$store_subs'), b.stmt(b.call('$.unsubscribe_stores', b.id('$$store_subs')))) + ); } // Propagate values of bound props upwards if they're undefined in the parent and have a value. // Don't do this as part of the props retrieval because people could eagerly mutate the prop in the instance script. From b4cc2b28b3578b67541c0b630938428bd6579aaf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 17 Feb 2024 14:09:50 -0500 Subject: [PATCH 2/3] drive-by fix --- .../3-transform/server/transform-server.js | 2 +- packages/svelte/src/internal/server/index.js | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 0c5c4d1fc433..5640a1f372a9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -321,7 +321,7 @@ function serialize_get_binding(node, state) { if (binding.kind === 'store_sub') { const store_id = b.id(node.name.slice(1)); return b.call( - state.options.dev ? '$.store_get_dev' : '$.store_get', + '$.store_get', b.assignment('??=', b.id('$$store_subs'), b.object([])), b.literal(node.name), serialize_get_binding(store_id, state) diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index f873bc4aa5ce..0f9d78afeb52 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -2,6 +2,7 @@ import * as $ from '../client/runtime.js'; import { is_promise, noop } from '../common.js'; import { subscribe_to_store } from '../../store/utils.js'; import { DOMBooleanAttributes } from '../../constants.js'; +import { DEV } from 'esm-env'; export * from '../client/validate.js'; @@ -340,6 +341,10 @@ export function merge_styles(style_attribute, style_directive) { * @returns {V} */ export function store_get(store_values, store_name, store) { + if (DEV) { + validate_store(store, store_name.slice(1)); + } + // it could be that someone eagerly updates the store in the instance script, so // we should only reuse the store value in the template if (store_name in store_values && store_values[store_name][0] === store) { @@ -356,18 +361,6 @@ export function store_get(store_values, store_name, store) { return store_values[store_name][2]; } -/** - * @template V - * @param {Record} store_values - * @param {string} store_name - * @param {import('../client/types.js').Store | null | undefined} store - * @returns {V} - */ -export function store_get_dev(store_values, store_name, store) { - validate_store(store, store_name.slice(1)); - return store_get(store_values, store_name, store); -} - /** * @param {any} store * @param {string} name From 697221cad4e768fa083338423e794e08c8dc9b7c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 17 Feb 2024 14:10:47 -0500 Subject: [PATCH 3/3] changeset --- .changeset/brown-months-fry.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/brown-months-fry.md diff --git a/.changeset/brown-months-fry.md b/.changeset/brown-months-fry.md new file mode 100644 index 000000000000..a95410d97668 --- /dev/null +++ b/.changeset/brown-months-fry.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: treeshake unused store subscriptions in SSR mode