@sveltejs/vite-plugin-svelte 2.2.0 → 2.4.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.
Files changed (44) hide show
  1. package/package.json +12 -17
  2. package/src/{handle-hot-update.ts → handle-hot-update.js} +35 -20
  3. package/src/index.d.ts +215 -0
  4. package/src/{index.ts → index.js} +50 -71
  5. package/src/{preprocess.ts → preprocess.js} +37 -28
  6. package/src/types/compile.d.ts +48 -0
  7. package/src/types/id.d.ts +31 -0
  8. package/src/types/log.d.ts +24 -0
  9. package/src/types/options.d.ts +20 -0
  10. package/src/types/plugin-api.d.ts +11 -0
  11. package/src/types/vite-plugin-svelte-stats.d.ts +30 -0
  12. package/src/utils/{compile.ts → compile.js} +32 -66
  13. package/src/utils/{dependencies.ts → dependencies.js} +14 -11
  14. package/src/utils/{error.ts → error.js} +21 -14
  15. package/src/utils/{esbuild.ts → esbuild.js} +23 -17
  16. package/src/utils/{hash.ts → hash.js} +14 -3
  17. package/src/utils/{id.ts → id.js} +59 -60
  18. package/src/utils/{load-raw.ts → load-raw.js} +16 -16
  19. package/src/utils/{load-svelte-config.ts → load-svelte-config.js} +12 -10
  20. package/src/utils/{log.ts → log.js} +81 -48
  21. package/src/utils/{optimizer.ts → optimizer.js} +15 -7
  22. package/src/utils/{options.ts → options.js} +146 -295
  23. package/src/utils/{preprocess.ts → preprocess.js} +28 -12
  24. package/src/utils/{resolve.ts → resolve.js} +18 -9
  25. package/src/utils/{sourcemaps.ts → sourcemaps.js} +22 -14
  26. package/src/utils/{svelte-version.ts → svelte-version.js} +15 -7
  27. package/src/utils/vite-plugin-svelte-cache.js +253 -0
  28. package/src/utils/{vite-plugin-svelte-stats.ts → vite-plugin-svelte-stats.js} +66 -62
  29. package/src/utils/{watch.ts → watch.js} +30 -22
  30. package/dist/index.d.ts +0 -259
  31. package/dist/index.js +0 -2428
  32. package/dist/index.js.map +0 -1
  33. package/src/__tests__/fixtures/preprocess/foo.scss +0 -3
  34. package/src/__tests__/preprocess.spec.ts +0 -51
  35. package/src/ui/inspector/Inspector.svelte +0 -384
  36. package/src/ui/inspector/load-inspector.js +0 -15
  37. package/src/ui/inspector/options.ts +0 -131
  38. package/src/ui/inspector/plugin.ts +0 -97
  39. package/src/ui/inspector/utils.ts +0 -13
  40. package/src/utils/__tests__/compile.spec.ts +0 -49
  41. package/src/utils/__tests__/sourcemaps.spec.ts +0 -79
  42. package/src/utils/__tests__/svelte-version.spec.ts +0 -102
  43. package/src/utils/vite-plugin-svelte-cache.ts +0 -182
  44. /package/src/utils/{constants.ts → constants.js} +0 -0
@@ -1,7 +1,5 @@
1
- import type { ResolvedConfig, Plugin } from 'vite';
2
1
  import MagicString from 'magic-string';
3
- import { PreprocessorGroup, ResolvedOptions } from './options';
4
- import { log } from './log';
2
+ import { log } from './log.js';
5
3
  import path from 'path';
6
4
 
7
5
  /**
@@ -9,8 +7,10 @@ import path from 'path';
9
7
  * That means adding/removing class rules from <style> node won't trigger js updates as the scope classes are not changed
10
8
  *
11
9
  * only used during dev with enabled css hmr
10
+ *
11
+ * @returns {import('svelte/types/compiler/preprocess').PreprocessorGroup}
12
12
  */
