Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/spotty-jokes-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/vite-plugin-svelte': minor
---

feat: enable optimizer for server environments during dev
14 changes: 13 additions & 1 deletion packages/vite-plugin-svelte/src/plugins/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export function configure(api, inlineOptions) {
*/
let preOptions;

/**
* @type {unknown}
*/
let extraViteConfig;

/** @type {import('vite').Plugin} */
return {
name: 'vite-plugin-svelte:config',
Expand All @@ -57,11 +62,12 @@ export function configure(api, inlineOptions) {

preOptions = await preResolveOptions(inlineOptions, config, configEnv);
// extra vite config
const extraViteConfig = await buildExtraViteConfig(preOptions, config);
extraViteConfig = await buildExtraViteConfig(preOptions, config);
log.debug('additional vite config', extraViteConfig, 'config');
return extraViteConfig;
}
},

configResolved: {
order: 'pre',
handler(config) {
Expand All @@ -87,6 +93,12 @@ export function configure(api, inlineOptions) {
ensureConfigEnvironmentConditions(name, config, opts);
// @ts-expect-error the function above should make `resolve.conditions` non-nullable
config.resolve.conditions.push('svelte');
if (config.consumer === 'server' && extraViteConfig?.optimizeDeps) {
// optimizeDeps is not inherited by server environments so return it here
return {
optimizeDeps: extraViteConfig.optimizeDeps
};
}
},

configureServer(server) {
Expand Down
145 changes: 67 additions & 78 deletions packages/vite-plugin-svelte/src/plugins/setup-optimizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
return {
name: 'vite-plugin-svelte:setup-optimizer',
apply: 'serve',
config() {
configEnvironment(_name, config) {
const consumer = config.consumer ?? 'client';
/** @type {import('vite').UserConfig['optimizeDeps']} */
const optimizeDeps = {
// Experimental Vite API to allow these extensions to be scanned and prebundled
Expand All @@ -43,43 +44,25 @@
// the added plugins are patched in configResolved below
if (rolldownVersion) {
//@ts-ignore rolldown types not finished

optimizeDeps.rollupOptions = {
plugins: [
placeholderRolldownOptimizerPlugin(optimizeSveltePluginName),
placeholderRolldownOptimizerPlugin(optimizeSvelteModulePluginName)
rolldownOptimizerPlugin(api, consumer, true),
rolldownOptimizerPlugin(api, consumer, false)
]
};
} else {
optimizeDeps.esbuildOptions = {
plugins: [
{ name: optimizeSveltePluginName, setup: () => {} },
{ name: optimizeSvelteModulePluginName, setup: () => {} }
eSBuildOptimizerPlugin(api, consumer, true),

Check failure on line 57 in packages/vite-plugin-svelte/src/plugins/setup-optimizer.js

View workflow job for this annotation

GitHub Actions / checks (22, ubuntu-latest)

'eSBuildOptimizerPlugin' is not defined
eSBuildOptimizerPlugin(api, consumer, false)

Check failure on line 58 in packages/vite-plugin-svelte/src/plugins/setup-optimizer.js

View workflow job for this annotation

GitHub Actions / checks (22, ubuntu-latest)

'eSBuildOptimizerPlugin' is not defined
]
};
}
return { optimizeDeps };
},
configResolved(c) {
viteConfig = c;
const optimizeDeps = c.optimizeDeps;
if (rolldownVersion) {
const plugins =
// @ts-expect-error not typed
optimizeDeps.rollupOptions?.plugins?.filter((p) =>
[optimizeSveltePluginName, optimizeSvelteModulePluginName].includes(p.name)
) ?? [];
for (const plugin of plugins) {
patchRolldownOptimizerPlugin(plugin, api.options);
}
} else {
const plugins =
optimizeDeps.esbuildOptions?.plugins?.filter((p) =>
[optimizeSveltePluginName, optimizeSvelteModulePluginName].includes(p.name)
) ?? [];
for (const plugin of plugins) {
patchESBuildOptimizerPlugin(plugin, api.options);
}
}
},
async buildStart() {
if (!api.options.prebundleSvelteLibraries) return;
Expand All @@ -94,54 +77,72 @@
}

/**
* @param {EsbuildPlugin} plugin
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {import('../types/plugin-api.d.ts').PluginAPI} api
* @param {'server'|'client'} consumer
* @param {boolean} components
* @return {EsbuildPlugin}
*/
function patchESBuildOptimizerPlugin(plugin, options) {
const components = plugin.name === optimizeSveltePluginName;
function esbuildOptimizerPlugin(api, consumer, components) {

Check failure on line 85 in packages/vite-plugin-svelte/src/plugins/setup-optimizer.js

View workflow job for this annotation

GitHub Actions / checks (22, ubuntu-latest)

'esbuildOptimizerPlugin' is defined but never used
const name = components ? optimizeSveltePluginName : optimizeSvelteModulePluginName;
const compileFn = components ? compileSvelte : compileSvelteModule;
const statsName = components ? 'prebundle library components' : 'prebundle library modules';
const filter = components ? /\.svelte(?:\?.*)?$/ : /\.svelte\.[jt]s(?:\?.*)?$/;
plugin.setup = (build) => {
if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
const generate = consumer === 'server' ? 'server' : 'client';

/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let statsCollection;
build.onStart(() => {
statsCollection = options.stats?.startCollection(statsName, {
logResult: (c) => c.stats.length > 1
return {
name,
setup(build) {
if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;

/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let statsCollection;
build.onStart(() => {
statsCollection = api.options.stats?.startCollection(statsName, {
logResult: (c) => c.stats.length > 1
});
});
});
build.onLoad({ filter }, async ({ path: filename }) => {
const code = readFileSync(filename, 'utf8');
try {
const result = await compileFn(options, { filename, code }, statsCollection);
const contents = result.map
? result.code + '//# sourceMappingURL=' + result.map.toUrl()
: result.code;
return { contents };
} catch (e) {
return { errors: [toESBuildError(e, options)] };
}
});
build.onEnd(() => {
statsCollection?.finish();
});
build.onLoad({ filter }, async ({ path: filename }) => {
const code = readFileSync(filename, 'utf8');
try {
const result = await compileFn(
api.options,
{ filename, code },
generate,
statsCollection
);
const contents = result.map
? result.code + '//# sourceMappingURL=' + result.map.toUrl()
: result.code;
return { contents };
} catch (e) {
return { errors: [toESBuildError(e, api.options)] };
}
});
build.onEnd(() => {
statsCollection?.finish();
});
}
};
}

/**
* @param {RollupPlugin} plugin
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {import('../types/plugin-api.d.ts').PluginAPI} api
* @param {'server'|'client'} consumer
* @param {boolean} components
* @return {import('vite').Rollup.Plugin}
*/
function patchRolldownOptimizerPlugin(plugin, options) {
const components = plugin.name === optimizeSveltePluginName;
function rolldownOptimizerPlugin(api, consumer, components) {
const name = components ? optimizeSveltePluginName : optimizeSvelteModulePluginName;
const compileFn = components ? compileSvelte : compileSvelteModule;
const statsName = components ? 'prebundle library components' : 'prebundle library modules';
const includeRe = components ? /^[^?#]+\.svelte(?:[?#]|$)/ : /^[^?#]+\.svelte\.[jt]s(?:[?#]|$)/;
const generate = consumer === 'server' ? 'server' : 'client';
/** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
let statsCollection;

/**@type {import('vite').Rollup.Plugin}*/
const plugin = {
name
};
plugin.options = (opts) => {
// @ts-expect-error plugins is an array here
const isScanner = opts.plugins.some(
Expand All @@ -160,14 +161,14 @@
*/
async handler(code, filename) {
try {
return await compileFn(options, { filename, code }, statsCollection);
return await compileFn(api.options, { filename, code }, generate, statsCollection);
} catch (e) {
throw toRollupError(e, options);
throw toRollupError(e, api.options);
}
}
};
plugin.buildStart = () => {
statsCollection = options.stats?.startCollection(statsName, {
statsCollection = api.options.stats?.startCollection(statsName, {
logResult: (c) => c.stats.length > 1
});
};
Expand All @@ -176,15 +177,17 @@
};
}
};
return plugin;
}

/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {{ filename: string, code: string }} input
* @param {'client'|'server'} generate
* @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} [statsCollection]
* @returns {Promise<import('../types/compile.d.ts').Code>}
*/
async function compileSvelte(options, { filename, code }, statsCollection) {
async function compileSvelte(options, { filename, code }, generate, statsCollection) {
let css = options.compilerOptions.css;
if (css !== 'injected') {
// TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
Expand All @@ -196,7 +199,7 @@
...options.compilerOptions,
css,
filename,
generate: 'client'
generate
};

if (compileOptions.hmr && options.emitCss) {
Expand Down Expand Up @@ -252,15 +255,16 @@
/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @param {{ filename: string; code: string }} input
* @param {'client'|'server'} generate
* @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} [statsCollection]
* @returns {Promise<import('../types/compile.d.ts').Code>}
*/
async function compileSvelteModule(options, { filename, code }, statsCollection) {
async function compileSvelteModule(options, { filename, code }, generate, statsCollection) {
const endStat = statsCollection?.start(filename);
const compiled = svelte.compileModule(code, {
dev: options.compilerOptions?.dev ?? true, // default to dev: true because prebundling is only used in dev
filename,
generate: 'client'
generate
});
if (endStat) {
endStat();
Expand Down Expand Up @@ -311,21 +315,6 @@
return currentSvelteMetadata !== existingSvelteMetadata;
}

/**
*
* @param {string} name
* @returns {import('vite').Rollup.Plugin}
*/
function placeholderRolldownOptimizerPlugin(name) {
return {
name,
options() {},
buildStart() {},
buildEnd() {},
transform: { filter: { id: /^$/ }, handler() {} }
};
}

/**
* @param {import('../types/options.d.ts').ResolvedOptions} options
* @returns {Partial<import('../types/options.d.ts').ResolvedOptions>}
Expand Down
Loading