@sveltejs/vite-plugin-svelte 1.0.0-next.46 → 1.0.0-next.49

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/vite-plugin-svelte",
3
- "version": "1.0.0-next.46",
3
+ "version": "1.0.0-next.49",
4
4
  "license": "MIT",
5
5
  "author": "dominikg",
6
6
  "files": [
@@ -59,18 +59,19 @@
59
59
  }
60
60
  },
61
61
  "devDependencies": {
62
+ "@sveltejs/kit": "^1.0.0-next.350",
62
63
  "@types/debug": "^4.1.7",
63
64
  "@types/diff-match-patch": "^1.0.32",
64
65
  "diff-match-patch": "^1.0.5",
65
- "esbuild": "^0.14.39",
66
- "rollup": "^2.74.1",
66
+ "esbuild": "^0.14.42",
67
+ "rollup": "^2.75.5",
67
68
  "svelte": "^3.48.0",
68
- "tsup": "^5.12.8",
69
- "vite": "^2.9.9"
69
+ "tsup": "^6.1.0",
70
+ "vite": "^2.9.10"
70
71
  },
71
72
  "scripts": {
72
73
  "dev": "pnpm build:ci --sourcemap --watch src",
73
- "build:ci": "rimraf dist && tsup-node src/index.ts --format esm,cjs --no-splitting --target node14",
74
+ "build:ci": "rimraf dist && tsup-node src/index.ts --format esm,cjs --no-splitting --shims",
74
75
  "build": "pnpm build:ci --dts --sourcemap"
75
76
  }
76
77
  }