13
- export function createInjectScopeEverythingRulePreprocessorGroup(): PreprocessorGroup {
13
+ export function createInjectScopeEverythingRulePreprocessorGroup() {
14
14
  return {
15
15
  style({ content, filename }) {
16
16
  const s = new MagicString(content);
@@ -26,9 +26,19 @@ export function createInjectScopeEverythingRulePreprocessorGroup(): Preprocessor
26
26
  };
27
27
  }
28
28
 
29
- function buildExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfig) {
30
- const prependPreprocessors: PreprocessorGroup[] = [];
31
- const appendPreprocessors: PreprocessorGroup[] = [];
29
+ /**
30
+ * @param {import('../types/options.d.ts').ResolvedOptions} options
31
+ * @param {import('vite').ResolvedConfig} config
32
+ * @returns {{
33
+ * prependPreprocessors: import('svelte/types/compiler/preprocess').PreprocessorGroup[],
34
+ * appendPreprocessors: import('svelte/types/compiler/preprocess').PreprocessorGroup[]
35
+ * }}
36
+ */
37
+ function buildExtraPreprocessors(options, config) {
38
+ /** @type {import('svelte/types/compiler/preprocess').PreprocessorGroup[]} */
39
+ const prependPreprocessors = [];
40
+ /** @type {import('svelte/types/compiler/preprocess').PreprocessorGroup[]} */
41
+ const appendPreprocessors = [];
32
42
 
33
43
  // @ts-ignore
34
44
  const pluginsWithPreprocessorsDeprecated = config.plugins.filter((p) => p?.sveltePreprocess);
@@ -53,10 +63,12 @@ function buildExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfi
53
63
  }
54
64
  });
55
65
  }
