@sveltejs/vite-plugin-svelte 2.4.5 → 2.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/vite-plugin-svelte",
3
- "version": "2.4.5",
3
+ "version": "2.5.0",
4
4
  "license": "MIT",
5
5
  "author": "dominikg",
6
6
  "files": [
@@ -34,22 +34,22 @@
34
34
  },
35
35
  "homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
36
36
  "dependencies": {
37
+ "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4",
37
38
  "debug": "^4.3.4",
38
39
  "deepmerge": "^4.3.1",
39
40
  "kleur": "^4.1.5",
40
- "magic-string": "^0.30.2",
41
+ "magic-string": "^0.30.3",
41
42
  "svelte-hmr": "^0.15.3",
42
- "vitefu": "^0.2.4",
43
- "@sveltejs/vite-plugin-svelte-inspector": "^1.0.3"
43
+ "vitefu": "^0.2.4"
44
44
  },
45
45
  "peerDependencies": {
46
- "svelte": "^3.54.0 || ^4.0.0",
46
+ "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-next.0",
47
47
  "vite": "^4.0.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/debug": "^4.1.8",
51
- "esbuild": "^0.19.0",
52
- "svelte": "^4.1.2",
51
+ "esbuild": "^0.19.3",
52
+ "svelte": "^4.2.0",
53
53
  "vite": "^4.4.9"
54
54
  },
55
55
  "scripts": {
package/src/index.d.ts CHANGED
@@ -170,6 +170,16 @@ interface ExperimentalOptions {
170
170
  * @default false
171
171
  */
172
172
  disableSvelteResolveWarnings?: boolean;
173
+ /**
174
+ * Options for compiling Svelte JS/TS modules
175
+ */
176
+ compileModule?: CompileModuleOptions;
177
+ }
178
+
179
+ interface CompileModuleOptions {
180
+ extensions?: string[];
181
+ include?: Arrayable<string>;
182
+ exclude?: Arrayable<string>;
173
183
  }
174
184
 
175
185
  type ModuleFormat = NonNullable<'esm'>;
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import fs from 'fs';
1
+ import fs from 'node:fs';
2
2
  import { version as viteVersion } from 'vite';
3
+ import * as svelteCompiler from 'svelte/compiler';
3
4
 
4
5
  import { svelteInspector } from '@sveltejs/vite-plugin-svelte-inspector';
5
6
 
@@ -7,7 +8,7 @@ import { isDepExcluded } from 'vitefu';
7
8
  import { handleHotUpdate } from './handle-hot-update.js';
8
9
  import { log, logCompilerWarnings } from './utils/log.js';
9
10
  import { createCompileSvelte } from './utils/compile.js';
10
- import { buildIdParser } from './utils/id.js';
11
+ import { buildIdParser, buildModuleIdParser } from './utils/id.js';
11
12
  import {
12
13
  buildExtraViteConfig,
13
14
  validateInlineOptions,
@@ -24,7 +25,7 @@ import { saveSvelteMetadata } from './utils/optimizer.js';
24
25
  import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache.js';
25
26
  import { loadRaw } from './utils/load-raw.js';
26
27
  import { FAQ_LINK_CONFLICTS_IN_SVELTE_RESOLVE } from './utils/constants.js';
27
- import { isSvelte3 } from './utils/svelte-version.js';
28
+ import { isSvelte3, isSvelte5 } from './utils/svelte-version.js';
28
29
 
29
30
  const isVite4_0 = viteVersion.startsWith('4.0');
30
31
 
@@ -38,6 +39,8 @@ export function svelte(inlineOptions) {
38
39
  // updated in configResolved hook
39
40
  /** @type {import('./types/id.d.ts').IdParser} */
40
41
  let requestParser;
42
+ /** @type {import('./types/id.d.ts').ModuleIdParser} */
43
+ let moduleRequestParser;
41
44
  /** @type {import('./types/options.d.ts').ResolvedOptions} */
42
45
  let options;
43
46
  /** @type {import('vite').ResolvedConfig} */
@@ -268,9 +271,45 @@ export function svelte(inlineOptions) {
268
271
  );
269
272
  }
270
273
  }
271
- },
272
- svelteInspector()
274
+ }
273
275
  ];
