From 9843803b3ee1e0cf641620a00b5f8ab7faa636f7 Mon Sep 17 00:00:00 2001 From: dominikg Date: Thu, 28 Aug 2025 12:01:45 +0200 Subject: [PATCH 1/4] feat(rolldown-vite): enable optimization.inlineConst by default --- .changeset/all-colts-dig.md | 5 +++ .../src/plugins/configure.js | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 .changeset/all-colts-dig.md diff --git a/.changeset/all-colts-dig.md b/.changeset/all-colts-dig.md new file mode 100644 index 000000000..8ce9d9b74 --- /dev/null +++ b/.changeset/all-colts-dig.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/vite-plugin-svelte': minor +--- + +feat(rolldown-vite): enable `optimization.inlineConst` by default to ensure treeshaking works with esm-env in svelte diff --git a/packages/vite-plugin-svelte/src/plugins/configure.js b/packages/vite-plugin-svelte/src/plugins/configure.js index b5538b06a..df00d2841 100644 --- a/packages/vite-plugin-svelte/src/plugins/configure.js +++ b/packages/vite-plugin-svelte/src/plugins/configure.js @@ -58,7 +58,38 @@ export function configure(api, inlineOptions) { preOptions = await preResolveOptions(inlineOptions, config, configEnv); // extra vite config const extraViteConfig = await buildExtraViteConfig(preOptions, config); + + if (rolldownVersion && configEnv.command === 'build') { + const [major, minor, patch, tag] = rolldownVersion + .replace(/[^\d.]/g, '') + .split('.') + .map(Number); + if (major > 1 || (major === 1 && (minor > 0 || patch > 0 || tag > 34))) { + extraViteConfig.build ??= {}; + // rename rollupOptions to rolldownOptions + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions = extraViteConfig.build.rollupOptions || {}; + delete extraViteConfig.build.rollupOptions; + + // set inlineConst + // TODO is `inlineConst: "safe"` safe to use with esm-env (we have to ensure it is always inlined) + if ( + //@ts-ignore optimization only exists in rolldown-vite + config.build?.rollupOptions?.optimization?.inlineConst == null && + //@ts-ignore rolldownOptions only exists in rolldown-vite + config.build?.rolldownOptions?.optimization?.inlineConst == null + ) { + // set inlineConst build optimization for esm-env + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions.optimization ??= {}; + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions.optimization.inlineConst = true; + } + } + } + log.debug('additional vite config', extraViteConfig, 'config'); + return extraViteConfig; } }, From 22a04bc73adeed5d226872089c9b2ec12c244cdd Mon Sep 17 00:00:00 2001 From: dominikg Date: Mon, 8 Sep 2025 16:07:36 +0200 Subject: [PATCH 2/4] add warning log if inlineConst is disabled --- .../src/plugins/configure.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/vite-plugin-svelte/src/plugins/configure.js b/packages/vite-plugin-svelte/src/plugins/configure.js index df00d2841..e4c4de3e1 100644 --- a/packages/vite-plugin-svelte/src/plugins/configure.js +++ b/packages/vite-plugin-svelte/src/plugins/configure.js @@ -70,20 +70,23 @@ export function configure(api, inlineOptions) { //@ts-ignore rolldownOptions only exists in rolldown-vite extraViteConfig.build.rolldownOptions = extraViteConfig.build.rollupOptions || {}; delete extraViteConfig.build.rollupOptions; - - // set inlineConst - // TODO is `inlineConst: "safe"` safe to use with esm-env (we have to ensure it is always inlined) - if ( + // read user config inlineConst value + const inlineConst = //@ts-ignore optimization only exists in rolldown-vite - config.build?.rollupOptions?.optimization?.inlineConst == null && - //@ts-ignore rolldownOptions only exists in rolldown-vite - config.build?.rolldownOptions?.optimization?.inlineConst == null - ) { + config.build?.rolldownOptions?.optimization?.inlineConst ?? + //@ts-ignore optimization only exists in rolldown-vite + config.build?.rollupOptions?.optimization?.inlineConst; + + if (inlineConst == null) { // set inlineConst build optimization for esm-env //@ts-ignore rolldownOptions only exists in rolldown-vite extraViteConfig.build.rolldownOptions.optimization ??= {}; //@ts-ignore rolldownOptions only exists in rolldown-vite extraViteConfig.build.rolldownOptions.optimization.inlineConst = true; + } else if (inlineConst === false) { + log.warn( + 'Your rolldown config contains `optimization.inlineConst: false`. This can lead to increased bundle size and leaked server code in client build.' + ); } } } From 822e3585c76b628997c510bc5cb106dc1d13e43a Mon Sep 17 00:00:00 2001 From: dominikg Date: Tue, 9 Sep 2025 15:09:37 +0200 Subject: [PATCH 3/4] refactor: reuse semver comparator and document why we only apply inlineConst after 1.0.0-beta.35 --- .../__tests__/svelte-version.spec.js | 8 ++- .../src/plugins/configure.js | 55 +++++++++---------- .../src/utils/svelte-version.js | 18 +++++- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js b/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js index 29a3d094e..94ce1145e 100644 --- a/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js +++ b/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js @@ -2,6 +2,9 @@ import { describe, it, expect } from 'vitest'; import { gte } from '../src/utils/svelte-version.js'; describe('gte', () => { + it('returns false for smaller tag', () => { + expect(gte('1.2.3-next.1', '1.2.3-next.2')).toBe(false); + }); it('returns false for smaller patch', () => { expect(gte('1.2.2', '1.2.3')).toBe(false); }); @@ -12,7 +15,10 @@ describe('gte', () => { expect(gte('0.3.4', '1.2.3')).toBe(false); }); it('returns true for equal', () => { - expect(gte('1.2.3', '1.2.3')).toBe(true); + expect(gte('1.2.3-next.1', '1.2.3-next.1')).toBe(true); + }); + it('returns false for larger tag', () => { + expect(gte('1.2.3-next.2', '1.2.3-next.1')).toBe(true); }); it('returns true for larger patch', () => { expect(gte('1.2.4', '1.2.3')).toBe(true); diff --git a/packages/vite-plugin-svelte/src/plugins/configure.js b/packages/vite-plugin-svelte/src/plugins/configure.js index e4c4de3e1..531f77df6 100644 --- a/packages/vite-plugin-svelte/src/plugins/configure.js +++ b/packages/vite-plugin-svelte/src/plugins/configure.js @@ -12,6 +12,7 @@ import { } from '../utils/options.js'; import { buildIdFilter, buildIdParser } from '../utils/id.js'; import { createCompileSvelte } from '../utils/compile.js'; +import { gte } from '../utils/svelte-version.js'; // @ts-ignore rolldownVersion const { version: viteVersion, rolldownVersion } = vite; @@ -59,35 +60,33 @@ export function configure(api, inlineOptions) { // extra vite config const extraViteConfig = await buildExtraViteConfig(preOptions, config); - if (rolldownVersion && configEnv.command === 'build') { - const [major, minor, patch, tag] = rolldownVersion - .replace(/[^\d.]/g, '') - .split('.') - .map(Number); - if (major > 1 || (major === 1 && (minor > 0 || patch > 0 || tag > 34))) { - extraViteConfig.build ??= {}; - // rename rollupOptions to rolldownOptions - //@ts-ignore rolldownOptions only exists in rolldown-vite - extraViteConfig.build.rolldownOptions = extraViteConfig.build.rollupOptions || {}; - delete extraViteConfig.build.rollupOptions; - // read user config inlineConst value - const inlineConst = - //@ts-ignore optimization only exists in rolldown-vite - config.build?.rolldownOptions?.optimization?.inlineConst ?? - //@ts-ignore optimization only exists in rolldown-vite - config.build?.rollupOptions?.optimization?.inlineConst; + if ( + rolldownVersion && + configEnv.command === 'build' && + gte(rolldownVersion, '1.0.0-beta.35') // inlineConst received a critical bugfix in 1.0.0-beta.35 + ) { + extraViteConfig.build ??= {}; + // rename rollupOptions to rolldownOptions + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions = extraViteConfig.build.rollupOptions || {}; + delete extraViteConfig.build.rollupOptions; + // read user config inlineConst value + const inlineConst = + //@ts-ignore optimization only exists in rolldown-vite + config.build?.rolldownOptions?.optimization?.inlineConst ?? + //@ts-ignore optimization only exists in rolldown-vite + config.build?.rollupOptions?.optimization?.inlineConst; - if (inlineConst == null) { - // set inlineConst build optimization for esm-env - //@ts-ignore rolldownOptions only exists in rolldown-vite - extraViteConfig.build.rolldownOptions.optimization ??= {}; - //@ts-ignore rolldownOptions only exists in rolldown-vite - extraViteConfig.build.rolldownOptions.optimization.inlineConst = true; - } else if (inlineConst === false) { - log.warn( - 'Your rolldown config contains `optimization.inlineConst: false`. This can lead to increased bundle size and leaked server code in client build.' - ); - } + if (inlineConst == null) { + // set inlineConst build optimization for esm-env + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions.optimization ??= {}; + //@ts-ignore rolldownOptions only exists in rolldown-vite + extraViteConfig.build.rolldownOptions.optimization.inlineConst = true; + } else if (inlineConst === false) { + log.warn( + 'Your rolldown config contains `optimization.inlineConst: false`. This can lead to increased bundle size and leaked server code in client build.' + ); } } diff --git a/packages/vite-plugin-svelte/src/utils/svelte-version.js b/packages/vite-plugin-svelte/src/utils/svelte-version.js index b716a6bdf..abc8e50b9 100644 --- a/packages/vite-plugin-svelte/src/utils/svelte-version.js +++ b/packages/vite-plugin-svelte/src/utils/svelte-version.js @@ -6,15 +6,27 @@ import { VERSION } from 'svelte/compiler'; export const isSvelteWithAsync = gte(VERSION, '5.36.0'); /** - * compare semver versions, does not include comparing tags (-next.xy is ignored) + * split semver string and convert to number, ignores non digits in tag + * @param {string} semver + * @return {number[]} [major,minor,patch,tag] + */ +function splitToNumbers(semver) { + return semver + .replace(/[^\d.-]/g, '') + .split(/[.-]+/, 4) + .map(Number); +} + +/** + * compare semver versions, tags are compared by their numeric part only * * @param {string} a semver version * @param {string} b semver version * @return {boolean} true if a is greater or equal to b */ export function gte(a, b) { - const aNum = a.split(/[.-]/, 3).map(Number); - const bNum = b.split(/[.-]/, 3).map(Number); + const aNum = splitToNumbers(a); + const bNum = splitToNumbers(b); for (let i = 0; i < aNum.length; i++) { if (aNum[i] < bNum[i]) { return false; From 4f7105a4ac4f75fd4e9b01f41fdfa394999bfa8d Mon Sep 17 00:00:00 2001 From: dominikg Date: Tue, 9 Sep 2025 15:28:11 +0200 Subject: [PATCH 4/4] fix: support comparing partial version strings (missing tag,patch,minor) --- .../__tests__/svelte-version.spec.js | 25 ++++++++++++++++++- .../src/utils/svelte-version.js | 9 ++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js b/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js index 94ce1145e..a30530b99 100644 --- a/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js +++ b/packages/vite-plugin-svelte/__tests__/svelte-version.spec.js @@ -5,28 +5,51 @@ describe('gte', () => { it('returns false for smaller tag', () => { expect(gte('1.2.3-next.1', '1.2.3-next.2')).toBe(false); }); + it('returns false for tag vs no tag', () => { + expect(gte('1.2.3-next.0', '1.2.3')).toBe(false); + }); it('returns false for smaller patch', () => { + expect(gte('1.2.2-next.0', '1.2.3')).toBe(false); expect(gte('1.2.2', '1.2.3')).toBe(false); }); it('returns false for smaller minor', () => { + expect(gte('1.1.4-next.0', '1.2.3')).toBe(false); expect(gte('1.1.4', '1.2.3')).toBe(false); + expect(gte('1.1', '1.2.3')).toBe(false); }); it('returns false for smaller major', () => { + expect(gte('0.3.4-next.0', '1.2.3')).toBe(false); expect(gte('0.3.4', '1.2.3')).toBe(false); + expect(gte('0.3', '1.2.3')).toBe(false); + expect(gte('0', '1.2.3')).toBe(false); }); it('returns true for equal', () => { expect(gte('1.2.3-next.1', '1.2.3-next.1')).toBe(true); }); - it('returns false for larger tag', () => { + it('returns true for equal without tag', () => { + expect(gte('1.2.3', '1.2.3')).toBe(true); + expect(gte('1.2', '1.2.0')).toBe(true); + expect(gte('1.2', '1.2')).toBe(true); + expect(gte('1', '1.0')).toBe(true); + expect(gte('1', '1.0.0')).toBe(true); + }); + it('returns true for larger tag', () => { expect(gte('1.2.3-next.2', '1.2.3-next.1')).toBe(true); }); + it('returns true for no tag vs tag', () => { + expect(gte('1.2.3', '1.2.3-next.0')).toBe(true); + }); it('returns true for larger patch', () => { expect(gte('1.2.4', '1.2.3')).toBe(true); + expect(gte('1.2.4-next.0', '1.2.3')).toBe(true); }); it('returns true for larger minor', () => { expect(gte('1.3.1', '1.2.3')).toBe(true); + expect(gte('1.3', '1.2.3')).toBe(true); }); it('returns true for larger major', () => { expect(gte('2.0.0', '1.2.3')).toBe(true); + expect(gte('2.0', '1.2.3')).toBe(true); + expect(gte('2', '1.2.3')).toBe(true); }); }); diff --git a/packages/vite-plugin-svelte/src/utils/svelte-version.js b/packages/vite-plugin-svelte/src/utils/svelte-version.js index abc8e50b9..d0ca8f2e0 100644 --- a/packages/vite-plugin-svelte/src/utils/svelte-version.js +++ b/packages/vite-plugin-svelte/src/utils/svelte-version.js @@ -11,10 +11,17 @@ export const isSvelteWithAsync = gte(VERSION, '5.36.0'); * @return {number[]} [major,minor,patch,tag] */ function splitToNumbers(semver) { - return semver + const num = semver .replace(/[^\d.-]/g, '') .split(/[.-]+/, 4) .map(Number); + while (num.length < 3) { + num.push(0); + } + if (num.length < 4) { + num.push(Infinity); + } + return num; } /**