56
-
57
- const pluginsWithPreprocessors: Plugin[] = config.plugins.filter((p) => p?.api?.sveltePreprocess);
58
- const ignored: Plugin[] = [],
59
- included: Plugin[] = [];
66
+ /** @type {import('vite').Plugin[]} */
67
+ const pluginsWithPreprocessors = config.plugins.filter((p) => p?.api?.sveltePreprocess);
68
+ /** @type {import('vite').Plugin[]} */
69
+ const ignored = [];
70
+ /** @type {import('vite').Plugin[]} */
71
+ const included = [];
60
72
  for (const p of pluginsWithPreprocessors) {
61
73
  if (
62
74
  options.ignorePluginPreprocessors === true ||
@@ -87,7 +99,11 @@ function buildExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfi
87
99
  return { prependPreprocessors, appendPreprocessors };
88
100
  }
89
101
 
90
- export function addExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfig) {
102
+ /**
103
+ * @param {import('../types/options.d.ts').ResolvedOptions} options
104
+ * @param {import('vite').ResolvedConfig} config
105
+ */
106
+ export function addExtraPreprocessors(options, config) {
91
107
  const { prependPreprocessors, appendPreprocessors } = buildExtraPreprocessors(options, config);
92
108
  if (prependPreprocessors.length > 0 || appendPreprocessors.length > 0) {
93
109
  if (!options.preprocess) {
@@ -1,14 +1,15 @@
1
1
  import path from 'path';
2
2
  import { builtinModules } from 'module';
3
- import { resolveDependencyData, isCommonDepWithoutSvelteField } from './dependencies';
4
- import { VitePluginSvelteCache } from './vite-plugin-svelte-cache';
3
+ import { resolveDependencyData, isCommonDepWithoutSvelteField } from './dependencies.js';
5
4
  import { normalizePath } from 'vite';
6
5
 
7
- export async function resolveViaPackageJsonSvelte(
8
- importee: string,
9
- importer: string | undefined,
10
- cache: VitePluginSvelteCache
11
- ): Promise<string | void> {
6
+ /**
7
+ * @param {string} importee
8
+ * @param {string | undefined} importer
9
+ * @param {import('./vite-plugin-svelte-cache').VitePluginSvelteCache} cache
10
+ * @returns {Promise<string | void>}
11
+ */
12
+ export async function resolveViaPackageJsonSvelte(importee, importer, cache) {
12
13
  if (
13
14
  importer &&
14
15
  isBareImport(importee) &&
@@ -31,11 +32,19 @@ export async function resolveViaPackageJsonSvelte(
31
32
  }
32
33
  }
33
34
 
34
- function isNodeInternal(importee: string) {
35
+ /**
36
+ * @param {string} importee
37
+ * @returns {boolean}
38
+ */
39
+ function isNodeInternal(importee) {
35
40
  return importee.startsWith('node:') || builtinModules.includes(importee);
36
41
  }
37
42
 
38
- function isBareImport(importee: string): boolean {
43
+ /**
44
+ * @param {string} importee
45
+ * @returns {boolean}
46
+ */
47
+ function isBareImport(importee) {
39
48
  if (
40
49
  !importee ||
41
50
  importee[0] === '.' ||
@@ -1,30 +1,37 @@
1
1
  import path from 'path';
2
+
2
3
  const IS_WINDOWS = process.platform === 'win32';
3
- interface SourceMapFileRefs {
4
- file?: string;
5
- sources?: string[];
6
- sourceRoot?: string;
7
- }
4
+
5
+ /**
6
+ * @typedef {{
7
+ * file?: string;
8
+ * sources?: string[];
9
+ * sourceRoot?: string;
10
+ * }} SourceMapFileRefs
11
+ */
8
12
 
9
13
  /**
10
14
  * convert absolute paths in sourcemap file refs to their relative equivalents to avoid leaking fs info
11
15
  *
12
16
  * map is modified in place.
13
17
  *
14
- * @param map sourcemap
15
- * @param filename absolute path to file the sourcemap is for
18
+ * @param {SourceMapFileRefs | undefined} map sourcemap
19
+ * @param {string} filename absolute path to file the sourcemap is for
16
20
  */
17
- export function mapToRelative(map: SourceMapFileRefs | undefined, filename: string) {
21
+ export function mapToRelative(map, filename) {
18
22
  if (!map) {
19
23
  return;
20
24
  }
21
25
  const sourceRoot = map.sourceRoot;
22
26
  const dirname = path.dirname(filename);
23
- const toRelative = (s: string) => {
27
+
28
+ /** @type {(s: string) => string} */
29
+ const toRelative = (s) => {
24
30
  if (!s) {
25
31
  return s;
26
32
  }
27
- let sourcePath: string;
33
+ /** @type {string} */
34
+ let sourcePath;
28
35
  if (s.startsWith('file:///')) {
29
36
  // windows has file:///C:/foo and posix has file:///foo, so we have to remove one extra on windows
30
37
  sourcePath = s.slice(IS_WINDOWS ? 8 : 7);
@@ -56,14 +63,15 @@ export function mapToRelative(map: SourceMapFileRefs | undefined, filename: stri
56
63
  *
57
64
  * map is modified in place.
58
65
  *
59
- * @param map the output sourcemap
60
- * @param suffix the suffix to remove
66
+ * @param {SourceMapFileRefs | undefined} map the output sourcemap
67
+ * @param {string} suffix the suffix to remove
61
68
  */
62
- export function removeLangSuffix(map: SourceMapFileRefs | undefined, suffix: string) {
69
+ export function removeLangSuffix(map, suffix) {
63
70
  if (!map) {
64
71
  return;
65
72
  }
66
- const removeSuffix = (s: string) => (s?.endsWith(suffix) ? s.slice(0, -1 * suffix.length) : s);
73
+ /** @type {(s:string)=> string} */
74
+ const removeSuffix = (s) => (s?.endsWith(suffix) ? s.slice(0, -1 * suffix.length) : s);
67
75
  if (map.file) {
68
76
  map.file = removeSuffix(map.file);
69
77
  }
@@ -1,7 +1,11 @@
1
1
  import { VERSION } from 'svelte/compiler';
2
2
  const svelteVersion = parseVersion(VERSION);
3
3
 
4
- export function parseVersion(version: string): number[] {
4
+ /**
5
+ * @param {string} version
6
+ * @returns {number[]}
7
+ */
8
+ export function parseVersion(version) {
5
9
  const segments = version.split('.', 3).map((s) => parseInt(s, 10));
6
10
  while (segments.length < 3) {
7
11
  segments.push(0);
@@ -12,10 +16,11 @@ export function parseVersion(version: string): number[] {
12
16
  /**
13
17
  * compare version with current svelte, only takes major.minor.patch into account.
14
18
  * If you don't pass all three, values will be filled with 0, ie `3` is equal to `3.0.0`
15
- * @param version
16
- * @returns 1 if passed version is larger than current, 0 if it is equal and -1 if it is lower
19
+ *
20
+ * @param {string} version
21
+ * @returns {1 | 0 | -1} 1 if passed version is larger than current, 0 if it is equal and -1 if it is lower
17
22
  */
18
- export function compareToSvelte(version: string): 1 | 0 | -1 {
23
+ export function compareToSvelte(version) {
19
24
  const parsedVersion = parseVersion(version);
20
25
  for (let i = 0; i < svelteVersion.length; i++) {
21
26
  const a = parsedVersion[i];
@@ -31,7 +36,10 @@ export function compareToSvelte(version: string): 1 | 0 | -1 {
31
36
  return 0;
32
37
  }
33
38
 
34
- export function atLeastSvelte(version: string) {
35
- const result = compareToSvelte(version) <= 0;
36
- return result;
39
+ /**
40
+ * @param {string} version
41
+ * @returns {boolean}
42
+ */
43
+ export function atLeastSvelte(version) {
44
+ return compareToSvelte(version) <= 0;
37
45
  }
@@ -0,0 +1,253 @@
1
+ import { readFileSync } from 'fs';
2
+ import { dirname } from 'path';
3
+ import { findClosestPkgJsonPath } from 'vitefu';
4
+ import { normalizePath } from 'vite';
5
+
6
+ /**
7
+ * @typedef {{
8
+ * name: string;
9
+ * version: string;
10
+ * svelte?: string;
11
+ * path: string;
12
+ * }} PackageInfo
13
+ */
14
+
15
+ /**
16
+ * @class
17
+ */
18
+ export class VitePluginSvelteCache {
19
+ /** @type {Map<string, import('../types/compile.d.ts').Code>} */
20
+ #css = new Map();
21
+ /** @type {Map<string, import('../types/compile.d.ts').Code>} */
22
+ #js = new Map();
23
+ /** @type {Map<string, string[]>} */
24
+ #dependencies = new Map();
25
+ /** @type {Map<string, Set<string>>} */
26
+ #dependants = new Map();
27
+ /** @type {Map<string, string>} */
28
+ #resolvedSvelteFields = new Map();
29
+ /** @type {Map<string, any>} */
30
+ #errors = new Map();
31
+ /** @type {PackageInfo[]} */
32
+ #packageInfos = [];
33
+
34
+ /**
35
+ * @param {import('../types/compile.d.ts').CompileData} compileData
36
+ */
37
+ update(compileData) {
38
+ this.#errors.delete(compileData.normalizedFilename);
39
+ this.#updateCSS(compileData);
40
+ this.#updateJS(compileData);
41
+ this.#updateDependencies(compileData);
42
+ }
43
+
44
+ /**
45
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
46
+ * @returns {boolean}
47
+ */
48
+ has(svelteRequest) {
49
+ const id = svelteRequest.normalizedFilename;
50
+ return this.#errors.has(id) || this.#js.has(id) || this.#css.has(id);
51
+ }
52
+
53
+ /**
54
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
55
+ * @param {any} error
56
+ */
57
+ setError(svelteRequest, error) {
58
+ // keep dependency info, otherwise errors in dependants would not trigger an update after fixing
59
+ // because they are no longer watched
60
+ this.remove(svelteRequest, true);
61
+ this.#errors.set(svelteRequest.normalizedFilename, error);
62
+ }
63
+
64
+ /**
65
+ * @param {import('../types/compile.d.ts').CompileData} compileData
66
+ */
67
+ #updateCSS(compileData) {
68
+ this.#css.set(compileData.normalizedFilename, compileData.compiled.css);
69
+ }
70
+
71
+ /**
72
+ * @param {import('../types/compile.d.ts').CompileData} compileData
73
+ */
74
+ #updateJS(compileData) {
75
+ if (!compileData.ssr) {
76
+ // do not cache SSR js
77
+ this.#js.set(compileData.normalizedFilename, compileData.compiled.js);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {import('../types/compile.d.ts').CompileData} compileData
83
+ */
84
+ #updateDependencies(compileData) {
85
+ const id = compileData.normalizedFilename;
86
+ const prevDependencies = this.#dependencies.get(id) || [];
87
+ const dependencies = compileData.dependencies;
88
+ this.#dependencies.set(id, dependencies);
89
+ const removed = prevDependencies.filter((d) => !dependencies.includes(d));
90
+ const added = dependencies.filter((d) => !prevDependencies.includes(d));
91
+ added.forEach((d) => {
92
+ if (!this.#dependants.has(d)) {
93
+ this.#dependants.set(d, new Set());
94
+ }
95
+ /** @type {Set<string>} */ (this.#dependants.get(d)).add(compileData.filename);
96
+ });
97
+ removed.forEach((d) => {
98
+ /** @type {Set<string>} */ (this.#dependants.get(d)).delete(compileData.filename);
99
+ });
100
+ }
101
+
102
+ /**
103
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
104
+ * @param {boolean} [keepDependencies]
105
+ * @returns {boolean}
106
+ */
107
+ remove(svelteRequest, keepDependencies = false) {
108
+ const id = svelteRequest.normalizedFilename;
109
+ let removed = false;
110
+ if (this.#errors.delete(id)) {
111
+ removed = true;
112
+ }
113
+ if (this.#js.delete(id)) {
114
+ removed = true;
115
+ }
116
+ if (this.#css.delete(id)) {
117
+ removed = true;
118
+ }
119
+ if (!keepDependencies) {
120
+ const dependencies = this.#dependencies.get(id);
121
+ if (dependencies) {
122
+ removed = true;
123
+ dependencies.forEach((d) => {
124
+ const dependants = this.#dependants.get(d);
125
+ if (dependants && dependants.has(svelteRequest.filename)) {
126
+ dependants.delete(svelteRequest.filename);
127
+ }
128
+ });
129
+ this.#dependencies.delete(id);
130
+ }
131
+ }
132
+
133
+ return removed;
134
+ }
135
+
136
+ /**
137
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
138
+ * @returns {import('../types/compile.d.ts').Code | undefined}
139
+ */
140
+ getCSS(svelteRequest) {
141
+ return this.#css.get(svelteRequest.normalizedFilename);
142
+ }
143
+
144
+ /**
145
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
146
+ * @returns {import('../types/compile.d.ts').Code | undefined}
147
+ */
148
+ getJS(svelteRequest) {
149
+ if (!svelteRequest.ssr) {
150
+ // SSR js isn't cached
151
+ return this.#js.get(svelteRequest.normalizedFilename);
152
+ }
153
+ }
154
+ /**
155
+ * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
156
+ * @returns {any}
157
+ */
158
+ getError(svelteRequest) {
159
+ return this.#errors.get(svelteRequest.normalizedFilename);
160
+ }
161
+
162
+ /**
163
+ * @param {string} path
164
+ * @returns {string[]}
165
+ */
166
+ getDependants(path) {
167
+ const dependants = this.#dependants.get(path);
168
+ return dependants ? [...dependants] : [];
169
+ }
170
+
171
+ /**
172
+ * @param {string} name
173
+ * @param {string} [importer]
174
+ * @returns {string|void}
175
+ */
176
+ getResolvedSvelteField(name, importer) {
177
+ return this.#resolvedSvelteFields.get(this.#getResolvedSvelteFieldKey(name, importer));
178
+ }
179
+
180
+ /**
181
+ * @param {string} name
182
+ * @param {string} [importer]
183
+ * @returns {boolean}
184
+ */
185
+ hasResolvedSvelteField(name, importer) {
186
+ return this.#resolvedSvelteFields.has(this.#getResolvedSvelteFieldKey(name, importer));
187
+ }
188
+ /**
189
+ *
190
+ * @param {string} importee
191
+ * @param {string | undefined} importer
192
+ * @param {string} resolvedSvelte
193
+ */
194
+ setResolvedSvelteField(importee, importer, resolvedSvelte) {
195
+ this.#resolvedSvelteFields.set(
196
+ this.#getResolvedSvelteFieldKey(importee, importer),
197
+ resolvedSvelte
198
+ );
199
+ }
200
+
201
+ /**
202
+ * @param {string} importee
203
+ * @param {string | undefined} importer
204
+ * @returns {string}
205
+ */
206
+ #getResolvedSvelteFieldKey(importee, importer) {
207
+ return importer ? `${importer} > ${importee}` : importee;
208
+ }
209
+
210
+ /**
211
+ * @param {string} file
212
+ * @returns {Promise<PackageInfo>}
213
+ */
214
+ async getPackageInfo(file) {
215
+ let info = this.#packageInfos.find((pi) => file.startsWith(pi.path));
216
+ if (!info) {
217
+ info = await findPackageInfo(file);
218
+ this.#packageInfos.push(info);
219
+ }
220
+ return info;
221
+ }
222
+ }
223
+
224
+ /**
225
+ * utility to get some info from the closest package.json with a "name" set
226
+ *
227
+ * @param {string} file to find info for
228
+ * @returns {Promise<PackageInfo>}
229
+ */
230
+ async function findPackageInfo(file) {
231
+ /** @type {PackageInfo} */
232
+ const info = {
233
+ name: '$unknown',
234
+ version: '0.0.0-unknown',
235
+ path: '$unknown'
236
+ };
237
+ let path = await findClosestPkgJsonPath(file, (pkgPath) => {
238
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
239
+ if (pkg.name != null) {
240
+ info.name = pkg.name;
241
+ if (pkg.version != null) {
242
+ info.version = pkg.version;
243
+ }
244
+ info.svelte = pkg.svelte;
245
+ return true;
246
+ }
247
+ return false;
248
+ });
249
+ // return normalized path with appended '/' so .startsWith works for future file checks
250
+ path = normalizePath(dirname(path ?? file)) + '/';
251
+ info.path = path;
252
+ return info;
253
+ }