@@ -15,19 +15,25 @@ export async function handleHotUpdate(
15
15
  cache: VitePluginSvelteCache,
16
16
  options: ResolvedOptions
17
17
  ): Promise<ModuleNode[] | void> {
18
- const { read, server } = ctx;
19
-
20
- const cachedJS = cache.getJS(svelteRequest);
21
- if (!cachedJS) {
18
+ if (!cache.has(svelteRequest)) {
22
19
  // file hasn't been requested yet (e.g. async component)
23
- log.debug(`handleHotUpdate first call ${svelteRequest.id}`);
20
+ log.debug(`handleHotUpdate called before initial transform for ${svelteRequest.id}`);
24
21
  return;
25
22
  }
23
+ const { read, server } = ctx;
24
+
25
+ const cachedJS = cache.getJS(svelteRequest);
26
26
  const cachedCss = cache.getCSS(svelteRequest);
27
27
 
28
28
  const content = await read();
29
- const compileData: CompileData = await compileSvelte(svelteRequest, content, options);
30
- cache.update(compileData);
29
+ let compileData: CompileData;
30
+ try {
31
+ compileData = await compileSvelte(svelteRequest, content, options);
32
+ cache.update(compileData);
33
+ } catch (e) {
34
+ cache.setError(svelteRequest, e);
35
+ throw e;
36
+ }
31
37
 
32
38
  const affectedModules = new Set<ModuleNode | undefined>();
33
39
 
@@ -35,19 +41,19 @@ export async function handleHotUpdate(
35
41
  const mainModule = server.moduleGraph.getModuleById(svelteRequest.id);
36
42
  const cssUpdated = cssModule && cssChanged(cachedCss, compileData.compiled.css);
37
43
  if (cssUpdated) {
38
- log.debug('handleHotUpdate css changed');
44
+ log.debug(`handleHotUpdate css changed for ${svelteRequest.cssId}`);
39
45
  affectedModules.add(cssModule);
40
46
  }
41
47
  const jsUpdated =
42
48
  mainModule && jsChanged(cachedJS, compileData.compiled.js, svelteRequest.filename);
43
49
  if (jsUpdated) {
44
- log.debug('handleHotUpdate js changed');
50
+ log.debug(`handleHotUpdate js changed for ${svelteRequest.id}`);
45
51
  affectedModules.add(mainModule);
46
52
  }
47
53
 
48
54
  if (!jsUpdated) {
49
55
  // transform won't be called, log warnings here
50
- logCompilerWarnings(compileData.compiled.warnings, options);
56
+ logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options);
51
57
  }
52
58
 
53
59
  const result = [...affectedModules].filter(Boolean) as ModuleNode[];
package/src/index.ts CHANGED
@@ -183,9 +183,10 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin[] {
183
183
  try {
184
184
  compileData = await compileSvelte(svelteRequest, code, options);
185
185
  } catch (e) {
186
+ cache.setError(svelteRequest, e);
186
187
  throw toRollupError(e, options);
187
188
  }
188
- logCompilerWarnings(compileData.compiled.warnings, options);
189
+ logCompilerWarnings(svelteRequest, compileData.compiled.warnings, options);
189
190
  cache.update(compileData);
190
191
  if (compileData.dependencies?.length && options.server) {
191
192
  compileData.dependencies.forEach((d) => {
@@ -209,7 +210,11 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin[] {
209
210
  }
210
211
  const svelteRequest = requestParser(ctx.file, false, ctx.timestamp);
211
212
  if (svelteRequest) {
212
- return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options);
213
+ try {
214
+ return handleHotUpdate(compileSvelte, ctx, svelteRequest, cache, options);
215
+ } catch (e) {
216
+ throw toRollupError(e, options);
217
+ }
213
218
  }
214
219
  }
215
220
  }
@@ -218,6 +223,8 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin[] {
218
223
  return plugins.filter(Boolean);
219
224
  }
220
225
 
226
+ export { loadSvelteConfig } from './utils/load-svelte-config';
227
+
221
228
  export {
222
229
  Options,
223
230
  Preprocessor,
@@ -230,3 +237,5 @@ export {
230
237
  Processed,
231
238
  Warning
232
239
  } from './utils/options';
240
+
241
+ export { SvelteWarningsMessage } from './utils/log';
@@ -127,6 +127,7 @@ function isSvelteLib(pkg: Pkg) {
127
127
 
128
128
  const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
129
129
  '@lukeed/uuid',
130
+ '@playwright/test',
130
131
  '@sveltejs/vite-plugin-svelte',
131
132
  '@sveltejs/kit',
132
133
  'autoprefixer',
@@ -136,6 +137,7 @@ const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
136
137
  'eslint',
137
138
  'jest',
138
139
  'mdsvex',
140
+ 'playwright',
139
141
  'postcss',
140
142
  'prettier',
141
143
  'svelte',
@@ -144,7 +146,9 @@ const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
144
146
  'svelte-preprocess',
145
147
  'tslib',
146
148
  'typescript',
147
- 'vite'
149
+ 'vite',
150
+ 'vitest',
151
+ '__vite-browser-external' // see https://github.com/sveltejs/vite-plugin-svelte/issues/362
148
152
  ];
149
153
  const COMMON_PREFIXES_WITHOUT_SVELTE_FIELD = [
150
154
  '@fontsource/',
@@ -22,14 +22,15 @@ export const knownSvelteConfigNames = [
22
22
  // also use timestamp query to avoid caching on reload
23
23
  const dynamicImportDefault = new Function(
24
24
  'path',
25
- 'return import(path + "?t=" + Date.now()).then(m => m.default)'
25
+ 'timestamp',
26
+ 'return import(path + "?t=" + timestamp).then(m => m.default)'
26
27
  );
27
28
 
28
29
  export async function loadSvelteConfig(
29
- viteConfig: UserConfig,
30
- inlineOptions: Partial<Options>
30
+ viteConfig?: UserConfig,
31
+ inlineOptions?: Partial<Options>
31
32
  ): Promise<Partial<Options> | undefined> {
32
- if (inlineOptions.configFile === false) {
33
+ if (inlineOptions?.configFile === false) {
33
34
  return;
34
35
  }
35
36
  const configFile = findConfigToLoad(viteConfig, inlineOptions);
@@ -38,7 +39,10 @@ export async function loadSvelteConfig(
38
39
  // try to use dynamic import for svelte.config.js first
39
40
  if (configFile.endsWith('.js') || configFile.endsWith('.mjs')) {
40
41
  try {
41
- const result = await dynamicImportDefault(pathToFileURL(configFile).href);
42
+ const result = await dynamicImportDefault(
43
+ pathToFileURL(configFile).href,
44
+ fs.statSync(configFile).mtimeMs
45
+ );
42
46
  if (result != null) {
43
47
  return {
44
48
  ...result,
@@ -83,9 +87,9 @@ export async function loadSvelteConfig(
83
87
  }
84
88
  }
85
89
 
86
- function findConfigToLoad(viteConfig: UserConfig, inlineOptions: Partial<Options>) {
87
- const root = viteConfig.root || process.cwd();
88
- if (inlineOptions.configFile) {
90
+ function findConfigToLoad(viteConfig?: UserConfig, inlineOptions?: Partial<Options>) {
91
+ const root = viteConfig?.root || process.cwd();
92
+ if (inlineOptions?.configFile) {
89
93
  const abolutePath = path.isAbsolute(inlineOptions.configFile)
90
94
  ? inlineOptions.configFile
91
95
  : path.resolve(root, inlineOptions.configFile);
package/src/utils/log.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  import { cyan, yellow, red } from 'kleur/colors';
3
3
  import debug from 'debug';
4
4
  import { ResolvedOptions, Warning } from './options';
5
+ import { SvelteRequest } from './id';
5
6
 
6
7
  const levels: string[] = ['debug', 'info', 'warn', 'error', 'silent'];
7
8
  const prefix = 'vite-plugin-svelte';
@@ -99,18 +100,55 @@ export const log = {
99
100
  setLevel
100
101
  };
101
102
 
102
- export function logCompilerWarnings(warnings: Warning[], options: ResolvedOptions) {
103
+ export type SvelteWarningsMessage = {
104
+ id: string;
105
+ filename: string;
106
+ normalizedFilename: string;
107
+ timestamp: number;
108
+ warnings: Warning[]; // allWarnings filtered by warnings where onwarn did not call the default handler
109
+ allWarnings: Warning[]; // includes warnings filtered by onwarn and our extra vite plugin svelte warnings
110
+ rawWarnings: Warning[]; // raw compiler output
111
+ };
112
+
113
+ export function logCompilerWarnings(
114
+ svelteRequest: SvelteRequest,
115
+ warnings: Warning[],
116
+ options: ResolvedOptions
117
+ ) {
103
118
  const { emitCss, onwarn, isBuild } = options;
104
- const warn = isBuild ? warnBuild : warnDev;
105
- const notIgnoredWarnings = warnings?.filter((w) => !ignoreCompilerWarning(w, isBuild, emitCss));
106
- const extraWarnings = buildExtraWarnings(warnings, isBuild);
107
- [...notIgnoredWarnings, ...extraWarnings].forEach((warning) => {
119
+ const sendViaWS = !isBuild && options.experimental?.sendWarningsToBrowser;
120
+ let warn = isBuild ? warnBuild : warnDev;
121
+ const handledByDefaultWarn: Warning[] = [];
122
+ const notIgnored = warnings?.filter((w) => !ignoreCompilerWarning(w, isBuild, emitCss));
123
+ const extra = buildExtraWarnings(warnings, isBuild);
124
+ const allWarnings = [...notIgnored, ...extra];
125
+ if (sendViaWS) {
126
+ const _warn = warn;
127
+ warn = (w: Warning) => {
128
+ handledByDefaultWarn.push(w);
129
+ _warn(w);
130
+ };
131
+ }
132
+ allWarnings.forEach((warning) => {
108
133
  if (onwarn) {
109
134
  onwarn(warning, warn);
110
135
  } else {
111
136
  warn(warning);
112
137
  }
113
138
  });
139
+ if (sendViaWS) {
140
+ const message: SvelteWarningsMessage = {
141
+ id: svelteRequest.id,
142
+ filename: svelteRequest.filename,
143
+ normalizedFilename: svelteRequest.normalizedFilename,
144
+ timestamp: svelteRequest.timestamp,
145
+ warnings: handledByDefaultWarn, // allWarnings filtered by warnings where onwarn did not call the default handler
146
+ allWarnings, // includes warnings filtered by onwarn and our extra vite plugin svelte warnings
147
+ rawWarnings: warnings // raw compiler output
148
+ };
149
+ log.debug(`sending svelte:warnings message for ${svelteRequest.normalizedFilename}`);
150
+ options.server?.ws?.send('svelte:warnings', message);
151
+ }
114
152
  }
115
153
 
116
154
  function ignoreCompilerWarning(
@@ -11,14 +11,16 @@ import { log } from './log';
11
11
  import { loadSvelteConfig } from './load-svelte-config';
12
12
  import { SVELTE_HMR_IMPORTS, SVELTE_IMPORTS, SVELTE_RESOLVE_MAIN_FIELDS } from './constants';
13
13
  // eslint-disable-next-line node/no-missing-import
14
- import { CompileOptions, Warning } from 'svelte/types/compiler/interfaces';
15
- import {
14
+ import type { CompileOptions, Warning } from 'svelte/types/compiler/interfaces';
15
+ import type {
16
16
  MarkupPreprocessor,
17
17
  Preprocessor,
18
18
  PreprocessorGroup,
19
19
  Processed
20
20
  // eslint-disable-next-line node/no-missing-import
21
21
  } from 'svelte/types/compiler/preprocess';
22
+ // eslint-disable-next-line node/no-missing-import
23
+ import type { KitConfig } from '@sveltejs/kit';
22
24
  import path from 'path';
23
25
  import { findRootSvelteDependencies, needsOptimization, SvelteDependency } from './dependencies';
24
26
  import { createRequire } from 'module';
@@ -76,7 +78,6 @@ export async function preResolveOptions(
76
78
  inlineOptions,
77
79
  extraOptions
78
80
  );
79
-
80
81
  // configFile of svelteConfig contains the absolute path it was loaded from,
81
82
  // prefer it over the possibly relative inline path
82
83
  if (svelteConfig?.configFile) {
@@ -116,6 +117,7 @@ export function resolveOptions(
116
117
  const merged: ResolvedOptions = mergeConfigs(defaultOptions, preResolveOptions, extraOptions);
117
118
 
118
119
  removeIgnoredOptions(merged);
120
+ addSvelteKitOptions(merged);
119
121
  addExtraPreprocessors(merged, viteConfig);
120
122
  enforceOptionsForHmr(merged);
121
123
  enforceOptionsForProduction(merged);
@@ -195,6 +197,23 @@ function removeIgnoredOptions(options: ResolvedOptions) {
195
197
  }
196
198
  }
197
199
 
200
+ // some SvelteKit options need compilerOptions to work, so set them here.
201
+ function addSvelteKitOptions(options: ResolvedOptions) {
202
+ if (options?.kit != null) {
203
+ const hydratable = options.kit.browser?.hydrate !== false;
204
+ if (
205
+ options.compilerOptions.hydratable != null &&
206
+ options.compilerOptions.hydratable !== hydratable
207
+ ) {
208
+ log.warn(
209
+ `Conflicting values "compilerOptions.hydratable: ${options.compilerOptions.hydratable}" and "kit.browser.hydrate: ${options.kit.browser?.hydrate}" in your svelte config. You should remove "compilerOptions.hydratable".`
210
+ );
211
+ }
212
+ log.debug(`Setting compilerOptions.hydratable: ${hydratable} for SvelteKit`);
213
+ options.compilerOptions.hydratable = hydratable;
214
+ }
215
+ }
216
+
198
217
  // vite passes unresolved `root`option to config hook but we need the resolved value, so do it here
199
218
  // https://github.com/sveltejs/vite-plugin-svelte/issues/113
200
219
  // https://github.com/vitejs/vite/blob/43c957de8a99bb326afd732c962f42127b0a4d1e/packages/vite/src/node/config.ts#L293
@@ -476,6 +495,11 @@ export interface Options {
476
495
  * These options are considered experimental and breaking changes to them can occur in any release
477
496
  */
478
497
  experimental?: ExperimentalOptions;
498
+
499
+ /**
500
+ * Options for SvelteKit
501
+ */
502
+ kit?: KitConfig;
479
503
  }
480
504
 
481
505
  /**
@@ -536,6 +560,12 @@ export interface ExperimentalOptions {
536
560
  * enable svelte inspector
537
561
  */
538
562
  inspector?: InspectorOptions | boolean;
563
+
564
+ /**
565
+ * send a websocket message with svelte compiler warnings during dev
566
+ *
567
+ */
568
+ sendWarningsToBrowser?: boolean;
539
569
  }
540
570
 
541
571
  export interface InspectorOptions {
@@ -585,7 +615,7 @@ export interface InspectorOptions {
585
615
  export interface PreResolvedOptions extends Options {
586
616
  // these options are non-nullable after resolve
587
617
  compilerOptions: CompileOptions;
588
- experimental: ExperimentalOptions;
618
+ experimental?: ExperimentalOptions;
589
619
  // extra options
590
620
  root: string;
591
621
  isBuild: boolean;
@@ -7,13 +7,27 @@ export class VitePluginSvelteCache {
7
7
  private _dependencies = new Map<string, string[]>();
8
8
  private _dependants = new Map<string, Set<string>>();
9
9
  private _resolvedSvelteFields = new Map<string, string>();
10
+ private _errors = new Map<string, any>();
10
11
 
11
12
  public update(compileData: CompileData) {
13
+ this._errors.delete(compileData.normalizedFilename);
12
14
  this.updateCSS(compileData);
13
15
  this.updateJS(compileData);
14
16
  this.updateDependencies(compileData);
15
17
  }
16
18
 
19
+ public has(svelteRequest: SvelteRequest) {
20
+ const id = svelteRequest.normalizedFilename;
21
+ return this._errors.has(id) || this._js.has(id) || this._css.has(id);
22
+ }
23
+
24
+ public setError(svelteRequest: SvelteRequest, error: any) {
25
+ // keep dependency info, otherwise errors in dependants would not trigger an update after fixing
26
+ // because they are no longer watched
27
+ this.remove(svelteRequest, true);
28
+ this._errors.set(svelteRequest.normalizedFilename, error);
29
+ }
30
+
17
31
  private updateCSS(compileData: CompileData) {
18
32
  this._css.set(compileData.normalizedFilename, compileData.compiled.css);
19
33
  }
@@ -43,26 +57,32 @@ export class VitePluginSvelteCache {
43
57
  });
44
58
  }
45
59
 
46
- public remove(svelteRequest: SvelteRequest): boolean {
60
+ public remove(svelteRequest: SvelteRequest, keepDependencies: boolean = false): boolean {
47
61
  const id = svelteRequest.normalizedFilename;
48
62
  let removed = false;
63
+ if (this._errors.delete(id)) {
64
+ removed = true;
65
+ }
49
66
  if (this._js.delete(id)) {
50
67
  removed = true;
51
68
  }
52
69
  if (this._css.delete(id)) {
53
70
  removed = true;
54
71
  }
55
- const dependencies = this._dependencies.get(id);
56
- if (dependencies) {
57
- removed = true;
58
- dependencies.forEach((d) => {
59
- const dependants = this._dependants.get(d);
60
- if (dependants && dependants.has(svelteRequest.filename)) {
61
- dependants.delete(svelteRequest.filename);
62
- }
63
- });
64
- this._dependencies.delete(id);
72
+ if (!keepDependencies) {
73
+ const dependencies = this._dependencies.get(id);
74
+ if (dependencies) {
75
+ removed = true;
76
+ dependencies.forEach((d) => {
77
+ const dependants = this._dependants.get(d);
78
+ if (dependants && dependants.has(svelteRequest.filename)) {
79
+ dependants.delete(svelteRequest.filename);
80
+ }
81
+ });
82
+ this._dependencies.delete(id);
83
+ }
65
84
  }
85
+
66
86
  return removed;
67
87
  }
68
88
 
@@ -77,6 +97,10 @@ export class VitePluginSvelteCache {
77
97
  }
78
98
  }
79
99
 
100
+ public getError(svelteRequest: SvelteRequest) {
101
+ return this._errors.get(svelteRequest.normalizedFilename);
102
+ }
103
+
80
104
  public getDependants(path: string): string[] {
81
105
  const dependants = this._dependants.get(path);
82
106
  return dependants ? [...dependants] : [];