276
+
277
+ if (!isSvelte5) {
278
+ plugins.push(svelteInspector()); // TODO reenable once svelte5 has support
279
+ }
280
+ if (isSvelte5) {
281
+ log.warn(
282
+ 'svelte 5 support in v-p-s is experimental, breaking changes can occur in any release until this notice is removed'
283
+ );
284
+ log.warn('svelte 5 does not support svelte-inspector yet, disabling it');
285
+ // TODO move to separate file
286
+ plugins.push({
287
+ name: 'vite-plugin-svelte-module',
288
+ enforce: 'post',
289
+ async configResolved() {
290
+ moduleRequestParser = buildModuleIdParser(options);
291
+ },
292
+ async transform(code, id, opts) {
293
+ const ssr = !!opts?.ssr;
294
+ const moduleRequest = moduleRequestParser(id, ssr);
295
+ if (!moduleRequest) {
296
+ return;
297
+ }
298
+ try {
299
+ // @ts-ignore doesn't exist in Svelte 4
300
+ const compileResult = await svelteCompiler.compileModule(code, {
301
+ generate: ssr ? 'ssr' : 'dom',
302
+ filename: moduleRequest.filename
303
+ });
304
+ logCompilerWarnings(moduleRequest, compileResult.warnings, options);
305
+ return compileResult.js;
306
+ } catch (e) {
307
+ throw toRollupError(e, options);
308
+ }
309
+ }
310
+ });
311
+ }
312
+
274
313
  return plugins;
275
314
  }
276
315
 
