@sveltejs/vite-plugin-svelte 1.0.0-next.28 → 1.0.0-next.31
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/README.md +1 -0
- package/dist/index.cjs +163 -23
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +161 -37
- package/dist/index.js.map +3 -3
- package/package.json +10 -10
- package/src/index.ts +7 -1
- package/src/utils/compile.ts +7 -0
- package/src/utils/error.ts +92 -0
- package/src/utils/esbuild.ts +99 -0
- package/src/utils/log.ts +1 -1
- package/src/utils/options.ts +22 -2
package/src/utils/compile.ts
CHANGED
|
@@ -26,6 +26,13 @@ const _createCompileSvelte = (makeHot: Function) =>
|
|
|
26
26
|
log.debug(`setting cssHash ${hash} for ${normalizedFilename}`);
|
|
27
27
|
compileOptions.cssHash = () => hash;
|
|
28
28
|
}
|
|
29
|
+
if (ssr && compileOptions.enableSourcemap !== false) {
|
|
30
|
+
if (typeof compileOptions.enableSourcemap === 'object') {
|
|
31
|
+
compileOptions.enableSourcemap.css = false;
|
|
32
|
+
} else {
|
|
33
|
+
compileOptions.enableSourcemap = { js: true, css: false };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
29
36
|
|
|
30
37
|
let preprocessed;
|
|
31
38
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { RollupError } from 'rollup';
|
|
2
|
+
import { Warning } from './options';
|
|
3
|
+
import { buildExtendedLogMessage } from './log';
|
|
4
|
+
import { PartialMessage } from 'esbuild';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* convert an error thrown by svelte.compile to a RollupError so that vite displays it in a user friendly way
|
|
8
|
+
* @param error a svelte compiler error, which is a mix of Warning and an error
|
|
9
|
+
* @returns {RollupError} the converted error
|
|
10
|
+
*/
|
|
11
|
+
export function toRollupError(error: Warning & Error): RollupError {
|
|
12
|
+
const { filename, frame, start, code, name } = error;
|
|
13
|
+
const rollupError: RollupError = {
|
|
14
|
+
name, // needed otherwise sveltekit coalesce_to_error turns it into a string
|
|
15
|
+
id: filename,
|
|
16
|
+
message: buildExtendedLogMessage(error), // include filename:line:column so that it's clickable
|
|
17
|
+
frame: formatFrameForVite(frame),
|
|
18
|
+
code,
|
|
19
|
+
stack: ''
|
|
20
|
+
};
|
|
21
|
+
if (start) {
|
|
22
|
+
rollupError.loc = {
|
|
23
|
+
line: start.line,
|
|
24
|
+
column: start.column,
|
|
25
|
+
file: filename
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return rollupError;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* convert an error thrown by svelte.compile to an esbuild PartialMessage
|
|
33
|
+
* @param error a svelte compiler error, which is a mix of Warning and an error
|
|
34
|
+
* @returns {PartialMessage} the converted error
|
|
35
|
+
*/
|
|
36
|
+
export function toESBuildError(error: Warning & Error): PartialMessage {
|
|
37
|
+
const { filename, frame, start } = error;
|
|
38
|
+
const partialMessage: PartialMessage = {
|
|
39
|
+
text: buildExtendedLogMessage(error)
|
|
40
|
+
};
|
|
41
|
+
if (start) {
|
|
42
|
+
partialMessage.location = {
|
|
43
|
+
line: start.line,
|
|
44
|
+
column: start.column,
|
|
45
|
+
file: filename,
|
|
46
|
+
lineText: lineFromFrame(start.line, frame) // needed to get a meaningful error message on cli
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return partialMessage;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* extract line with number from codeframe
|
|
54
|
+
*/
|
|
55
|
+
function lineFromFrame(lineNo: number, frame?: string): string {
|
|
56
|
+
if (!frame) {
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
const lines = frame.split('\n');
|
|
60
|
+
const errorLine = lines.find((line) => line.trimStart().startsWith(`${lineNo}: `));
|
|
61
|
+
return errorLine ? errorLine.substring(errorLine.indexOf(': ') + 3) : '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* vite error overlay expects a specific format to show frames
|
|
66
|
+
* this reformats svelte frame (colon separated, less whitespace)
|
|
67
|
+
* to one that vite displays on overlay ( pipe separated, more whitespace)
|
|
68
|
+
* e.g.
|
|
69
|
+
* ```
|
|
70
|
+
* 1: foo
|
|
71
|
+
* 2: bar;
|
|
72
|
+
* ^
|
|
73
|
+
* 3: baz
|
|
74
|
+
* ```
|
|
75
|
+
* to
|
|
76
|
+
* ```
|
|
77
|
+
* 1 | foo
|
|
78
|
+
* 2 | bar;
|
|
79
|
+
* ^
|
|
80
|
+
* 3 | baz
|
|
81
|
+
* ```
|
|
82
|
+
* @see https://github.com/vitejs/vite/blob/96591bf9989529de839ba89958755eafe4c445ae/packages/vite/src/client/overlay.ts#L116
|
|
83
|
+
*/
|
|
84
|
+
function formatFrameForVite(frame?: string): string {
|
|
85
|
+
if (!frame) {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
return frame
|
|
89
|
+
.split('\n')
|
|
90
|
+
.map((line) => (line.match(/^\s+\^/) ? ' ' + line : ' ' + line.replace(':', ' | ')))
|
|
91
|
+
.join('\n');
|
|
92
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { compile, preprocess } from 'svelte/compiler';
|
|
3
|
+
import { DepOptimizationOptions } from 'vite';
|
|
4
|
+
import { Compiled } from './compile';
|
|
5
|
+
import { log } from './log';
|
|
6
|
+
import { CompileOptions, ResolvedOptions } from './options';
|
|
7
|
+
import { toESBuildError } from './error';
|
|
8
|
+
|
|
9
|
+
type EsbuildOptions = NonNullable<DepOptimizationOptions['esbuildOptions']>;
|
|
10
|
+
type EsbuildPlugin = NonNullable<EsbuildOptions['plugins']>[number];
|
|
11
|
+
type EsbuildPluginBuild = Parameters<EsbuildPlugin['setup']>[0];
|
|
12
|
+
|
|
13
|
+
export function esbuildSveltePlugin(options: ResolvedOptions): EsbuildPlugin {
|
|
14
|
+
return {
|
|
15
|
+
name: 'vite-plugin-svelte:optimize-svelte',
|
|
16
|
+
setup(build) {
|
|
17
|
+
disableVitePrebundleSvelte(build);
|
|
18
|
+
|
|
19
|
+
const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1));
|
|
20
|
+
const svelteFilter = new RegExp(`\\.(` + svelteExtensions.join('|') + `)(\\?.*)?$`);
|
|
21
|
+
|
|
22
|
+
build.onLoad({ filter: svelteFilter }, async ({ path: filename }) => {
|
|
23
|
+
const code = await fs.readFile(filename, 'utf8');
|
|
24
|
+
try {
|
|
25
|
+
const contents = await compileSvelte(options, { filename, code });
|
|
26
|
+
return { contents };
|
|
27
|
+
} catch (e) {
|
|
28
|
+
return { errors: [toESBuildError(e)] };
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function disableVitePrebundleSvelte(build: EsbuildPluginBuild) {
|
|
36
|
+
const viteDepPrebundlePlugin = build.initialOptions.plugins?.find(
|
|
37
|
+
(v) => v.name === 'vite:dep-pre-bundle'
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (!viteDepPrebundlePlugin) return;
|
|
41
|
+
|
|
42
|
+
// Prevent vite:dep-pre-bundle from externalizing svelte files
|
|
43
|
+
const _setup = viteDepPrebundlePlugin.setup.bind(viteDepPrebundlePlugin);
|
|
44
|
+
viteDepPrebundlePlugin.setup = function (build) {
|
|
45
|
+
const _onResolve = build.onResolve.bind(build);
|
|
46
|
+
build.onResolve = function (options, callback) {
|
|
47
|
+
if (options.filter.source.includes('svelte')) {
|
|
48
|
+
options.filter = new RegExp(
|
|
49
|
+
options.filter.source.replace('|svelte', ''),
|
|
50
|
+
options.filter.flags
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return _onResolve(options, callback);
|
|
54
|
+
};
|
|
55
|
+
return _setup(build);
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function compileSvelte(
|
|
60
|
+
options: ResolvedOptions,
|
|
61
|
+
{ filename, code }: { filename: string; code: string }
|
|
62
|
+
): Promise<string> {
|
|
63
|
+
const compileOptions: CompileOptions = {
|
|
64
|
+
...options.compilerOptions,
|
|
65
|
+
css: true,
|
|
66
|
+
filename,
|
|
67
|
+
generate: 'dom'
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
let preprocessed;
|
|
71
|
+
|
|
72
|
+
if (options.preprocess) {
|
|
73
|
+
preprocessed = await preprocess(code, options.preprocess, { filename });
|
|
74
|
+
if (preprocessed.map) compileOptions.sourcemap = preprocessed.map;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const finalCode = preprocessed ? preprocessed.code : code;
|
|
78
|
+
|
|
79
|
+
const dynamicCompileOptions = await options.experimental?.dynamicCompileOptions?.({
|
|
80
|
+
filename,
|
|
81
|
+
code: finalCode,
|
|
82
|
+
compileOptions
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (dynamicCompileOptions && log.debug.enabled) {
|
|
86
|
+
log.debug(`dynamic compile options for ${filename}: ${JSON.stringify(dynamicCompileOptions)}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const finalCompileOptions = dynamicCompileOptions
|
|
90
|
+
? {
|
|
91
|
+
...compileOptions,
|
|
92
|
+
...dynamicCompileOptions
|
|
93
|
+
}
|
|
94
|
+
: compileOptions;
|
|
95
|
+
|
|
96
|
+
const compiled = compile(finalCode, finalCompileOptions) as Compiled;
|
|
97
|
+
|
|
98
|
+
return compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl();
|
|
99
|
+
}
|
package/src/utils/log.ts
CHANGED
|
@@ -155,7 +155,7 @@ function warnBuild(w: Warning) {
|
|
|
155
155
|
log.warn.enabled && log.warn(buildExtendedLogMessage(w), w.frame);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function buildExtendedLogMessage(w: Warning) {
|
|
158
|
+
export function buildExtendedLogMessage(w: Warning) {
|
|
159
159
|
const parts = [];
|
|
160
160
|
if (w.filename) {
|
|
161
161
|
parts.push(w.filename);
|
package/src/utils/options.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import path from 'path';
|
|
16
16
|
import { findRootSvelteDependencies, needsOptimization, SvelteDependency } from './dependencies';
|
|
17
17
|
import { createRequire } from 'module';
|
|
18
|
+
import { esbuildSveltePlugin } from './esbuild';
|
|
18
19
|
|
|
19
20
|
const knownOptions = new Set([
|
|
20
21
|
'configFile',
|
|
@@ -217,8 +218,6 @@ function buildOptimizeDepsForSvelte(
|
|
|
217
218
|
options: ResolvedOptions,
|
|
218
219
|
optimizeDeps?: DepOptimizationOptions
|
|
219
220
|
): DepOptimizationOptions {
|
|
220
|
-
// only svelte component libraries needs to be processed for optimizeDeps, js libraries work fine
|
|
221
|
-
svelteDeps = svelteDeps.filter((dep) => dep.type === 'component-library');
|
|
222
221
|
// include svelte imports for optimization unless explicitly excluded
|
|
223
222
|
const include: string[] = [];
|
|
224
223
|
const exclude: string[] = ['svelte-hmr'];
|
|
@@ -241,6 +240,20 @@ function buildOptimizeDepsForSvelte(
|
|
|
241
240
|
log.debug('"svelte" is excluded in optimizeDeps.exclude, skipped adding it to include.');
|
|
242
241
|
}
|
|
243
242
|
|
|
243
|
+
// If we prebundle svelte libraries, we can skip the whole prebundling dance below
|
|
244
|
+
if (options.experimental.prebundleSvelteLibraries) {
|
|
245
|
+
return {
|
|
246
|
+
include,
|
|
247
|
+
exclude,
|
|
248
|
+
esbuildOptions: {
|
|
249
|
+
plugins: [esbuildSveltePlugin(options)]
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// only svelte component libraries needs to be processed for optimizeDeps, js libraries work fine
|
|
255
|
+
svelteDeps = svelteDeps.filter((dep) => dep.type === 'component-library');
|
|
256
|
+
|
|
244
257
|
const svelteDepsToExclude = Array.from(new Set(svelteDeps.map((dep) => dep.name))).filter(
|
|
245
258
|
(dep) => !isIncluded(dep)
|
|
246
259
|
);
|
|
@@ -420,6 +433,13 @@ export interface ExperimentalOptions {
|
|
|
420
433
|
*/
|
|
421
434
|
useVitePreprocess?: boolean;
|
|
422
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Force Vite to pre-bundle Svelte libraries
|
|
438
|
+
*
|
|
439
|
+
* @default false
|
|
440
|
+
*/
|
|
441
|
+
prebundleSvelteLibraries?: boolean;
|
|
442
|
+
|
|
423
443
|
/**
|
|
424
444
|
* If a preprocessor does not provide a sourcemap, a best-effort fallback sourcemap will be provided.
|
|
425
445
|
* This option requires `diff-match-patch` to be installed as a peer dependency.
|