Skip to content

Commit 1a4d225

Browse files
teemingcCopilot
andauthored
feat: enable optimizer for server environments during dev (#1328)
* try this * changeset * fix * fix * fix * in case of undefined * real fix * don't filter svelte imports for the server * fix * try mapping path to remove fs info Co-authored-by: Copilot <copilot@github.com> * revert * this isn't used anymore * test kit change * fix lockfile * bump kit --------- Co-authored-by: Copilot <copilot@github.com>
1 parent d91be5f commit 1a4d225

10 files changed

Lines changed: 108 additions & 87 deletions

File tree

.changeset/wet-cats-study.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/vite-plugin-svelte': minor
3+
---
4+
5+
feat: enable optimizer for server environments during dev

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"@eslint/markdown": "^7.5.1",
3030
"@stylistic/eslint-plugin": "^5.10.0",
3131
"@sveltejs/eslint-config": "^9.0.0",
32-
"@sveltejs/kit": "^2.55.0",
32+
"@sveltejs/kit": "catalog:",
3333
"@svitejs/changesets-changelog-github-compact": "^1.2.0",
3434
"@types/fs-extra": "^11.0.4",
3535
"@types/node": "^22.19.1",

packages/e2e-tests/inspector-kit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"preview": "vite preview"
99
},
1010
"devDependencies": {
11-
"@sveltejs/kit": "^2.55.0",
11+
"@sveltejs/kit": "catalog:",
1212
"@sveltejs/vite-plugin-svelte": "workspace:^",
1313
"svelte": "^5.45.4",
1414
"vite": "catalog:"

packages/e2e-tests/kit-async/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"devDependencies": {
1616
"@sveltejs/adapter-node": "^5.4.0",
17-
"@sveltejs/kit": "^2.55.0",
17+
"@sveltejs/kit": "catalog:",
1818
"@sveltejs/vite-plugin-svelte": "workspace:^",
1919
"svelte": "^5.45.4",
2020
"svelte-check": "^4.3.4",

packages/e2e-tests/kit-node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
},
1515
"devDependencies": {
1616
"@sveltejs/adapter-node": "^5.4.0",
17-
"@sveltejs/kit": "^2.55.0",
17+
"@sveltejs/kit": "catalog:",
1818
"@sveltejs/package": "^2.5.7",
1919
"@sveltejs/vite-plugin-svelte": "workspace:^",
2020
"e2e-test-dep-svelte-api-only": "file:../_test_dependencies/svelte-api-only",

packages/vite-plugin-svelte/src/plugins/setup-optimizer.js

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
/** @import { PluginAPI } from '../types/plugin-api.js' */
44
/** @import { StatCollection } from '../types/vite-plugin-svelte-stats.js' */
55
/** @import { CompileOptions } from 'svelte/compiler' */
6-
/** @import { Plugin, ResolvedConfig, Rollup, UserConfig } from 'vite' */
6+
/** @import { Plugin, ResolvedConfig, Rolldown, UserConfig } from 'vite' */
77

88
import fs from 'node:fs/promises';
99
import path from 'node:path';
1010
import * as svelte from 'svelte/compiler';
1111
import { log } from '../utils/log.js';
1212
import { toRollupError } from '../utils/error.js';
13+
import { SVELTE_IMPORTS } from '../utils/constants.js';
14+
import { isDepExcluded } from 'vitefu';
1315

1416
/**
15-
* @typedef {NonNullable<Rollup.Plugin>} RollupPlugin
17+
* @typedef {NonNullable<Rolldown.Plugin>} RollupPlugin
1618
*/
1719

1820
const optimizeSveltePluginName = 'vite-plugin-svelte:optimize';
@@ -29,36 +31,31 @@ export function setupOptimizer(api) {
2931
return {
3032
name: 'vite-plugin-svelte:setup-optimizer',
3133
apply: 'serve',
32-
config() {
34+
configEnvironment(name, config) {
35+
// fall back to vite behavior when consumer isn't set
36+
const consumer = (config.consumer ?? name === 'client') ? 'client' : 'server';
3337
/** @type {UserConfig['optimizeDeps']} */
3438
const optimizeDeps = {
3539
// Experimental Vite API to allow these extensions to be scanned and prebundled
3640
extensions: ['.svelte']
3741
};
38-
// Add optimizer plugins to prebundle Svelte files.
39-
// Currently, a placeholder as more information is needed after Vite config is resolved,
40-
// the added plugins are patched in configResolved below
4142

43+
// Add optimizer plugins to prebundle Svelte files.
4244
optimizeDeps.rolldownOptions = {
4345
plugins: [
44-
placeholderRolldownOptimizerPlugin(optimizeSveltePluginName),
45-
placeholderRolldownOptimizerPlugin(optimizeSvelteModulePluginName)
46+
rolldownOptimizerPlugin(api, consumer, true),
47+
rolldownOptimizerPlugin(api, consumer, false)
4648
]
4749
};
4850

51+
if (consumer === 'server' && !isDepExcluded('svelte', config.optimizeDeps?.exclude ?? [])) {
52+
optimizeDeps.include = [...SVELTE_IMPORTS];
53+
}
54+
4955
return { optimizeDeps };
5056
},
5157
configResolved(c) {
5258
viteConfig = c;
53-
const optimizeDeps = c.optimizeDeps;
54-
const plugins =
55-
// @ts-expect-error not typed
56-
optimizeDeps.rolldownOptions?.plugins?.filter((p) =>
57-
[optimizeSveltePluginName, optimizeSvelteModulePluginName].includes(p.name)
58-
) ?? [];
59-
for (const plugin of plugins) {
60-
patchRolldownOptimizerPlugin(plugin, api.options);
61-
}
6259
},
6360
async buildStart() {
6461
if (!api.options.prebundleSvelteLibraries) return;
@@ -73,21 +70,29 @@ export function setupOptimizer(api) {
7370
}
7471

7572
/**
76-
* @param {RollupPlugin} plugin
77-
* @param {ResolvedOptions} options
73+
* @param {import('../types/plugin-api.d.ts').PluginAPI} api
74+
* @param {'server'|'client'} consumer
75+
* @param {boolean} components
76+
* @return {Rolldown.Plugin}
7877
*/
79-
function patchRolldownOptimizerPlugin(plugin, options) {
80-
const components = plugin.name === optimizeSveltePluginName;
78+
function rolldownOptimizerPlugin(api, consumer, components) {
79+
const name = components ? optimizeSveltePluginName : optimizeSvelteModulePluginName;
8180
const compileFn = components ? compileSvelte : compileSvelteModule;
8281
const statsName = components ? 'prebundle library components' : 'prebundle library modules';
8382
const includeRe = components ? /^[^?#]+\.svelte(?:[?#]|$)/ : /^[^?#]+\.svelte\.[jt]s(?:[?#]|$)/;
83+
const generate = consumer === 'server' ? 'server' : 'client';
8484
/** @type {StatCollection | undefined} */
8585
let statsCollection;
8686

87+
/**@type {Rolldown.Plugin}*/
88+
const plugin = {
89+
name
90+
};
91+
8792
plugin.options = (opts) => {
8893
// @ts-expect-error plugins is an array here
8994
const isScanner = opts.plugins.some(
90-
(/** @type {{ name: string; }} */ p) => p.name === 'vite:dep-scan:resolve'
95+
(/** @type {{ name: string; } | undefined} */ p) => p?.name === 'vite:dep-scan:resolve'
9196
);
9297
if (isScanner) {
9398
delete plugin.buildStart;
@@ -102,14 +107,14 @@ function patchRolldownOptimizerPlugin(plugin, options) {
102107
*/
103108
async handler(code, filename) {
104109
try {
105-
return await compileFn(options, { filename, code }, statsCollection);
110+
return await compileFn(api.options, { filename, code }, generate, statsCollection);
106111
} catch (e) {
107-
throw toRollupError(e, options);
112+
throw toRollupError(e, api.options);
108113
}
109114
}
110115
};
111116
plugin.buildStart = () => {
112-
statsCollection = options.stats?.startCollection(statsName, {
117+
statsCollection = api.options.stats?.startCollection(statsName, {
113118
logResult: (c) => c.stats.length > 1
114119
});
115120
};
@@ -118,15 +123,18 @@ function patchRolldownOptimizerPlugin(plugin, options) {
118123
};
119124
}
120125
};
126+
127+
return plugin;
121128
}
122129

123130
/**
124131
* @param {ResolvedOptions} options
125132
* @param {{ filename: string, code: string }} input
133+
* @param {'client'|'server'} generate
126134
* @param {StatCollection} [statsCollection]
127135
* @returns {Promise<Code>}
128136
*/
129-
async function compileSvelte(options, { filename, code }, statsCollection) {
137+
async function compileSvelte(options, { filename, code }, generate, statsCollection) {
130138
let css = options.compilerOptions.css;
131139
if (css !== 'injected') {
132140
// TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
@@ -138,7 +146,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
138146
...options.compilerOptions,
139147
css,
140148
filename,
141-
generate: 'client'
149+
generate
142150
};
143151

144152
let preprocessed;
@@ -189,15 +197,16 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
189197
/**
190198
* @param {ResolvedOptions} options
191199
* @param {{ filename: string; code: string }} input
200+
* @param {'client'|'server'} generate
192201
* @param {StatCollection} [statsCollection]
193202
* @returns {Promise<Code>}
194203
*/
195-
async function compileSvelteModule(options, { filename, code }, statsCollection) {
204+
async function compileSvelteModule(options, { filename, code }, generate, statsCollection) {
196205
const endStat = statsCollection?.start(filename);
197206
const compiled = svelte.compileModule(code, {
198207
dev: options.compilerOptions?.dev ?? true, // default to dev: true because prebundling is only used in dev
199208
filename,
200-
generate: 'client'
209+
generate
201210
});
202211
if (endStat) {
203212
endStat();
@@ -247,21 +256,6 @@ async function svelteMetadataChanged(cacheDir, options) {
247256
return currentSvelteMetadata !== existingSvelteMetadata;
248257
}
249258

250-
/**
251-
*
252-
* @param {string} name
253-
* @returns {Rollup.Plugin}
254-
*/
255-
function placeholderRolldownOptimizerPlugin(name) {
256-
return {
257-
name,
258-
options() {},
259-
buildStart() {},
260-
buildEnd() {},
261-
transform: { filter: { id: /^$/ }, handler() {} }
262-
};
263-
}
264-
265259
/**
266260
* @param {ResolvedOptions} options
267261
* @returns {Partial<ResolvedOptions>}

packages/vite-plugin-svelte/src/utils/constants.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
11
import { createRequire } from 'node:module';
22

3+
/** @type {import('svelte/package.json')} */
34
const sveltePkg = createRequire(import.meta.url)('svelte/package.json');
45

56
// list of svelte runtime dependencies to optimize together with svelte itself
6-
export const SVELTE_RUNTIME_DEPENDENCIES = [
7+
export const SVELTE_RUNTIME_DEPENDENCIES = /** @type {const} */ ([
78
'clsx' // avoids dev server restart after page load with npm + vite6 (see #1067)
8-
].filter((dep) => !!sveltePkg.dependencies?.[dep]);
9+
]).filter((dep) => !!sveltePkg.dependencies?.[dep]);
910

1011
export const SVELTE_IMPORTS = Object.entries(sveltePkg.exports)
11-
.map(([name, config]) => {
12-
// ignore type only
13-
if (typeof config === 'object' && Object.keys(config).length === 1 && config.types) {
14-
return '';
15-
}
12+
.filter(([name, config]) => {
1613
// ignore names
17-
if (name === './package.json' || name === './compiler') {
14+
if (name === './package.json') {
1815
return '';
1916
}
20-
return name.replace(/^\./, 'svelte');
17+
18+
// ignore type only
19+
return !(
20+
typeof config === 'object' &&
21+
Object.keys(config).length === 1 &&
22+
'types' in config &&
23+
config.types
24+
);
2125
})
22-
.filter((s) => s.length > 0);
26+
.map(([name]) => {
27+
return name.replace(/^\./, 'svelte');
28+
});
29+
30+
export const SVELTE_DEDUPED_IMPORTS = SVELTE_IMPORTS.map((name) => {
31+
if (name === 'svelte/compiler') {
32+
return '';
33+
}
34+
return name;
35+
}).filter((s) => s.length > 0);
36+
37+
export const SVELTE_CLIENT_IMPORTS = SVELTE_IMPORTS.map((name) => {
38+
// ignore names
39+
if (name === 'svelte/compiler' || name.endsWith('/server') || name.includes('/server/')) {
40+
return '';
41+
}
42+
43+
return name;
44+
}).filter((s) => s.length > 0);
2345

2446
export const SVELTE_EXPORT_CONDITIONS = ['svelte'];
2547

packages/vite-plugin-svelte/src/utils/options.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import {
2121
FAQ_LINK_MISSING_EXPORTS_CONDITION,
2222
LINK_TRANSFORM_WITH_PLUGIN,
2323
SVELTE_EXPORT_CONDITIONS,
24-
SVELTE_IMPORTS,
24+
SVELTE_CLIENT_IMPORTS,
25+
SVELTE_DEDUPED_IMPORTS,
2526
SVELTE_RUNTIME_DEPENDENCIES
2627
} from './constants.js';
2728

@@ -369,7 +370,7 @@ export async function buildExtraViteConfig(options, config) {
369370
/** @type {Partial<UserConfig>} */
370371
const extraViteConfig = {
371372
resolve: {
372-
dedupe: [...SVELTE_IMPORTS]
373+
dedupe: [...SVELTE_DEDUPED_IMPORTS]
373374
}
374375
// this option is still awaiting a PR in vite to be supported
375376
// see https://github.com/sveltejs/vite-plugin-svelte/issues/60
@@ -572,9 +573,7 @@ function buildExtraConfigForSvelte(config) {
572573
/** @type {string[]} */
573574
const exclude = [];
574575
if (!isDepExcluded('svelte', config.optimizeDeps?.exclude ?? [])) {
575-
const svelteImportsToInclude = SVELTE_IMPORTS.filter(
576-
(si) => !(si.endsWith('/server') || si.includes('/server/'))
577-
);
576+
const svelteImportsToInclude = [...SVELTE_CLIENT_IMPORTS];
578577
svelteImportsToInclude.push(...SVELTE_RUNTIME_DEPENDENCIES.map((dep) => `svelte > ${dep}`));
579578
log.debug(
580579
`adding bare svelte packages and runtime dependencies to optimizeDeps.include: ${svelteImportsToInclude.join(', ')} `,

0 commit comments

Comments
 (0)