@@ -19,7 +19,7 @@ export interface Compiled {
19
19
  css: Code;
20
20
  ast: any; // TODO type
21
21
  warnings: any[]; // TODO type
22
- vars: {
22
+ vars: Array<{
23
23
  name: string;
24
24
  export_name: string;
25
25
  injected: boolean;
@@ -29,7 +29,7 @@ export interface Compiled {
29
29
  referenced: boolean;
30
30
  writable: boolean;
31
31
  referenced_from_script: boolean;
32
- }[];
32
+ }>;
33
33
  stats: {
34
34
  timings: {
35
35
  total: number;
package/src/types/id.d.ts CHANGED
@@ -28,4 +28,19 @@ export interface SvelteRequest {
28
28
  raw: boolean;
29
29
  }
30
30
 
31
+ export interface SvelteModuleRequest {
32
+ id: string;
33
+ filename: string;
34
+ normalizedFilename: string;
35
+ query: RequestQuery;
36
+ timestamp: number;
37
+ ssr: boolean;
38
+ }
39
+
31
40
  export type IdParser = (id: string, ssr: boolean, timestamp?: number) => SvelteRequest | undefined;
41
+
42
+ export type ModuleIdParser = (
43
+ id: string,
44
+ ssr: boolean,
45
+ timestamp?: number
46
+ ) => SvelteModuleRequest | undefined;
@@ -1,4 +1,4 @@
1
- import { compile, preprocess, walk } from 'svelte/compiler';
1
+ import * as svelte from 'svelte/compiler';
2
2
  // @ts-ignore
3
3
  import { createMakeHot } from 'svelte-hmr';
4
4
  import { safeBase64Hash } from './hash.js';
@@ -86,7 +86,7 @@ export const _createCompileSvelte = (makeHot) => {
86
86
  }
87
87
  if (preprocessors) {
88
88
  try {
89
- preprocessed = await preprocess(code, preprocessors, { filename }); // full filename here so postcss works
89
+ preprocessed = await svelte.preprocess(code, preprocessors, { filename }); // full filename here so postcss works
90
90
  } catch (e) {
91
91
  e.message = `Error while preprocessing ${filename}${e.message ? ` - ${e.message}` : ''}`;
92
92
  throw e;
@@ -123,7 +123,7 @@ export const _createCompileSvelte = (makeHot) => {
123
123
  : compileOptions;
124
124
 
125
125
  const endStat = stats?.start(filename);
126
- const compiled = compile(finalCode, finalCompileOptions);
126
+ const compiled = svelte.compile(finalCode, finalCompileOptions);
127
127
 
128
128
  if (isSvelte3) {
129
129
  // prevent dangling pure comments
@@ -187,7 +187,8 @@ function buildMakeHot(options) {
187
187
  // @ts-ignore
188
188
  const adapter = options?.hot?.adapter;
189
189
  return createMakeHot({
190
- walk,
190
+ // TODO Svelte 5 doesn't expose walk anymore. If we decide to make v-p-s 2 work with Svelte 5 HMR, we need to import walk from estree-walker
191
+ walk: svelte.walk,
191
192
  hotApi,
192
193
  adapter,
193
194
  hotOptions: { noOverlay: true, .../** @type {object} */ (options.hot) }
@@ -1,5 +1,5 @@
1
- import path from 'path';
2
- import fs from 'fs/promises';
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
3
  import { findDepPkgJsonPath } from 'vitefu';
4
4
 
5
5
  /**
@@ -1,8 +1,8 @@
1
- import { readFileSync } from 'fs';
2
- import { compile, preprocess } from 'svelte/compiler';
1
+ import { readFileSync } from 'node:fs';
2
+ import * as svelte from 'svelte/compiler';
3
3
  import { log } from './log.js';
4
4
  import { toESBuildError } from './error.js';
5
- import { isSvelte3 } from './svelte-version.js';
5
+ import { isSvelte3, isSvelte5 } from './svelte-version.js';
6
6
 
7
7
  /**
8
8
  * @typedef {NonNullable<import('vite').DepOptimizationOptions['esbuildOptions']>} EsbuildOptions
@@ -11,6 +11,8 @@ import { isSvelte3 } from './svelte-version.js';
11
11
 
12
12
  export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade';
13
13
 
14
+ const svelteModuleExtension = '.svelte.js';
15
+
14
16
  /**
15
17
  * @param {import('../types/options.d.ts').ResolvedOptions} options
16
18
  * @returns {EsbuildPlugin}
@@ -24,7 +26,10 @@ export function esbuildSveltePlugin(options) {
24
26
  if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
25
27
 
26
28
  const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1));
27
- const svelteFilter = new RegExp(`\\.(` + svelteExtensions.join('|') + `)(\\?.*)?$`);
29
+ if (isSvelte5) {
30
+ svelteExtensions.push(svelteModuleExtension.slice(1));
31
+ }
32
+ const svelteFilter = new RegExp('\\.(' + svelteExtensions.join('|') + ')(\\?.*)?$');
28
33
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
29
34
  let statsCollection;
30
35
  build.onStart(() => {
@@ -55,6 +60,22 @@ export function esbuildSveltePlugin(options) {
55
60
  * @returns {Promise<string>}
56
61
  */
57
62
  async function compileSvelte(options, { filename, code }, statsCollection) {
63
+ if (isSvelte5 && filename.endsWith(svelteModuleExtension)) {
64
+ const endStat = statsCollection?.start(filename);
65
+ // @ts-ignore doesn't exist in Svelte 4
66
+ const compiled = svelte.compileModule(code, {
67
+ filename,
68
+ generate: 'dom',
69
+ runes: true
70
+ });
71
+ if (endStat) {
72
+ endStat();
73
+ }
74
+ return compiled.js.map
75
+ ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
76
+ : compiled.js.code;
77
+ }
78
+
58
79
  let css = options.compilerOptions.css;
59
80
  if (css !== 'none') {
60
81
  // TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
@@ -75,7 +96,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
75
96
 
76
97
  if (options.preprocess) {
77
98
  try {
78
- preprocessed = await preprocess(code, options.preprocess, { filename });
99
+ preprocessed = await svelte.preprocess(code, options.preprocess, { filename });
79
100
  } catch (e) {
80
101
  e.message = `Error while preprocessing ${filename}${e.message ? ` - ${e.message}` : ''}`;
81
102
  throw e;
@@ -102,9 +123,11 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
102
123
  }
103
124
  : compileOptions;
104
125
  const endStat = statsCollection?.start(filename);
105
- const compiled = compile(finalCode, finalCompileOptions);
126
+ const compiled = svelte.compile(finalCode, finalCompileOptions);
106
127
  if (endStat) {
107
128
  endStat();
108
129
  }
109
- return compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl();
130
+ return compiled.js.map
131
+ ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
132
+ : compiled.js.code;
110
133
  }
package/src/utils/hash.js CHANGED
@@ -1,4 +1,4 @@
1
- import * as crypto from 'crypto';
1
+ import * as crypto from 'node:crypto';
2
2
 
3
3
  const hashes = Object.create(null);
4
4
 
package/src/utils/id.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createFilter, normalizePath } from 'vite';
2
- import * as fs from 'fs';
2
+ import * as fs from 'node:fs';
3
3
  import { log } from './log.js';
4
4
 
5
5
  const VITE_FS_PREFIX = '/@fs/';
@@ -21,7 +21,7 @@ const TYPES_WITH_COMPILER_OPTIONS = ['style', 'script', 'all'];
21
21
  * @returns {{ filename: string, rawQuery: string }}
22
22
  */
23
23
  function splitId(id) {
24
- const parts = id.split(`?`, 2);
24
+ const parts = id.split('?', 2);
25
25
  const filename = parts[0];
26
26
  const rawQuery = parts[1];
27
27
  return { filename, rawQuery };
@@ -184,3 +184,48 @@ export function buildIdParser(options) {
184
184
  }
185
185
  };
186
186
  }
187
+ /**
188
+ * @param {import('../types/options.d.ts').ResolvedOptions} options
189
+ * @returns {import('../types/id.d.ts').ModuleIdParser}
190
+ */
191
+ export function buildModuleIdParser(options) {
192
+ const { include, exclude, extensions } = options?.experimental?.compileModule ?? {};
193
+ const root = options.root;
194
+ const normalizedRoot = normalizePath(root);
195
+ const filter = buildFilter(include, exclude, extensions ?? ['.svelte.js', '.svelte.ts']);
196
+ return (id, ssr, timestamp = Date.now()) => {
197
+ const { filename, rawQuery } = splitId(id);
198
+ if (filter(filename)) {
199
+ return parseToSvelteModuleRequest(id, filename, rawQuery, normalizedRoot, timestamp, ssr);
200
+ }
201
+ };
202
+ }
203
+
204
+ /**
205
+ * @param {string} id
206
+ * @param {string} filename
207
+ * @param {string} rawQuery
208
+ * @param {string} root
209
+ * @param {number} timestamp
210
+ * @param {boolean} ssr
211
+ * @returns {import('../types/id.d.ts').SvelteModuleRequest | undefined}
212
+ */
213
+ function parseToSvelteModuleRequest(id, filename, rawQuery, root, timestamp, ssr) {
214
+ const query = parseRequestQuery(rawQuery);
215
+
216
+ if (query.url || query.raw || query.direct) {
217
+ // skip requests with special vite tags
218
+ return;
219
+ }
220
+
221
+ const normalizedFilename = normalize(filename, root);
222
+
223
+ return {
224
+ id,
225
+ filename,
226
+ normalizedFilename,
227
+ query,
228
+ timestamp,
229
+ ssr
230
+ };
231
+ }
@@ -1,4 +1,4 @@
1
- import fs from 'fs';
1
+ import fs from 'node:fs';
2
2
  import { toRollupError } from './error.js';
3
3
  import { log } from './log.js';
4
4
 
@@ -126,7 +126,7 @@ function toRawExports(object) {
126
126
  .map(([key, value]) => `export const ${key}=${JSON.stringify(value)}`)
127
127
  .join('\n') + '\n';
128
128
  if (Object.prototype.hasOwnProperty.call(object, 'code')) {
129
- exports += `export default code\n`;
129
+ exports += 'export default code\n';
130
130
  }
131
131
  return exports;
132
132
  }
@@ -1,7 +1,7 @@
1
- import { createRequire } from 'module';
2
- import path from 'path';
3
- import fs from 'fs';
4
- import { pathToFileURL } from 'url';
1
+ import { createRequire } from 'node:module';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { pathToFileURL } from 'node:url';
5
5
  import { log } from './log.js';
6
6
 
7
7
  // used to require cjs config in esm.
package/src/utils/log.js CHANGED
@@ -120,7 +120,7 @@ export const log = {
120
120
  };
121
121
 
122
122
  /**
123
- * @param {import('../types/id.d.ts').SvelteRequest} svelteRequest
123
+ * @param {import('../types/id.d.ts').SvelteRequest | import('../types/id.d.ts').SvelteModuleRequest} svelteRequest
124
124
  * @param {import('svelte/types/compiler/interfaces').Warning[]} warnings
125
125
  * @param {import('../types/options.d.ts').ResolvedOptions} options
126
126
  */
@@ -204,7 +204,8 @@ function buildExtraWarnings(warnings, isBuild) {
204
204
  extraWarnings.push({
205
205
  ...noScopableElementWarning,
206
206
  code: 'vite-plugin-svelte-css-no-scopable-elements',
207
- message: `No scopable elements found in template. If you're using global styles in the style tag, you should move it into an external stylesheet file and import it in JS. See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#where-should-i-put-my-global-styles.`
207
+ message:
208
+ "No scopable elements found in template. If you're using global styles in the style tag, you should move it into an external stylesheet file and import it in JS. See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#where-should-i-put-my-global-styles."
208
209
  });
209
210
  }
210
211
  }
@@ -1,5 +1,5 @@
1
- import { promises as fs } from 'fs';
2
- import path from 'path';
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
3
 
4
4
  // List of options that changes the prebundling result
5
5
  /** @type {(keyof import('../types/options.d.ts').ResolvedOptions)[]} */
@@ -10,7 +10,7 @@ import {
10
10
  VITE_RESOLVE_MAIN_FIELDS
11
11
  } from './constants.js';
12
12
 
13
- import path from 'path';
13
+ import path from 'node:path';
14
14
  import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild.js';
15
15
  import { addExtraPreprocessors } from './preprocess.js';
16
16
  import deepmerge from 'deepmerge';
@@ -25,6 +25,7 @@ import {
25
25
  import { isCommonDepWithoutSvelteField } from './dependencies.js';
26
26
  import { VitePluginSvelteStats } from './vite-plugin-svelte-stats.js';
27
27
  import { VitePluginSvelteCache } from './vite-plugin-svelte-cache.js';
28
+ import { isSvelte5 } from './svelte-version.js';
28
29
 
29
30
  const allowedPluginOptions = new Set([
30
31
  'include',
@@ -227,6 +228,10 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
227
228
  * @param {import('../types/options.d.ts').ResolvedOptions} options
228
229
  */
229
230
  function enforceOptionsForHmr(options) {
231
+ if (isSvelte5) {
232
+ log.warn('svelte 5 does not support hmr api yet, disabling it for now');
233
+ options.hot = false;
234
+ }
230
235
  if (options.hot) {
231
236
  if (!options.compilerOptions.dev) {
232
237
  log.warn('hmr is enabled but compilerOptions.dev is false, forcing it to true');
@@ -1,6 +1,6 @@
1
1
  import MagicString from 'magic-string';
2
2
  import { log } from './log.js';
3
- import path from 'path';
3
+ import path from 'node:path';
4
4
 
5
5
  /**
6
6
  * this appends a *{} rule to component styles to force the svelte compiler to add style classes to all nodes
@@ -1,5 +1,5 @@
1
- import path from 'path';
2
- import { builtinModules } from 'module';
1
+ import path from 'node:path';
2
+ import { builtinModules } from 'node:module';
3
3
  import { resolveDependencyData, isCommonDepWithoutSvelteField } from './dependencies.js';
4
4
  import { normalizePath } from 'vite';
5
5
 
@@ -1,4 +1,4 @@
1
- import path from 'path';
1
+ import path from 'node:path';
2
2
 
3
3
  const IS_WINDOWS = process.platform === 'win32';
4
4
 
@@ -4,3 +4,8 @@ import { VERSION } from 'svelte/compiler';
4
4
  * @type {boolean}
5
5
  */
6
6
  export const isSvelte3 = VERSION.startsWith('3.');
7
+
8
+ /**
9
+ * @type {boolean}
10
+ */
11
+ export const isSvelte5 = VERSION.startsWith('5.');
@@ -1,5 +1,5 @@
1
- import { readFileSync } from 'fs';
2
- import { dirname } from 'path';
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
3
  import { findClosestPkgJsonPath } from 'vitefu';
4
4
  import { normalizePath } from 'vite';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { log } from './log.js';
2
- import { performance } from 'perf_hooks';
2
+ import { performance } from 'node:perf_hooks';
3
3
  import { normalizePath } from 'vite';
4
4
 
5
5
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').CollectionOptions} */
@@ -1,7 +1,7 @@
1
- import fs from 'fs';
1
+ import fs from 'node:fs';
2
2
  import { log } from './log.js';
3
3
  import { knownSvelteConfigNames } from './load-svelte-config.js';
4
- import path from 'path';
4
+ import path from 'node:path';
5
5
 
6
6
  /**
7
7
  * @param {import('../types/options.d.ts').ResolvedOptions} options