@rsvelte/vite-plugin-svelte 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/package.json +59 -0
- package/src/index.js +42 -0
- package/src/plugins/compile-module.js +130 -0
- package/src/plugins/compile.js +65 -0
- package/src/plugins/configure.js +97 -0
- package/src/plugins/hot-update.js +196 -0
- package/src/plugins/load-compiled-css.js +66 -0
- package/src/plugins/load-custom.js +42 -0
- package/src/plugins/preprocess.js +208 -0
- package/src/plugins/setup-optimizer.js +340 -0
- package/src/preprocess.js +166 -0
- package/src/public.d.ts +217 -0
- package/src/types/compile.d.ts +37 -0
- package/src/types/id.d.ts +46 -0
- package/src/types/log.d.ts +24 -0
- package/src/types/options.d.ts +21 -0
- package/src/types/plugin-api.d.ts +15 -0
- package/src/types/vite-plugin-svelte-stats.d.ts +30 -0
- package/src/utils/compile.js +152 -0
- package/src/utils/constants.js +36 -0
- package/src/utils/dependencies.js +60 -0
- package/src/utils/error.js +167 -0
- package/src/utils/hash.js +43 -0
- package/src/utils/id.js +274 -0
- package/src/utils/load-svelte-config.js +80 -0
- package/src/utils/log.js +256 -0
- package/src/utils/options.js +618 -0
- package/src/utils/preprocess.js +89 -0
- package/src/utils/sourcemaps.js +82 -0
- package/src/utils/svelte-version.js +46 -0
- package/src/utils/vite-plugin-svelte-stats.js +248 -0
- package/src/utils/watch.js +95 -0
- package/types/index.d.ts +228 -0
- package/types/index.d.ts.map +31 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import * as vite from 'vite';
|
|
3
|
+
const {
|
|
4
|
+
defaultClientMainFields,
|
|
5
|
+
defaultServerMainFields,
|
|
6
|
+
defaultClientConditions,
|
|
7
|
+
defaultServerConditions,
|
|
8
|
+
normalizePath,
|
|
9
|
+
searchForWorkspaceRoot,
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
rolldownVersion
|
|
12
|
+
} = vite;
|
|
13
|
+
import { log } from './log.js';
|
|
14
|
+
import { loadSvelteConfig } from './load-svelte-config.js';
|
|
15
|
+
import {
|
|
16
|
+
DEFAULT_SVELTE_EXT,
|
|
17
|
+
FAQ_LINK_MISSING_EXPORTS_CONDITION,
|
|
18
|
+
SVELTE_EXPORT_CONDITIONS,
|
|
19
|
+
SVELTE_IMPORTS,
|
|
20
|
+
SVELTE_RUNTIME_DEPENDENCIES
|
|
21
|
+
} from './constants.js';
|
|
22
|
+
|
|
23
|
+
import path from 'node:path';
|
|
24
|
+
import { addExtraPreprocessors } from './preprocess.js';
|
|
25
|
+
import deepmerge from 'deepmerge';
|
|
26
|
+
import {
|
|
27
|
+
crawlFrameworkPkgs,
|
|
28
|
+
isDepExcluded,
|
|
29
|
+
isDepExternaled,
|
|
30
|
+
isDepIncluded,
|
|
31
|
+
isDepNoExternaled
|
|
32
|
+
} from 'vitefu';
|
|
33
|
+
|
|
34
|
+
import { isCommonDepWithoutSvelteField } from './dependencies.js';
|
|
35
|
+
|
|
36
|
+
const allowedPluginOptions = new Set([
|
|
37
|
+
'include',
|
|
38
|
+
'exclude',
|
|
39
|
+
'emitCss',
|
|
40
|
+
'hot',
|
|
41
|
+
'ignorePluginPreprocessors',
|
|
42
|
+
'disableDependencyReinclusion',
|
|
43
|
+
'prebundleSvelteLibraries',
|
|
44
|
+
'inspector',
|
|
45
|
+
'dynamicCompileOptions',
|
|
46
|
+
'experimental'
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
const knownRootOptions = new Set(['extensions', 'compilerOptions', 'preprocess', 'onwarn']);
|
|
50
|
+
|
|
51
|
+
const allowedInlineOptions = new Set(['configFile', ...allowedPluginOptions, ...knownRootOptions]);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {Partial<import('../public.d.ts').Options>} [inlineOptions]
|
|
55
|
+
*/
|
|
56
|
+
export function validateInlineOptions(inlineOptions) {
|
|
57
|
+
const invalidKeys = Object.keys(inlineOptions || {}).filter(
|
|
58
|
+
(key) => !allowedInlineOptions.has(key)
|
|
59
|
+
);
|
|
60
|
+
if (invalidKeys.length) {
|
|
61
|
+
log.warn(`invalid plugin options "${invalidKeys.join(', ')}" in inline config`, inlineOptions);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Partial<import('../public.d.ts').SvelteConfig>} [config]
|
|
67
|
+
* @returns {Partial<import('../public.d.ts').Options> | undefined}
|
|
68
|
+
*/
|
|
69
|
+
function convertPluginOptions(config) {
|
|
70
|
+
if (!config) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const invalidRootOptions = Object.keys(config).filter((key) => allowedPluginOptions.has(key));
|
|
74
|
+
if (invalidRootOptions.length > 0) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`Invalid options in svelte config. Move the following options into 'vitePlugin:{...}': ${invalidRootOptions.join(
|
|
77
|
+
', '
|
|
78
|
+
)}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (!config.vitePlugin) {
|
|
82
|
+
return config;
|
|
83
|
+
}
|
|
84
|
+
const pluginOptions = config.vitePlugin;
|
|
85
|
+
const pluginOptionKeys = Object.keys(pluginOptions);
|
|
86
|
+
|
|
87
|
+
const rootOptionsInPluginOptions = pluginOptionKeys.filter((key) => knownRootOptions.has(key));
|
|
88
|
+
if (rootOptionsInPluginOptions.length > 0) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Invalid options in svelte config under vitePlugin:{...}', move them to the config root : ${rootOptionsInPluginOptions.join(
|
|
91
|
+
', '
|
|
92
|
+
)}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const duplicateOptions = pluginOptionKeys.filter((key) =>
|
|
96
|
+
Object.prototype.hasOwnProperty.call(config, key)
|
|
97
|
+
);
|
|
98
|
+
if (duplicateOptions.length > 0) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Invalid duplicate options in svelte config under vitePlugin:{...}', they are defined in root too and must only exist once: ${duplicateOptions.join(
|
|
101
|
+
', '
|
|
102
|
+
)}`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const unknownPluginOptions = pluginOptionKeys.filter((key) => !allowedPluginOptions.has(key));
|
|
106
|
+
if (unknownPluginOptions.length > 0) {
|
|
107
|
+
log.warn(
|
|
108
|
+
`ignoring unknown plugin options in svelte config under vitePlugin:{...}: ${unknownPluginOptions.join(
|
|
109
|
+
', '
|
|
110
|
+
)}`
|
|
111
|
+
);
|
|
112
|
+
unknownPluginOptions.forEach((unkownOption) => {
|
|
113
|
+
// @ts-expect-error not typed
|
|
114
|
+
delete pluginOptions[unkownOption];
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** @type {import('../public.d.ts').Options} */
|
|
118
|
+
const result = {
|
|
119
|
+
...config,
|
|
120
|
+
...pluginOptions
|
|
121
|
+
};
|
|
122
|
+
// @ts-expect-error it exists
|
|
123
|
+
delete result.vitePlugin;
|
|
124
|
+
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* used in config phase, merges the default options, svelte config, and inline options
|
|
130
|
+
* @param {Partial<import('../public.d.ts').Options> | undefined} inlineOptions
|
|
131
|
+
* @param {import('vite').UserConfig} viteUserConfig
|
|
132
|
+
* @param {import('vite').ConfigEnv} viteEnv
|
|
133
|
+
* @returns {Promise<import('../types/options.d.ts').PreResolvedOptions>}
|
|
134
|
+
*/
|
|
135
|
+
export async function preResolveOptions(inlineOptions, viteUserConfig, viteEnv) {
|
|
136
|
+
if (!inlineOptions) {
|
|
137
|
+
inlineOptions = {};
|
|
138
|
+
}
|
|
139
|
+
/** @type {import('vite').UserConfig} */
|
|
140
|
+
const viteConfigWithResolvedRoot = {
|
|
141
|
+
...viteUserConfig,
|
|
142
|
+
root: resolveViteRoot(viteUserConfig)
|
|
143
|
+
};
|
|
144
|
+
const isBuild = viteEnv.command === 'build';
|
|
145
|
+
/** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
|
|
146
|
+
const defaultOptions = {
|
|
147
|
+
extensions: DEFAULT_SVELTE_EXT,
|
|
148
|
+
emitCss: true,
|
|
149
|
+
prebundleSvelteLibraries: !isBuild
|
|
150
|
+
};
|
|
151
|
+
const svelteConfig = convertPluginOptions(
|
|
152
|
+
await loadSvelteConfig(viteConfigWithResolvedRoot, inlineOptions)
|
|
153
|
+
);
|
|
154
|
+
/** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
|
|
155
|
+
const extraOptions = {
|
|
156
|
+
root: viteConfigWithResolvedRoot.root,
|
|
157
|
+
isBuild,
|
|
158
|
+
isServe: viteEnv.command === 'serve',
|
|
159
|
+
isDebug: process.env.DEBUG != null
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const merged = /** @type {import('../types/options.d.ts').PreResolvedOptions} */ (
|
|
163
|
+
mergeConfigs(defaultOptions, svelteConfig, inlineOptions, extraOptions)
|
|
164
|
+
);
|
|
165
|
+
// configFile of svelteConfig contains the absolute path it was loaded from,
|
|
166
|
+
// prefer it over the possibly relative inline path
|
|
167
|
+
if (svelteConfig?.configFile) {
|
|
168
|
+
merged.configFile = svelteConfig.configFile;
|
|
169
|
+
}
|
|
170
|
+
return merged;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @template T
|
|
175
|
+
* @param {(Partial<T> | undefined)[]} configs
|
|
176
|
+
* @returns T
|
|
177
|
+
*/
|
|
178
|
+
function mergeConfigs(...configs) {
|
|
179
|
+
/** @type {Partial<T>} */
|
|
180
|
+
let result = {};
|
|
181
|
+
for (const config of configs.filter((x) => x != null)) {
|
|
182
|
+
result = deepmerge(result, /** @type {Partial<T>} */ (config), {
|
|
183
|
+
// replace arrays
|
|
184
|
+
arrayMerge: (target, source) => source ?? target
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return /** @type {T} */ result;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* used in configResolved phase, merges a contextual default config, pre-resolved options, and some preprocessors. also validates the final config.
|
|
192
|
+
*
|
|
193
|
+
* @param {import('../types/options.d.ts').PreResolvedOptions} preResolveOptions
|
|
194
|
+
* @param {import('vite').ResolvedConfig} viteConfig
|
|
195
|
+
* @returns {import('../types/options.d.ts').ResolvedOptions}
|
|
196
|
+
*/
|
|
197
|
+
export function resolveOptions(preResolveOptions, viteConfig) {
|
|
198
|
+
const css = preResolveOptions.emitCss ? 'external' : 'injected';
|
|
199
|
+
/** @type {Partial<import('../public.d.ts').Options>} */
|
|
200
|
+
const defaultOptions = {
|
|
201
|
+
compilerOptions: {
|
|
202
|
+
css,
|
|
203
|
+
dev: !viteConfig.isProduction,
|
|
204
|
+
hmr:
|
|
205
|
+
!viteConfig.isProduction &&
|
|
206
|
+
!preResolveOptions.isBuild &&
|
|
207
|
+
viteConfig.server &&
|
|
208
|
+
viteConfig.server.hmr !== false
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/** @type {Partial<import('../types/options.d.ts').ResolvedOptions>} */
|
|
213
|
+
const extraOptions = {
|
|
214
|
+
root: viteConfig.root,
|
|
215
|
+
isProduction: viteConfig.isProduction
|
|
216
|
+
};
|
|
217
|
+
const merged = /** @type {import('../types/options.d.ts').ResolvedOptions}*/ (
|
|
218
|
+
mergeConfigs(defaultOptions, preResolveOptions, extraOptions)
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
removeIgnoredOptions(merged);
|
|
222
|
+
handleDeprecatedOptions(merged);
|
|
223
|
+
addExtraPreprocessors(merged, viteConfig);
|
|
224
|
+
enforceOptionsForHmr(merged, viteConfig);
|
|
225
|
+
enforceOptionsForProduction(merged);
|
|
226
|
+
|
|
227
|
+
return merged;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
232
|
+
* @param {import('vite').ResolvedConfig} viteConfig
|
|
233
|
+
*/
|
|
234
|
+
function enforceOptionsForHmr(options, viteConfig) {
|
|
235
|
+
if (options.hot) {
|
|
236
|
+
log.warn(
|
|
237
|
+
'svelte 5 has hmr integrated in core. Please remove the vitePlugin.hot option and use compilerOptions.hmr instead'
|
|
238
|
+
);
|
|
239
|
+
delete options.hot;
|
|
240
|
+
options.compilerOptions.hmr = true;
|
|
241
|
+
}
|
|
242
|
+
if (options.compilerOptions.hmr && viteConfig.server?.hmr === false) {
|
|
243
|
+
log.warn(
|
|
244
|
+
'vite config server.hmr is false but compilerOptions.hmr is true. Forcing compilerOptions.hmr to false as it would not work.'
|
|
245
|
+
);
|
|
246
|
+
options.compilerOptions.hmr = false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
252
|
+
*/
|
|
253
|
+
function enforceOptionsForProduction(options) {
|
|
254
|
+
if (options.isProduction) {
|
|
255
|
+
if (options.compilerOptions.hmr) {
|
|
256
|
+
log.warn(
|
|
257
|
+
'you are building for production but compilerOptions.hmr is true, forcing it to false'
|
|
258
|
+
);
|
|
259
|
+
options.compilerOptions.hmr = false;
|
|
260
|
+
}
|
|
261
|
+
if (options.compilerOptions.dev) {
|
|
262
|
+
log.warn(
|
|
263
|
+
'you are building for production but compilerOptions.dev is true, forcing it to false'
|
|
264
|
+
);
|
|
265
|
+
options.compilerOptions.dev = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
272
|
+
*/
|
|
273
|
+
function removeIgnoredOptions(options) {
|
|
274
|
+
const ignoredCompilerOptions = ['generate', 'format', 'filename'];
|
|
275
|
+
if (options.compilerOptions.hmr && options.emitCss) {
|
|
276
|
+
ignoredCompilerOptions.push('cssHash');
|
|
277
|
+
}
|
|
278
|
+
const passedCompilerOptions = Object.keys(options.compilerOptions || {});
|
|
279
|
+
const passedIgnored = passedCompilerOptions.filter((o) => ignoredCompilerOptions.includes(o));
|
|
280
|
+
if (passedIgnored.length) {
|
|
281
|
+
log.warn(
|
|
282
|
+
`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(
|
|
283
|
+
', '
|
|
284
|
+
)}`
|
|
285
|
+
);
|
|
286
|
+
passedIgnored.forEach((ignored) => {
|
|
287
|
+
// @ts-expect-error string access
|
|
288
|
+
delete options.compilerOptions[ignored];
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
295
|
+
*/
|
|
296
|
+
function handleDeprecatedOptions(options) {
|
|
297
|
+
const experimental = /** @type {Record<string, any>} */ (options.experimental);
|
|
298
|
+
if (experimental) {
|
|
299
|
+
for (const promoted of ['prebundleSvelteLibraries', 'inspector', 'dynamicCompileOptions']) {
|
|
300
|
+
if (experimental[promoted]) {
|
|
301
|
+
//@ts-expect-error untyped assign
|
|
302
|
+
options[promoted] = experimental[promoted];
|
|
303
|
+
delete experimental[promoted];
|
|
304
|
+
log.warn(
|
|
305
|
+
`Option "experimental.${promoted}" is no longer experimental and has moved to "${promoted}". Please update your Svelte or Vite config.`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (experimental.generateMissingPreprocessorSourcemaps) {
|
|
310
|
+
log.warn('experimental.generateMissingPreprocessorSourcemaps has been removed.');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* vite passes unresolved `root`option to config hook but we need the resolved value, so do it here
|
|
317
|
+
*
|
|
318
|
+
* @see https://github.com/sveltejs/vite-plugin-svelte/issues/113
|
|
319
|
+
* @see https://github.com/vitejs/vite/blob/43c957de8a99bb326afd732c962f42127b0a4d1e/packages/vite/src/node/config.ts#L293
|
|
320
|
+
*
|
|
321
|
+
* @param {import('vite').UserConfig} viteConfig
|
|
322
|
+
* @returns {string | undefined}
|
|
323
|
+
*/
|
|
324
|
+
function resolveViteRoot(viteConfig) {
|
|
325
|
+
return normalizePath(viteConfig.root ? path.resolve(viteConfig.root) : process.cwd());
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
330
|
+
* @param {import('vite').UserConfig} config
|
|
331
|
+
* @returns {Promise<Partial<import('vite').UserConfig>>}
|
|
332
|
+
*/
|
|
333
|
+
export async function buildExtraViteConfig(options, config) {
|
|
334
|
+
/** @type {Partial<import('vite').UserConfig>} */
|
|
335
|
+
const extraViteConfig = {
|
|
336
|
+
resolve: {
|
|
337
|
+
dedupe: [...SVELTE_IMPORTS]
|
|
338
|
+
}
|
|
339
|
+
// this option is still awaiting a PR in vite to be supported
|
|
340
|
+
// see https://github.com/sveltejs/vite-plugin-svelte/issues/60
|
|
341
|
+
// knownJsSrcExtensions: options.extensions
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const extraSvelteConfig = buildExtraConfigForSvelte(config);
|
|
345
|
+
const extraDepsConfig = await buildExtraConfigForDependencies(options, config);
|
|
346
|
+
// merge extra svelte and deps config, but make sure dep values are not contradicting svelte
|
|
347
|
+
extraViteConfig.optimizeDeps = {
|
|
348
|
+
include: [
|
|
349
|
+
...extraSvelteConfig.optimizeDeps.include,
|
|
350
|
+
...extraDepsConfig.optimizeDeps.include.filter(
|
|
351
|
+
(dep) => !isDepExcluded(dep, extraSvelteConfig.optimizeDeps.exclude)
|
|
352
|
+
)
|
|
353
|
+
],
|
|
354
|
+
exclude: [
|
|
355
|
+
...extraSvelteConfig.optimizeDeps.exclude,
|
|
356
|
+
...extraDepsConfig.optimizeDeps.exclude.filter(
|
|
357
|
+
(dep) => !isDepIncluded(dep, extraSvelteConfig.optimizeDeps.include)
|
|
358
|
+
)
|
|
359
|
+
]
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
extraViteConfig.ssr = {
|
|
363
|
+
external: [
|
|
364
|
+
...extraSvelteConfig.ssr.external,
|
|
365
|
+
...extraDepsConfig.ssr.external.filter(
|
|
366
|
+
(dep) => !isDepNoExternaled(dep, extraSvelteConfig.ssr.noExternal)
|
|
367
|
+
)
|
|
368
|
+
],
|
|
369
|
+
noExternal: [
|
|
370
|
+
...extraSvelteConfig.ssr.noExternal,
|
|
371
|
+
...extraDepsConfig.ssr.noExternal.filter(
|
|
372
|
+
(dep) => !isDepExternaled(dep, extraSvelteConfig.ssr.external)
|
|
373
|
+
)
|
|
374
|
+
]
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// enable hmrPartialAccept if not explicitly disabled
|
|
378
|
+
if (config.experimental?.hmrPartialAccept !== false) {
|
|
379
|
+
log.debug('enabling "experimental.hmrPartialAccept" in vite config', undefined, 'config');
|
|
380
|
+
extraViteConfig.experimental = { hmrPartialAccept: true };
|
|
381
|
+
}
|
|
382
|
+
validateViteConfig(extraViteConfig, config, options);
|
|
383
|
+
return extraViteConfig;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @param {Partial<import('vite').UserConfig>} extraViteConfig
|
|
388
|
+
* @param {import('vite').UserConfig} config
|
|
389
|
+
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
390
|
+
*/
|
|
391
|
+
function validateViteConfig(extraViteConfig, config, options) {
|
|
392
|
+
const { prebundleSvelteLibraries, isBuild } = options;
|
|
393
|
+
if (prebundleSvelteLibraries) {
|
|
394
|
+
/** @type {(option: 'dev' | 'build' | boolean)=> boolean} */
|
|
395
|
+
const isEnabled = (option) => option !== true && option !== (isBuild ? 'build' : 'dev');
|
|
396
|
+
/** @type {(name: string, value: 'dev' | 'build' | boolean, recommendation: string)=> void} */
|
|
397
|
+
const logWarning = (name, value, recommendation) =>
|
|
398
|
+
log.warn.once(
|
|
399
|
+
`Incompatible options: \`prebundleSvelteLibraries: true\` and vite \`${name}: ${JSON.stringify(
|
|
400
|
+
value
|
|
401
|
+
)}\` ${isBuild ? 'during build.' : '.'} ${recommendation}`
|
|
402
|
+
);
|
|
403
|
+
const viteOptimizeDepsDisabled = config.optimizeDeps?.disabled ?? 'build'; // fall back to vite default
|
|
404
|
+
const isOptimizeDepsEnabled = isEnabled(viteOptimizeDepsDisabled);
|
|
405
|
+
if (!isBuild && !isOptimizeDepsEnabled) {
|
|
406
|
+
logWarning(
|
|
407
|
+
'optimizeDeps.disabled',
|
|
408
|
+
viteOptimizeDepsDisabled,
|
|
409
|
+
'Forcing `optimizeDeps.disabled: "build"`. Disable prebundleSvelteLibraries or update your vite config to enable optimizeDeps during dev.'
|
|
410
|
+
);
|
|
411
|
+
if (!extraViteConfig.optimizeDeps) {
|
|
412
|
+
extraViteConfig.optimizeDeps = {};
|
|
413
|
+
}
|
|
414
|
+
extraViteConfig.optimizeDeps.disabled = 'build';
|
|
415
|
+
} else if (isBuild && isOptimizeDepsEnabled) {
|
|
416
|
+
logWarning(
|
|
417
|
+
'optimizeDeps.disabled',
|
|
418
|
+
viteOptimizeDepsDisabled,
|
|
419
|
+
'Disable optimizeDeps or prebundleSvelteLibraries for build if you experience errors.'
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (rolldownVersion && isBuild) {
|
|
424
|
+
// read user config inlineConst value
|
|
425
|
+
const inlineConst =
|
|
426
|
+
//@ts-ignore optimization only exists in vite-8 beta
|
|
427
|
+
config.build?.rolldownOptions?.optimization?.inlineConst ??
|
|
428
|
+
//@ts-ignore optimization only exists in vite-8 beta
|
|
429
|
+
config.build?.rollupOptions?.optimization?.inlineConst;
|
|
430
|
+
|
|
431
|
+
if (inlineConst === false) {
|
|
432
|
+
log.warn(
|
|
433
|
+
'Your rolldown config contains `optimization.inlineConst: false`. This can lead to increased bundle size and leaked server code in client build.'
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* @param {import('../types/options.d.ts').PreResolvedOptions} options
|
|
441
|
+
* @param {import('vite').UserConfig} config
|
|
442
|
+
* @returns {Promise<import('vitefu').CrawlFrameworkPkgsResult>}
|
|
443
|
+
*/
|
|
444
|
+
async function buildExtraConfigForDependencies(options, config) {
|
|
445
|
+
// extra handling for svelte dependencies in the project
|
|
446
|
+
const packagesWithoutSvelteExportsCondition = new Set();
|
|
447
|
+
const depsConfig = await crawlFrameworkPkgs({
|
|
448
|
+
root: options.root,
|
|
449
|
+
workspaceRoot: searchForWorkspaceRoot(options.root),
|
|
450
|
+
isBuild: options.isBuild,
|
|
451
|
+
viteUserConfig: config,
|
|
452
|
+
isFrameworkPkgByJson(pkgJson) {
|
|
453
|
+
let hasSvelteCondition = false;
|
|
454
|
+
if (typeof pkgJson.exports === 'object') {
|
|
455
|
+
// use replacer as a simple way to iterate over nested keys
|
|
456
|
+
JSON.stringify(pkgJson.exports, (key, value) => {
|
|
457
|
+
if (SVELTE_EXPORT_CONDITIONS.includes(key)) {
|
|
458
|
+
hasSvelteCondition = true;
|
|
459
|
+
}
|
|
460
|
+
return value;
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
const hasSvelteField = !!pkgJson.svelte;
|
|
464
|
+
if (hasSvelteField && !hasSvelteCondition) {
|
|
465
|
+
packagesWithoutSvelteExportsCondition.add(`${pkgJson.name}@${pkgJson.version}`);
|
|
466
|
+
}
|
|
467
|
+
return hasSvelteCondition || hasSvelteField;
|
|
468
|
+
},
|
|
469
|
+
isSemiFrameworkPkgByJson(pkgJson) {
|
|
470
|
+
return !!pkgJson.dependencies?.svelte || !!pkgJson.peerDependencies?.svelte;
|
|
471
|
+
},
|
|
472
|
+
isFrameworkPkgByName(pkgName) {
|
|
473
|
+
const isNotSveltePackage = isCommonDepWithoutSvelteField(pkgName);
|
|
474
|
+
if (isNotSveltePackage) {
|
|
475
|
+
return false;
|
|
476
|
+
} else {
|
|
477
|
+
return undefined;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
if (
|
|
482
|
+
!options.isBuild &&
|
|
483
|
+
!options.experimental?.disableSvelteResolveWarnings &&
|
|
484
|
+
packagesWithoutSvelteExportsCondition?.size > 0
|
|
485
|
+
) {
|
|
486
|
+
log.info.once(
|
|
487
|
+
`The following packages have a svelte field in their package.json but no exports condition for svelte.\n\n${[
|
|
488
|
+
...packagesWithoutSvelteExportsCondition
|
|
489
|
+
].join('\n')}\n\nPlease see ${FAQ_LINK_MISSING_EXPORTS_CONDITION} for details.`
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
log.debug('extra config for dependencies generated by vitefu', depsConfig, 'config');
|
|
493
|
+
|
|
494
|
+
if (options.prebundleSvelteLibraries) {
|
|
495
|
+
// prebundling enabled, so we don't need extra dependency excludes
|
|
496
|
+
depsConfig.optimizeDeps.exclude = [];
|
|
497
|
+
// but keep dependency reinclusions of explicit user excludes
|
|
498
|
+
const userExclude = config.optimizeDeps?.exclude;
|
|
499
|
+
depsConfig.optimizeDeps.include = !userExclude
|
|
500
|
+
? []
|
|
501
|
+
: depsConfig.optimizeDeps.include.filter((dep) => {
|
|
502
|
+
// reincludes look like this: foo > bar > baz
|
|
503
|
+
// in case foo or bar are excluded, we have to retain the reinclude even with prebundling
|
|
504
|
+
return (
|
|
505
|
+
dep.includes('>') &&
|
|
506
|
+
dep
|
|
507
|
+
.split('>')
|
|
508
|
+
.slice(0, -1)
|
|
509
|
+
.some((d) => isDepExcluded(d.trim(), userExclude))
|
|
510
|
+
);
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
if (options.disableDependencyReinclusion === true) {
|
|
514
|
+
depsConfig.optimizeDeps.include = depsConfig.optimizeDeps.include.filter(
|
|
515
|
+
(dep) => !dep.includes('>')
|
|
516
|
+
);
|
|
517
|
+
} else if (Array.isArray(options.disableDependencyReinclusion)) {
|
|
518
|
+
const disabledDeps = options.disableDependencyReinclusion;
|
|
519
|
+
depsConfig.optimizeDeps.include = depsConfig.optimizeDeps.include.filter((dep) => {
|
|
520
|
+
if (!dep.includes('>')) return true;
|
|
521
|
+
const trimDep = dep.replace(/\s+/g, '');
|
|
522
|
+
return disabledDeps.some((disabled) => trimDep.includes(`${disabled}>`));
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
log.debug('post-processed extra config for dependencies', depsConfig, 'config');
|
|
527
|
+
|
|
528
|
+
return depsConfig;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* @param {import('vite').UserConfig} config
|
|
533
|
+
* @returns {import('vite').UserConfig & { optimizeDeps: { include: string[], exclude:string[] }, ssr: { noExternal:(string|RegExp)[], external: string[] } } }
|
|
534
|
+
*/
|
|
535
|
+
function buildExtraConfigForSvelte(config) {
|
|
536
|
+
// include svelte imports for optimization unless explicitly excluded
|
|
537
|
+
/** @type {string[]} */
|
|
538
|
+
const include = [];
|
|
539
|
+
/** @type {string[]} */
|
|
540
|
+
const exclude = [];
|
|
541
|
+
if (!isDepExcluded('svelte', config.optimizeDeps?.exclude ?? [])) {
|
|
542
|
+
const svelteImportsToInclude = SVELTE_IMPORTS.filter(
|
|
543
|
+
(si) => !(si.endsWith('/server') || si.includes('/server/'))
|
|
544
|
+
);
|
|
545
|
+
svelteImportsToInclude.push(...SVELTE_RUNTIME_DEPENDENCIES.map((dep) => `svelte > ${dep}`));
|
|
546
|
+
log.debug(
|
|
547
|
+
`adding bare svelte packages and runtime dependencies to optimizeDeps.include: ${svelteImportsToInclude.join(', ')} `,
|
|
548
|
+
undefined,
|
|
549
|
+
'config'
|
|
550
|
+
);
|
|
551
|
+
include.push(...svelteImportsToInclude);
|
|
552
|
+
} else {
|
|
553
|
+
log.debug(
|
|
554
|
+
'"svelte" is excluded in optimizeDeps.exclude, skipped adding it to include.',
|
|
555
|
+
undefined,
|
|
556
|
+
'config'
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
/** @type {(string | RegExp)[]} */
|
|
560
|
+
const noExternal = [];
|
|
561
|
+
/** @type {string[]} */
|
|
562
|
+
const external = [];
|
|
563
|
+
// add svelte to ssr.noExternal unless it is present in ssr.external
|
|
564
|
+
// so it is correctly resolving according to the conditions in sveltes exports map
|
|
565
|
+
if (!isDepExternaled('svelte', config.ssr?.external ?? [])) {
|
|
566
|
+
noExternal.push('svelte', /^svelte\//);
|
|
567
|
+
}
|
|
568
|
+
// esm-env needs to be bundled by default for the development/production condition
|
|
569
|
+
// be properly used by svelte
|
|
570
|
+
if (!isDepExternaled('esm-env', config.ssr?.external ?? [])) {
|
|
571
|
+
noExternal.push('esm-env');
|
|
572
|
+
}
|
|
573
|
+
return { optimizeDeps: { include, exclude }, ssr: { noExternal, external } };
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Mutates `config` to ensure `resolve.mainFields` is set. If unset, it emulates Vite's default fallback.
|
|
578
|
+
* @param {string} name
|
|
579
|
+
* @param {import('vite').EnvironmentOptions} config
|
|
580
|
+
* @param {{ isSsrTargetWebworker?: boolean }} opts
|
|
581
|
+
*/
|
|
582
|
+
export function ensureConfigEnvironmentMainFields(name, config, opts) {
|
|
583
|
+
config.resolve ??= {};
|
|
584
|
+
if (config.resolve.mainFields == null) {
|
|
585
|
+
if (config.consumer === 'client' || name === 'client' || opts.isSsrTargetWebworker) {
|
|
586
|
+
config.resolve.mainFields = [...defaultClientMainFields];
|
|
587
|
+
} else {
|
|
588
|
+
config.resolve.mainFields = [...defaultServerMainFields];
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Mutates `config` to ensure `resolve.conditions` is set. If unset, it emulates Vite's default fallback.
|
|
596
|
+
* @param {string} name
|
|
597
|
+
* @param {import('vite').EnvironmentOptions} config
|
|
598
|
+
* @param {{ isSsrTargetWebworker?: boolean }} opts
|
|
599
|
+
*/
|
|
600
|
+
export function ensureConfigEnvironmentConditions(name, config, opts) {
|
|
601
|
+
config.resolve ??= {};
|
|
602
|
+
if (config.resolve.conditions == null) {
|
|
603
|
+
if (config.consumer === 'client' || name === 'client' || opts.isSsrTargetWebworker) {
|
|
604
|
+
config.resolve.conditions = [...defaultClientConditions];
|
|
605
|
+
} else {
|
|
606
|
+
config.resolve.conditions = [...defaultServerConditions];
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* @template T
|
|
613
|
+
* @param {T | T[] | null | undefined } value
|
|
614
|
+
* @returns {T[]}
|
|
615
|
+
*/
|
|
616
|
+
export function arraify(value) {
|
|
617
|
+
return value == null ? [] : Array.isArray(value) ? value : [value];
|
|
618
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { log } from './log.js';
|
|
2
|
+
import { LINK_TRANSFORM_WITH_PLUGIN } from './constants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
6
|
+
* @param {import('vite').ResolvedConfig} config
|
|
7
|
+
* @returns {{
|
|
8
|
+
* prependPreprocessors: import('@rsvelte/compiler').PreprocessorGroup[],
|
|
9
|
+
* appendPreprocessors: import('@rsvelte/compiler').PreprocessorGroup[]
|
|
10
|
+
* }}
|
|
11
|
+
*/
|
|
12
|
+
function buildExtraPreprocessors(options, config) {
|
|
13
|
+
/** @type {import('@rsvelte/compiler').PreprocessorGroup[]} */
|
|
14
|
+
const prependPreprocessors = [];
|
|
15
|
+
/** @type {import('@rsvelte/compiler').PreprocessorGroup[]} */
|
|
16
|
+
const appendPreprocessors = [];
|
|
17
|
+
|
|
18
|
+
/** @type {import('vite').Plugin[]} */
|
|
19
|
+
const pluginsWithPreprocessors = config.plugins.filter((p) => p?.api?.sveltePreprocess);
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
!options.isBuild &&
|
|
23
|
+
!options.experimental?.disableApiSveltePreprocessWarnings &&
|
|
24
|
+
pluginsWithPreprocessors.length > 0
|
|
25
|
+
) {
|
|
26
|
+
log.info.once(
|
|
27
|
+
`The following plugins use the deprecated 'plugin.api.sveltePreprocess' field: ${pluginsWithPreprocessors
|
|
28
|
+
.map((p) => p.name)
|
|
29
|
+
.join(', ')}
|
|
30
|
+
Please contact their maintainers and ask them to use a vite plugin transform instead.
|
|
31
|
+
See ${LINK_TRANSFORM_WITH_PLUGIN} for more information.
|
|
32
|
+
`.replace(/\t+/g, '\t')
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
/** @type {import('vite').Plugin[]} */
|
|
36
|
+
const ignored = [];
|
|
37
|
+
/** @type {import('vite').Plugin[]} */
|
|
38
|
+
const included = [];
|
|
39
|
+
for (const p of pluginsWithPreprocessors) {
|
|
40
|
+
if (
|
|
41
|
+
options.ignorePluginPreprocessors === true ||
|
|
42
|
+
(Array.isArray(options.ignorePluginPreprocessors) &&
|
|
43
|
+
options.ignorePluginPreprocessors?.includes(p.name))
|
|
44
|
+
) {
|
|
45
|
+
ignored.push(p);
|
|
46
|
+
} else {
|
|
47
|
+
included.push(p);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (ignored.length > 0) {
|
|
51
|
+
log.debug(
|
|
52
|
+
`Ignoring svelte preprocessors defined by these vite plugins: ${ignored
|
|
53
|
+
.map((p) => p.name)
|
|
54
|
+
.join(', ')}`,
|
|
55
|
+
undefined,
|
|
56
|
+
'preprocess'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (included.length > 0) {
|
|
60
|
+
log.debug(
|
|
61
|
+
`Adding svelte preprocessors defined by these vite plugins: ${included
|
|
62
|
+
.map((p) => p.name)
|
|
63
|
+
.join(', ')}`,
|
|
64
|
+
undefined,
|
|
65
|
+
'preprocess'
|
|
66
|
+
);
|
|
67
|
+
appendPreprocessors.push(...pluginsWithPreprocessors.map((p) => p.api.sveltePreprocess));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { prependPreprocessors, appendPreprocessors };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {import('../types/options.d.ts').ResolvedOptions} options
|
|
75
|
+
* @param {import('vite').ResolvedConfig} config
|
|
76
|
+
*/
|
|
77
|
+
export function addExtraPreprocessors(options, config) {
|
|
78
|
+
const { prependPreprocessors, appendPreprocessors } = buildExtraPreprocessors(options, config);
|
|
79
|
+
if (prependPreprocessors.length > 0 || appendPreprocessors.length > 0) {
|
|
80
|
+
if (!options.preprocess) {
|
|
81
|
+
options.preprocess = [...prependPreprocessors, ...appendPreprocessors];
|
|
82
|
+
} else if (Array.isArray(options.preprocess)) {
|
|
83
|
+
options.preprocess.unshift(...prependPreprocessors);
|
|
84
|
+
options.preprocess.push(...appendPreprocessors);
|
|
85
|
+
} else {
|
|
86
|
+
options.preprocess = [...prependPreprocessors, options.preprocess, ...appendPreprocessors];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|