613 lines
20 KiB
JavaScript
613 lines
20 KiB
JavaScript
/* eslint-disable no-unused-vars */
|
|
import { normalizePath } from 'vite';
|
|
import { isDebugNamespaceEnabled, log } from './log.js';
|
|
import { loadSvelteConfig } from './load-svelte-config.js';
|
|
import {
|
|
SVELTE_EXPORT_CONDITIONS,
|
|
SVELTE_HMR_IMPORTS,
|
|
SVELTE_IMPORTS,
|
|
SVELTE_RESOLVE_MAIN_FIELDS,
|
|
VITE_RESOLVE_MAIN_FIELDS
|
|
} from './constants.js';
|
|
|
|
import path from 'node:path';
|
|
import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild.js';
|
|
import { addExtraPreprocessors } from './preprocess.js';
|
|
import deepmerge from 'deepmerge';
|
|
import {
|
|
crawlFrameworkPkgs,
|
|
isDepExcluded,
|
|
isDepExternaled,
|
|
isDepIncluded,
|
|
isDepNoExternaled
|
|
} from 'vitefu';
|
|
|
|
import { isCommonDepWithoutSvelteField } from './dependencies.js';
|
|
import { VitePluginSvelteStats } from './vite-plugin-svelte-stats.js';
|
|
import { VitePluginSvelteCache } from './vite-plugin-svelte-cache.js';
|
|
|
|
const allowedPluginOptions = new Set([
|
|
'include',
|
|
'exclude',
|
|
'emitCss',
|
|
'hot',
|
|
'ignorePluginPreprocessors',
|
|
'disableDependencyReinclusion',
|
|
'prebundleSvelteLibraries',
|
|
'inspector',
|
|
'experimental'
|
|
]);
|
|
|
|
const knownRootOptions = new Set(['extensions', 'compilerOptions', 'preprocess', 'onwarn']);
|
|
|
|
const allowedInlineOptions = new Set(['configFile', ...allowedPluginOptions, ...knownRootOptions]);
|
|
|
|
/**
|
|
* @param {Partial<import('../index.d.ts').Options>} [inlineOptions]
|
|
*/
|
|
export function validateInlineOptions(inlineOptions) {
|
|
const invalidKeys = Object.keys(inlineOptions || {}).filter(
|
|
(key) => !allowedInlineOptions.has(key)
|
|
);
|
|
if (invalidKeys.length) {
|
|
log.warn(`invalid plugin options "${invalidKeys.join(', ')}" in inline config`, inlineOptions);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Partial<import('../index.d.ts').SvelteOptions>} [config]
|
|
* @returns {Partial<import('../index.d.ts').Options> | undefined}
|
|
*/
|
|
function convertPluginOptions(config) {
|
|
if (!config) {
|
|
return;
|
|
}
|
|
const invalidRootOptions = Object.keys(config).filter((key) => allowedPluginOptions.has(key));
|
|
if (invalidRootOptions.length > 0) {
|
|
throw new Error(
|
|
`Invalid options in svelte config. Move the following options into 'vitePlugin:{...}': ${invalidRootOptions.join(
|
|
', '
|
|
)}`
|
|
);
|
|
}
|
|
if (!config.vitePlugin) {
|
|
return config;
|
|
}
|
|
const pluginOptions = config.vitePlugin;
|
|
const pluginOptionKeys = Object.keys(pluginOptions);
|
|
|
|
const rootOptionsInPluginOptions = pluginOptionKeys.filter((key) => knownRootOptions.has(key));
|
|
if (rootOptionsInPluginOptions.length > 0) {
|
|
throw new Error(
|
|
`Invalid options in svelte config under vitePlugin:{...}', move them to the config root : ${rootOptionsInPluginOptions.join(
|
|
', '
|
|
)}`
|
|
);
|
|
}
|
|
const duplicateOptions = pluginOptionKeys.filter((key) =>
|
|
Object.prototype.hasOwnProperty.call(config, key)
|
|
);
|
|
if (duplicateOptions.length > 0) {
|
|
throw new Error(
|
|
`Invalid duplicate options in svelte config under vitePlugin:{...}', they are defined in root too and must only exist once: ${duplicateOptions.join(
|
|
', '
|
|
)}`
|
|
);
|
|
}
|
|
const unknownPluginOptions = pluginOptionKeys.filter((key) => !allowedPluginOptions.has(key));
|
|
if (unknownPluginOptions.length > 0) {
|
|
log.warn(
|
|
`ignoring unknown plugin options in svelte config under vitePlugin:{...}: ${unknownPluginOptions.join(
|
|
', '
|
|
)}`
|
|
);
|
|
unknownPluginOptions.forEach((unkownOption) => {
|
|
// @ts-ignore
|
|
delete pluginOptions[unkownOption];
|
|
});
|
|
}
|
|
/** @type {import('../index.d.ts').Options} */
|
|
const result = {
|
|
...config,
|
|
...pluginOptions
|
|
};
|
|
// @ts-expect-error it exists
|
|
delete result.vitePlugin;
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* used in config phase, merges the default options, svelte config, and inline options
|
|
* @param {Partial<import('../index.d.ts').Options> | undefined} inlineOptions
|
|
* @param {import('vite').UserConfig} viteUserConfig
|
|
* @param {import('vite').ConfigEnv} viteEnv
|
|
* @returns {Promise<import('../types/options.d.ts').PreResolvedOptions>}
|
|
*/
|
|
export async function preResolveOptions(inlineOptions, viteUserConfig, viteEnv) {
|
|
if (!inlineOptions) {
|
|
inlineOptions = {};
|
|
}
|
|
/** @type {import('vite').UserConfig} */
|
|
const viteConfigWithResolvedRoot = {
|
|
...viteUserConfig,
|
|
root: resolveViteRoot(viteUserConfig)
|
|
};
|
|
const isBuild = viteEnv.command === 'build';
|
|
/** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
|
|
const defaultOptions = {
|
|
extensions: ['.svelte'],
|
|
emitCss: true,
|
|
prebundleSvelteLibraries: !isBuild
|
|
};
|
|
const svelteConfig = convertPluginOptions(
|
|
await loadSvelteConfig(viteConfigWithResolvedRoot, inlineOptions)
|
|
);
|
|
/** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
|
|
const extraOptions = {
|
|
root: viteConfigWithResolvedRoot.root,
|
|
isBuild,
|
|
isServe: viteEnv.command === 'serve',
|
|
isDebug: process.env.DEBUG != null
|
|
};
|
|
|
|
const merged = /** @type {import('../types/options.d.ts').PreResolvedOptions} */ (
|
|
mergeConfigs(defaultOptions, svelteConfig, inlineOptions, extraOptions)
|
|
);
|
|
// configFile of svelteConfig contains the absolute path it was loaded from,
|
|
// prefer it over the possibly relative inline path
|
|
if (svelteConfig?.configFile) {
|
|
merged.configFile = svelteConfig.configFile;
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {(Partial<T> | undefined)[]} configs
|
|
* @returns T
|
|
*/
|
|
function mergeConfigs(...configs) {
|
|
/** @type {Partial<T>} */
|
|
let result = {};
|
|
for (const config of configs.filter((x) => x != null)) {
|
|
result = deepmerge(result, /** @type {Partial<T>} */ (config), {
|
|
// replace arrays
|
|
arrayMerge: (target, source) => source ?? target
|
|
});
|
|
}
|
|
return /** @type {T} */ result;
|
|
}
|
|
|
|
/**
|
|
* used in configResolved phase, merges a contextual default config, pre-resolved options, and some preprocessors. also validates the final config.
|
|
*
|
|
* @param {import('../types/options.d.ts').PreResolvedOptions} preResolveOptions
|
|
* @param {import('vite').ResolvedConfig} viteConfig
|
|
* @param {VitePluginSvelteCache} cache
|
|
* @returns {import('../types/options.d.ts').ResolvedOptions}
|
|
*/
|
|
export function resolveOptions(preResolveOptions, viteConfig, cache) {
|
|
const css = preResolveOptions.emitCss ? 'external' : 'injected';
|
|
/** @type {Partial<import('../index.d.ts').Options>} */
|
|
const defaultOptions = {
|
|
hot: viteConfig.isProduction
|
|
? false
|
|
: {
|
|
injectCss: css === 'injected',
|
|
partialAccept: !!viteConfig.experimental?.hmrPartialAccept
|
|
},
|
|
compilerOptions: {
|
|
css,
|
|
dev: !viteConfig.isProduction
|
|
}
|
|
};
|
|
/** @type {Partial<import('../types/options.d.ts').ResolvedOptions>} */
|
|
const extraOptions = {
|
|
root: viteConfig.root,
|
|
isProduction: viteConfig.isProduction
|
|
};
|
|
const merged = /** @type {import('../types/options.d.ts').ResolvedOptions}*/ (
|
|
mergeConfigs(defaultOptions, preResolveOptions, extraOptions)
|
|
);
|
|
|
|
removeIgnoredOptions(merged);
|
|
handleDeprecatedOptions(merged);
|
|
addExtraPreprocessors(merged, viteConfig);
|
|
enforceOptionsForHmr(merged);
|
|
enforceOptionsForProduction(merged);
|
|
// mergeConfigs would mangle functions on the stats class, so do this afterwards
|
|
if (log.debug.enabled && isDebugNamespaceEnabled('stats')) {
|
|
merged.stats = new VitePluginSvelteStats(cache);
|
|
}
|
|
return merged;
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
*/
|
|
function enforceOptionsForHmr(options) {
|
|
if (options.hot) {
|
|
if (!options.compilerOptions.dev) {
|
|
log.warn('hmr is enabled but compilerOptions.dev is false, forcing it to true');
|
|
options.compilerOptions.dev = true;
|
|
}
|
|
if (options.emitCss) {
|
|
if (options.hot !== true && options.hot.injectCss) {
|
|
log.warn('hmr and emitCss are enabled but hot.injectCss is true, forcing it to false');
|
|
options.hot.injectCss = false;
|
|
}
|
|
const css = options.compilerOptions.css;
|
|
if (css === true || css === 'injected') {
|
|
const forcedCss = 'external';
|
|
log.warn(
|
|
`hmr and emitCss are enabled but compilerOptions.css is ${css}, forcing it to ${forcedCss}`
|
|
);
|
|
options.compilerOptions.css = forcedCss;
|
|
}
|
|
} else {
|
|
if (options.hot === true || !options.hot.injectCss) {
|
|
log.warn(
|
|
'hmr with emitCss disabled requires option hot.injectCss to be enabled, forcing it to true'
|
|
);
|
|
if (options.hot === true) {
|
|
options.hot = { injectCss: true };
|
|
} else {
|
|
options.hot.injectCss = true;
|
|
}
|
|
}
|
|
const css = options.compilerOptions.css;
|
|
if (!(css === true || css === 'injected')) {
|
|
const forcedCss = 'injected';
|
|
log.warn(
|
|
`hmr with emitCss disabled requires compilerOptions.css to be enabled, forcing it to ${forcedCss}`
|
|
);
|
|
options.compilerOptions.css = forcedCss;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
*/
|
|
function enforceOptionsForProduction(options) {
|
|
if (options.isProduction) {
|
|
if (options.hot) {
|
|
log.warn('options.hot is enabled but does not work on production build, forcing it to false');
|
|
options.hot = false;
|
|
}
|
|
if (options.compilerOptions.dev) {
|
|
log.warn(
|
|
'you are building for production but compilerOptions.dev is true, forcing it to false'
|
|
);
|
|
options.compilerOptions.dev = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
*/
|
|
function removeIgnoredOptions(options) {
|
|
const ignoredCompilerOptions = ['generate', 'format', 'filename'];
|
|
if (options.hot && options.emitCss) {
|
|
ignoredCompilerOptions.push('cssHash');
|
|
}
|
|
const passedCompilerOptions = Object.keys(options.compilerOptions || {});
|
|
const passedIgnored = passedCompilerOptions.filter((o) => ignoredCompilerOptions.includes(o));
|
|
if (passedIgnored.length) {
|
|
log.warn(
|
|
`The following Svelte compilerOptions are controlled by vite-plugin-svelte and essential to its functionality. User-specified values are ignored. Please remove them from your configuration: ${passedIgnored.join(
|
|
', '
|
|
)}`
|
|
);
|
|
passedIgnored.forEach((ignored) => {
|
|
// @ts-expect-error string access
|
|
delete options.compilerOptions[ignored];
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
*/
|
|
function handleDeprecatedOptions(options) {
|
|
const experimental = /** @type {Record<string, any>} */ (options.experimental);
|
|
if (experimental) {
|
|
for (const promoted of ['prebundleSvelteLibraries', 'inspector']) {
|
|
if (experimental[promoted]) {
|
|
//@ts-expect-error untyped assign
|
|
options[promoted] = experimental[promoted];
|
|
delete experimental[promoted];
|
|
log.warn(
|
|
`Option "vitePlugin.experimental.${promoted}" is no longer experimental and has moved to "vitePlugin.${promoted}". Please update your svelte config.`
|
|
);
|
|
}
|
|
}
|
|
if (experimental.generateMissingPreprocessorSourcemaps) {
|
|
log.warn('experimental.generateMissingPreprocessorSourcemaps has been removed.');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* vite passes unresolved `root`option to config hook but we need the resolved value, so do it here
|
|
*
|
|
* @see https://github.com/sveltejs/vite-plugin-svelte/issues/113
|
|
* @see https://github.com/vitejs/vite/blob/43c957de8a99bb326afd732c962f42127b0a4d1e/packages/vite/src/node/config.ts#L293
|
|
*
|
|
* @param {import('vite').UserConfig} viteConfig
|
|
* @returns {string | undefined}
|
|
*/
|
|
function resolveViteRoot(viteConfig) {
|
|
return normalizePath(viteConfig.root ? path.resolve(viteConfig.root) : process.cwd());
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
* @param {import('vite').UserConfig} config
|
|
* @returns {Promise<Partial<import('vite').UserConfig>>}
|
|
*/
|
|
export async function buildExtraViteConfig(options, config) {
|
|
// make sure we only readd vite default mainFields when no other plugin has changed the config already
|
|
// see https://github.com/sveltejs/vite-plugin-svelte/issues/581
|
|
if (!config.resolve) {
|
|
config.resolve = {};
|
|
}
|
|
config.resolve.mainFields = [
|
|
...SVELTE_RESOLVE_MAIN_FIELDS,
|
|
...(config.resolve.mainFields ?? VITE_RESOLVE_MAIN_FIELDS)
|
|
];
|
|
|
|
/** @type {Partial<import('vite').UserConfig>} */
|
|
const extraViteConfig = {
|
|
resolve: {
|
|
dedupe: [...SVELTE_IMPORTS, ...SVELTE_HMR_IMPORTS],
|
|
conditions: [...SVELTE_EXPORT_CONDITIONS]
|
|
}
|
|
// this option is still awaiting a PR in vite to be supported
|
|
// see https://github.com/sveltejs/vite-plugin-svelte/issues/60
|
|
// @ts-ignore
|
|
// knownJsSrcExtensions: options.extensions
|
|
};
|
|
|
|
const extraSvelteConfig = buildExtraConfigForSvelte(config);
|
|
const extraDepsConfig = await buildExtraConfigForDependencies(options, config);
|
|
// merge extra svelte and deps config, but make sure dep values are not contradicting svelte
|
|
extraViteConfig.optimizeDeps = {
|
|
include: [
|
|
...extraSvelteConfig.optimizeDeps.include,
|
|
...extraDepsConfig.optimizeDeps.include.filter(
|
|
(dep) => !isDepExcluded(dep, extraSvelteConfig.optimizeDeps.exclude)
|
|
)
|
|
],
|
|
exclude: [
|
|
...extraSvelteConfig.optimizeDeps.exclude,
|
|
...extraDepsConfig.optimizeDeps.exclude.filter(
|
|
(dep) => !isDepIncluded(dep, extraSvelteConfig.optimizeDeps.include)
|
|
)
|
|
]
|
|
};
|
|
|
|
extraViteConfig.ssr = {
|
|
external: [
|
|
...extraSvelteConfig.ssr.external,
|
|
...extraDepsConfig.ssr.external.filter(
|
|
(dep) => !isDepNoExternaled(dep, extraSvelteConfig.ssr.noExternal)
|
|
)
|
|
],
|
|
noExternal: [
|
|
...extraSvelteConfig.ssr.noExternal,
|
|
...extraDepsConfig.ssr.noExternal.filter(
|
|
(dep) => !isDepExternaled(dep, extraSvelteConfig.ssr.external)
|
|
)
|
|
]
|
|
};
|
|
|
|
// handle prebundling for svelte files
|
|
if (options.prebundleSvelteLibraries) {
|
|
extraViteConfig.optimizeDeps = {
|
|
...extraViteConfig.optimizeDeps,
|
|
// Experimental Vite API to allow these extensions to be scanned and prebundled
|
|
// @ts-ignore
|
|
extensions: options.extensions ?? ['.svelte'],
|
|
// Add esbuild plugin to prebundle Svelte files.
|
|
// Currently a placeholder as more information is needed after Vite config is resolved,
|
|
// the real Svelte plugin is added in `patchResolvedViteConfig()`
|
|
esbuildOptions: {
|
|
plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
|
|
}
|
|
};
|
|
}
|
|
|
|
// enable hmrPartialAccept if not explicitly disabled
|
|
if (
|
|
(options.hot == null ||
|
|
options.hot === true ||
|
|
(options.hot && options.hot.partialAccept !== false)) && // deviate from svelte-hmr, default to true
|
|
config.experimental?.hmrPartialAccept !== false
|
|
) {
|
|
log.debug('enabling "experimental.hmrPartialAccept" in vite config');
|
|
extraViteConfig.experimental = { hmrPartialAccept: true };
|
|
}
|
|
validateViteConfig(extraViteConfig, config, options);
|
|
return extraViteConfig;
|
|
}
|
|
|
|
/**
|
|
* @param {Partial<import('vite').UserConfig>} extraViteConfig
|
|
* @param {import('vite').UserConfig} config
|
|
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
*/
|
|
function validateViteConfig(extraViteConfig, config, options) {
|
|
const { prebundleSvelteLibraries, isBuild } = options;
|
|
if (prebundleSvelteLibraries) {
|
|
/** @type {(option: 'dev' | 'build' | boolean)=> boolean} */
|
|
const isEnabled = (option) => option !== true && option !== (isBuild ? 'build' : 'dev');
|
|
/** @type {(name: string, value: 'dev' | 'build' | boolean, recommendation: string)=> void} */
|
|
const logWarning = (name, value, recommendation) =>
|
|
log.warn.once(
|
|
`Incompatible options: \`prebundleSvelteLibraries: true\` and vite \`${name}: ${JSON.stringify(
|
|
value
|
|
)}\` ${isBuild ? 'during build.' : '.'} ${recommendation}`
|
|
);
|
|
const viteOptimizeDepsDisabled = config.optimizeDeps?.disabled ?? 'build'; // fall back to vite default
|
|
const isOptimizeDepsEnabled = isEnabled(viteOptimizeDepsDisabled);
|
|
if (!isBuild && !isOptimizeDepsEnabled) {
|
|
logWarning(
|
|
'optimizeDeps.disabled',
|
|
viteOptimizeDepsDisabled,
|
|
'Forcing `optimizeDeps.disabled: "build"`. Disable prebundleSvelteLibraries or update your vite config to enable optimizeDeps during dev.'
|
|
);
|
|
if (!extraViteConfig.optimizeDeps) {
|
|
extraViteConfig.optimizeDeps = {};
|
|
}
|
|
extraViteConfig.optimizeDeps.disabled = 'build';
|
|
} else if (isBuild && isOptimizeDepsEnabled) {
|
|
logWarning(
|
|
'optimizeDeps.disabled',
|
|
viteOptimizeDepsDisabled,
|
|
'Disable optimizeDeps or prebundleSvelteLibraries for build if you experience errors.'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
* @param {import('vite').UserConfig} config
|
|
* @returns {Promise<import('vitefu').CrawlFrameworkPkgsResult>}
|
|
*/
|
|
async function buildExtraConfigForDependencies(options, config) {
|
|
// extra handling for svelte dependencies in the project
|
|
const depsConfig = await crawlFrameworkPkgs({
|
|
root: options.root,
|
|
isBuild: options.isBuild,
|
|
viteUserConfig: config,
|
|
isFrameworkPkgByJson(pkgJson) {
|
|
let hasSvelteCondition = false;
|
|
if (typeof pkgJson.exports === 'object') {
|
|
// use replacer as a simple way to iterate over nested keys
|
|
JSON.stringify(pkgJson.exports, (key, value) => {
|
|
if (SVELTE_EXPORT_CONDITIONS.includes(key)) {
|
|
hasSvelteCondition = true;
|
|
}
|
|
return value;
|
|
});
|
|
}
|
|
return hasSvelteCondition || !!pkgJson.svelte;
|
|
},
|
|
isSemiFrameworkPkgByJson(pkgJson) {
|
|
return !!pkgJson.dependencies?.svelte || !!pkgJson.peerDependencies?.svelte;
|
|
},
|
|
isFrameworkPkgByName(pkgName) {
|
|
const isNotSveltePackage = isCommonDepWithoutSvelteField(pkgName);
|
|
if (isNotSveltePackage) {
|
|
return false;
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
});
|
|
|
|
log.debug('extra config for dependencies generated by vitefu', depsConfig);
|
|
|
|
if (options.prebundleSvelteLibraries) {
|
|
// prebundling enabled, so we don't need extra dependency excludes
|
|
depsConfig.optimizeDeps.exclude = [];
|
|
// but keep dependency reinclusions of explicit user excludes
|
|
const userExclude = config.optimizeDeps?.exclude;
|
|
depsConfig.optimizeDeps.include = !userExclude
|
|
? []
|
|
: depsConfig.optimizeDeps.include.filter((dep) => {
|
|
// reincludes look like this: foo > bar > baz
|
|
// in case foo or bar are excluded, we have to retain the reinclude even with prebundling
|
|
return (
|
|
dep.includes('>') &&
|
|
dep
|
|
.split('>')
|
|
.slice(0, -1)
|
|
.some((d) => isDepExcluded(d.trim(), userExclude))
|
|
);
|
|
});
|
|
}
|
|
if (options.disableDependencyReinclusion === true) {
|
|
depsConfig.optimizeDeps.include = depsConfig.optimizeDeps.include.filter(
|
|
(dep) => !dep.includes('>')
|
|
);
|
|
} else if (Array.isArray(options.disableDependencyReinclusion)) {
|
|
const disabledDeps = options.disableDependencyReinclusion;
|
|
depsConfig.optimizeDeps.include = depsConfig.optimizeDeps.include.filter((dep) => {
|
|
if (!dep.includes('>')) return true;
|
|
const trimDep = dep.replace(/\s+/g, '');
|
|
return disabledDeps.some((disabled) => trimDep.includes(`${disabled}>`));
|
|
});
|
|
}
|
|
|
|
log.debug('post-processed extra config for dependencies', depsConfig);
|
|
|
|
return depsConfig;
|
|
}
|
|
|
|
/**
|
|
* @param {import('vite').UserConfig} config
|
|
* @returns {import('vite').UserConfig & { optimizeDeps: { include: string[], exclude:string[] }, ssr: { noExternal:(string|RegExp)[], external: string[] } } }
|
|
*/
|
|
function buildExtraConfigForSvelte(config) {
|
|
// include svelte imports for optimization unless explicitly excluded
|
|
/** @type {string[]} */
|
|
const include = [];
|
|
const exclude = ['svelte-hmr'];
|
|
if (!isDepExcluded('svelte', config.optimizeDeps?.exclude ?? [])) {
|
|
const svelteImportsToInclude = SVELTE_IMPORTS.filter((x) => x !== 'svelte/ssr'); // not used on clientside
|
|
log.debug(
|
|
`adding bare svelte packages to optimizeDeps.include: ${svelteImportsToInclude.join(', ')} `
|
|
);
|
|
include.push(...svelteImportsToInclude);
|
|
} else {
|
|
log.debug('"svelte" is excluded in optimizeDeps.exclude, skipped adding it to include.');
|
|
}
|
|
/** @type {(string | RegExp)[]} */
|
|
const noExternal = [];
|
|
/** @type {string[]} */
|
|
const external = [];
|
|
// add svelte to ssr.noExternal unless it is present in ssr.external
|
|
// so we can resolve it with svelte/ssr
|
|
if (!isDepExternaled('svelte', config.ssr?.external ?? [])) {
|
|
noExternal.push('svelte', /^svelte\//);
|
|
}
|
|
return { optimizeDeps: { include, exclude }, ssr: { noExternal, external } };
|
|
}
|
|
|
|
/**
|
|
* @param {import('vite').ResolvedConfig} viteConfig
|
|
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
*/
|
|
export function patchResolvedViteConfig(viteConfig, options) {
|
|
if (options.preprocess) {
|
|
for (const preprocessor of arraify(options.preprocess)) {
|
|
if (preprocessor.style && '__resolvedConfig' in preprocessor.style) {
|
|
preprocessor.style.__resolvedConfig = viteConfig;
|
|
}
|
|
}
|
|
}
|
|
|
|
// replace facade esbuild plugin with a real one
|
|
const facadeEsbuildSveltePlugin = viteConfig.optimizeDeps.esbuildOptions?.plugins?.find(
|
|
(plugin) => plugin.name === facadeEsbuildSveltePluginName
|
|
);
|
|
if (facadeEsbuildSveltePlugin) {
|
|
Object.assign(facadeEsbuildSveltePlugin, esbuildSveltePlugin(options));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {T | T[]} value
|
|
* @returns {T[]}
|
|
*/
|
|
function arraify(value) {
|
|
return Array.isArray(value) ? value : [value];
|
|
}
|