@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.
@@ -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);
@@ -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.