@sveltejs/vite-plugin-svelte 4.0.0-next.0 → 4.0.0-next.2

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": "4.0.0-next.0",
3
+ "version": "4.0.0-next.2",
4
4
  "license": "MIT",
5
5
  "author": "dominikg",
6
6
  "files": [
@@ -36,12 +36,12 @@
36
36
  },
37
37
  "homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
38
38
  "dependencies": {
39
+ "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0||^3.0.0",
39
40
  "debug": "^4.3.4",
40
41
  "deepmerge": "^4.3.1",
41
42
  "kleur": "^4.1.5",
42
43
  "magic-string": "^0.30.10",
43
- "vitefu": "^0.2.5",
44
- "@sveltejs/vite-plugin-svelte-inspector": "^3.0.0-next.0"
44
+ "vitefu": "^0.2.5"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "svelte": "^5.0.0-next.96 || ^5.0.0",
@@ -49,9 +49,9 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/debug": "^4.1.12",
52
- "esbuild": "^0.20.2",
53
- "sass": "^1.76.0",
54
- "svelte": "^5.0.0-next.123",
52
+ "esbuild": "^0.21.3",
53
+ "sass": "^1.77.2",
54
+ "svelte": "^5.0.0-next.141",
55
55
  "vite": "^5.2.11"
56
56
  },
57
57
  "scripts": {
package/src/index.js CHANGED
@@ -200,6 +200,7 @@ export function svelte(inlineOptions) {
200
200
  }
201
201
  try {
202
202
  const compileResult = svelteCompiler.compileModule(code, {
203
+ dev: !viteConfig.isProduction,
203
204
  generate: ssr ? 'server' : 'client',
204
205
  filename: moduleRequest.filename
205
206
  });
package/src/preprocess.js CHANGED
@@ -61,29 +61,16 @@ function viteScript() {
61
61
  * @returns {{ style: import('svelte/compiler').Preprocessor }}
62
62
  */
63
63
  function viteStyle(config = {}) {
64
- /** @type {CssTransform} */
65
- let transform;
64
+ /** @type {Promise<CssTransform> | CssTransform} */
65
+ let cssTransform;
66
66
  /** @type {import('svelte/compiler').Preprocessor} */
67
67
  const style = async ({ attributes, content, filename = '' }) => {
68
68
  const ext = attributes.lang ? `.${attributes.lang}` : '.css';
69
69
  if (attributes.lang && !isCSSRequest(ext)) return;
70
- if (!transform) {
71
- /** @type {import('vite').ResolvedConfig} */
72
- let resolvedConfig;
73
- // @ts-expect-error special prop added if running in v-p-s
74
- if (style.__resolvedConfig) {
75
- // @ts-expect-error
76
- resolvedConfig = style.__resolvedConfig;
77
- } else if (isResolvedConfig(config)) {
78
- resolvedConfig = config;
79
- } else {
80
- resolvedConfig = await resolveConfig(
81
- config,
82
- process.env.NODE_ENV === 'production' ? 'build' : 'serve'
83
- );
84
- }
85
- transform = getCssTransformFn(resolvedConfig);
70
+ if (!cssTransform) {
71
+ cssTransform = createCssTransform(style, config).then((t) => (cssTransform = t));
86
72
  }
73
+ const transform = await cssTransform;
87
74
  const suffix = `${lang_sep}${ext}`;
88
75
  const moduleId = `${filename}${suffix}`;
89
76
  const { code, map, deps } = await transform(content, moduleId);
@@ -102,12 +89,27 @@ function viteStyle(config = {}) {
102
89
  }
103
90
 
104
91
  /**
105
- * @param {import('vite').ResolvedConfig} config
106
- * @returns {CssTransform}
92
+ * @param {import('svelte/compiler').Preprocessor} style
93
+ * @param {import('vite').ResolvedConfig | import('vite').InlineConfig} config
94
+ * @returns {Promise<CssTransform>}
107
95
  */
108
- function getCssTransformFn(config) {
96
+ async function createCssTransform(style, config) {
97
+ /** @type {import('vite').ResolvedConfig} */
98
+ let resolvedConfig;
99
+ // @ts-expect-error special prop added if running in v-p-s
100
+ if (style.__resolvedConfig) {
101
+ // @ts-expect-error
102
+ resolvedConfig = style.__resolvedConfig;
103
+ } else if (isResolvedConfig(config)) {
104
+ resolvedConfig = config;
105
+ } else {
106
+ resolvedConfig = await resolveConfig(
107
+ config,
108
+ process.env.NODE_ENV === 'production' ? 'build' : 'serve'
109
+ );
110
+ }
109
111
  return async (code, filename) => {
110
- return preprocessCSS(code, filename, config);
112
+ return preprocessCSS(code, filename, resolvedConfig);
111
113
  };
112
114
  }
113
115
 
package/src/public.d.ts CHANGED
@@ -175,6 +175,15 @@ interface ExperimentalOptions {
175
175
  }
176
176
 
177
177
  interface CompileModuleOptions {
178
+ /**
179
+ * infix that must be present in filename
180
+ * @default ['.svelte.']
181
+ */
182
+ infixes?: string[];
183
+ /**
184
+ * module extensions
185
+ * @default ['.ts','.js']
186
+ */
178
187
  extensions?: string[];
179
188
  include?: Arrayable<string>;
180
189
  exclude?: Arrayable<string>;
@@ -195,5 +204,5 @@ export interface VitePreprocessOptions {
195
204
  */
196
205
  style?: boolean | InlineConfig | ResolvedConfig;
197
206
  }
198
-
207
+ // eslint-disable-next-line n/no-missing-import
199
208
  export * from './index.js';
@@ -1,5 +1,6 @@
1
1
  import type { CompileOptions } from 'svelte/compiler';
2
2
  import type { ViteDevServer } from 'vite';
3
+ // eslint-disable-next-line n/no-missing-import
3
4
  import { VitePluginSvelteStats } from '../utils/vite-plugin-svelte-stats.js';
4
5
  import type { Options } from '../public.d.ts';
5
6
 
@@ -128,12 +128,11 @@ export function createCompileSvelte() {
128
128
  ...dynamicCompileOptions
129
129
  }
130
130
  : compileOptions;
131
-
132
131
  const endStat = stats?.start(filename);
133
132
  /** @type {import('svelte/compiler').CompileResult} */
134
133
  let compiled;
135
134
  try {
136
- compiled = svelte.compile(finalCode, finalCompileOptions);
135
+ compiled = svelte.compile(finalCode, { ...finalCompileOptions, filename: filename });
137
136
  // patch output with partial accept until svelte does it
138
137
  // TODO remove later
139
138
  if (
@@ -20,3 +20,7 @@ export const SVELTE_EXPORT_CONDITIONS = ['svelte'];
20
20
 
21
21
  export const FAQ_LINK_MISSING_EXPORTS_CONDITION =
22
22
  'https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#missing-exports-condition';
23
+
24
+ export const DEFAULT_SVELTE_EXT = ['.svelte'];
25
+ export const DEFAULT_SVELTE_MODULE_INFIX = ['.svelte.'];
26
+ export const DEFAULT_SVELTE_MODULE_EXT = ['.js', '.ts'];
@@ -9,8 +9,7 @@ import { toESBuildError } from './error.js';
9
9
  */
10
10
 
11
11
  export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade';
12
-
13
- const svelteModuleExtension = '.svelte.js';
12
+ export const facadeEsbuildSvelteModulePluginName = 'vite-plugin-svelte-module:facade';
14
13
 
15
14
  /**
16
15
  * @param {import('../types/options.d.ts').ResolvedOptions} options
@@ -24,18 +23,15 @@ export function esbuildSveltePlugin(options) {
24
23
  // Otherwise this would heavily slow down the scanning phase.
25
24
  if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
26
25
 
27
- const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1));
28
- svelteExtensions.push(svelteModuleExtension.slice(1));
29
-
30
- const svelteFilter = new RegExp('\\.(' + svelteExtensions.join('|') + ')(\\?.*)?$');
26
+ const filter = /\.svelte(?:\?.*)?$/;
31
27
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
32
28
  let statsCollection;
33
29
  build.onStart(() => {
34
- statsCollection = options.stats?.startCollection('prebundle libraries', {
30
+ statsCollection = options.stats?.startCollection('prebundle library components', {
35
31
  logResult: (c) => c.stats.length > 1
36
32
  });
37
33
  });
38
- build.onLoad({ filter: svelteFilter }, async ({ path: filename }) => {
34
+ build.onLoad({ filter }, async ({ path: filename }) => {
39
35
  const code = readFileSync(filename, 'utf8');
40
36
  try {
41
37
  const contents = await compileSvelte(options, { filename, code }, statsCollection);
@@ -58,19 +54,6 @@ export function esbuildSveltePlugin(options) {
58
54
  * @returns {Promise<string>}
59
55
  */
60
56
  async function compileSvelte(options, { filename, code }, statsCollection) {
61
- if (filename.endsWith(svelteModuleExtension)) {
62
- const endStat = statsCollection?.start(filename);
63
- const compiled = svelte.compileModule(code, {
64
- filename,
65
- generate: 'client'
66
- });
67
- if (endStat) {
68
- endStat();
69
- }
70
- return compiled.js.map
71
- ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
72
- : compiled.js.code;
73
- }
74
57
  let css = options.compilerOptions.css;
75
58
  if (css !== 'injected') {
76
59
  // TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
@@ -78,6 +61,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
78
61
  }
79
62
  /** @type {import('svelte/compiler').CompileOptions} */
80
63
  const compileOptions = {
64
+ dev: true, // default to dev: true because prebundling is only used in dev
81
65
  ...options.compilerOptions,
82
66
  css,
83
67
  filename,
@@ -127,3 +111,60 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
127
111
  ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
128
112
  : compiled.js.code;
129
113
  }
114
+
115
+ /**
116
+ * @param {import('../types/options.d.ts').ResolvedOptions} options
117
+ * @returns {EsbuildPlugin}
118
+ */
119
+ export function esbuildSvelteModulePlugin(options) {
120
+ return {
121
+ name: 'vite-plugin-svelte-module:optimize-svelte',
122
+ setup(build) {
123
+ // Skip in scanning phase as Vite already handles scanning Svelte files.
124
+ // Otherwise this would heavily slow down the scanning phase.
125
+ if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
126
+
127
+ const filter = /\.svelte\.[jt]s(?:\?.*)?$/;
128
+ /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
129
+ let statsCollection;
130
+ build.onStart(() => {
131
+ statsCollection = options.stats?.startCollection('prebundle library modules', {
132
+ logResult: (c) => c.stats.length > 1
133
+ });
134
+ });
135
+ build.onLoad({ filter }, async ({ path: filename }) => {
136
+ const code = readFileSync(filename, 'utf8');
137
+ try {
138
+ const contents = await compileSvelteModule(options, { filename, code }, statsCollection);
139
+ return { contents };
140
+ } catch (e) {
141
+ return { errors: [toESBuildError(e, options)] };
142
+ }
143
+ });
144
+ build.onEnd(() => {
145
+ statsCollection?.finish();
146
+ });
147
+ }
148
+ };
149
+ }
150
+
151
+ /**
152
+ * @param {import('../types/options.d.ts').ResolvedOptions} options
153
+ * @param {{ filename: string; code: string }} input
154
+ * @param {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection} [statsCollection]
155
+ * @returns {Promise<string>}
156
+ */
157
+ async function compileSvelteModule(options, { filename, code }, statsCollection) {
158
+ const endStat = statsCollection?.start(filename);
159
+ const compiled = svelte.compileModule(code, {
160
+ dev: options.compilerOptions?.dev ?? true, // default to dev: true because prebundling is only used in dev
161
+ filename,
162
+ generate: 'client'
163
+ });
164
+ if (endStat) {
165
+ endStat();
166
+ }
167
+ return compiled.js.map
168
+ ? compiled.js.code + '//# sourceMappingURL=' + compiled.js.map.toUrl()
169
+ : compiled.js.code;
170
+ }
package/src/utils/id.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createFilter, normalizePath } from 'vite';
2
2
  import * as fs from 'node:fs';
3
3
  import { log } from './log.js';
4
+ import { DEFAULT_SVELTE_MODULE_EXT, DEFAULT_SVELTE_MODULE_INFIX } from './constants.js';
4
5
 
5
6
  const VITE_FS_PREFIX = '/@fs/';
6
7
  const IS_WINDOWS = process.platform === 'win32';
@@ -169,6 +170,21 @@ function buildFilter(include, exclude, extensions) {
169
170
  return (filename) => rollupFilter(filename) && extensions.some((ext) => filename.endsWith(ext));
170
171
  }
171
172
 
173
+ /**
174
+ * @param {import('../public.d.ts').Options['include'] | undefined} include
175
+ * @param {import('../public.d.ts').Options['exclude'] | undefined} exclude
176
+ * @param {string[]} infixes
177
+ * @param {string[]} extensions
178
+ * @returns {(filename: string) => boolean}
179
+ */
180
+ function buildModuleFilter(include, exclude, infixes, extensions) {
181
+ const rollupFilter = createFilter(include, exclude);
182
+ return (filename) =>
183
+ rollupFilter(filename) &&
184
+ infixes.some((infix) => filename.includes(infix)) &&
185
+ extensions.some((ext) => filename.endsWith(ext));
186
+ }
187
+
172
188
  /**
173
189
  * @param {import('../types/options.d.ts').ResolvedOptions} options
174
190
  * @returns {import('../types/id.d.ts').IdParser}
@@ -190,10 +206,15 @@ export function buildIdParser(options) {
190
206
  * @returns {import('../types/id.d.ts').ModuleIdParser}
191
207
  */
192
208
  export function buildModuleIdParser(options) {
193
- const { include, exclude, extensions } = options?.experimental?.compileModule ?? {};
209
+ const {
210
+ include,
211
+ exclude,
212
+ infixes = DEFAULT_SVELTE_MODULE_INFIX,
213
+ extensions = DEFAULT_SVELTE_MODULE_EXT
214
+ } = options?.experimental?.compileModule ?? {};
194
215
  const root = options.root;
195
216
  const normalizedRoot = normalizePath(root);
196
- const filter = buildFilter(include, exclude, extensions ?? ['.svelte.js', '.svelte.ts']);
217
+ const filter = buildModuleFilter(include, exclude, infixes, extensions);
197
218
  return (id, ssr, timestamp = Date.now()) => {
198
219
  const { filename, rawQuery } = splitId(id);
199
220
  if (filter(filename)) {
@@ -3,6 +3,7 @@ import { normalizePath } from 'vite';
3
3
  import { isDebugNamespaceEnabled, log } from './log.js';
4
4
  import { loadSvelteConfig } from './load-svelte-config.js';
5
5
  import {
6
+ DEFAULT_SVELTE_EXT,
6
7
  FAQ_LINK_MISSING_EXPORTS_CONDITION,
7
8
  SVELTE_EXPORT_CONDITIONS,
8
9
  SVELTE_IMPORTS,
@@ -11,7 +12,12 @@ import {
11
12
  } from './constants.js';
12
13
 
13
14
  import path from 'node:path';
14
- import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild.js';
15
+ import {
16
+ esbuildSvelteModulePlugin,
17
+ esbuildSveltePlugin,
18
+ facadeEsbuildSvelteModulePluginName,
19
+ facadeEsbuildSveltePluginName
20
+ } from './esbuild.js';
15
21
  import { addExtraPreprocessors } from './preprocess.js';
16
22
  import deepmerge from 'deepmerge';
17
23
  import {
@@ -137,7 +143,7 @@ export async function preResolveOptions(inlineOptions, viteUserConfig, viteEnv)
137
143
  const isBuild = viteEnv.command === 'build';
138
144
  /** @type {Partial<import('../types/options.d.ts').PreResolvedOptions>} */
139
145
  const defaultOptions = {
140
- extensions: ['.svelte'],
146
+ extensions: DEFAULT_SVELTE_EXT,
141
147
  emitCss: true,
142
148
  prebundleSvelteLibraries: !isBuild
143
149
  };
@@ -195,7 +201,11 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
195
201
  compilerOptions: {
196
202
  css,
197
203
  dev: !viteConfig.isProduction,
198
- hmr: !viteConfig.isProduction && !preResolveOptions.isBuild
204
+ hmr:
205
+ !viteConfig.isProduction &&
206
+ !preResolveOptions.isBuild &&
207
+ viteConfig.server &&
208
+ viteConfig.server.hmr !== false
199
209
  }
200
210
  };
201
211
 
@@ -211,7 +221,7 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
211
221
  removeIgnoredOptions(merged);
212
222
  handleDeprecatedOptions(merged);
213
223
  addExtraPreprocessors(merged, viteConfig);
214
- enforceOptionsForHmr(merged);
224
+ enforceOptionsForHmr(merged, viteConfig);
215
225
  enforceOptionsForProduction(merged);
216
226
  // mergeConfigs would mangle functions on the stats class, so do this afterwards
217
227
  if (log.debug.enabled && isDebugNamespaceEnabled('stats')) {
@@ -222,8 +232,9 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
222
232
 
223
233
  /**
224
234
  * @param {import('../types/options.d.ts').ResolvedOptions} options
235
+ * @param {import('vite').ResolvedConfig} viteConfig
225
236
  */
226
- function enforceOptionsForHmr(options) {
237
+ function enforceOptionsForHmr(options, viteConfig) {
227
238
  if (options.hot) {
228
239
  log.warn(
229
240
  'svelte 5 has hmr integrated in core. Please remove the vitePlugin.hot option and use compilerOptions.hmr instead'
@@ -231,6 +242,12 @@ function enforceOptionsForHmr(options) {
231
242
  delete options.hot;
232
243
  options.compilerOptions.hmr = true;
233
244
  }
245
+ if (options.compilerOptions.hmr && viteConfig.server?.hmr === false) {
246
+ log.warn(
247
+ 'vite config server.hmr is false but compilerOptions.hmr is true. Forcing compilerOptions.hmr to false as it would not work.'
248
+ );
249
+ options.compilerOptions.hmr = false;
250
+ }
234
251
  }
235
252
 
236
253
  /**
@@ -258,7 +275,7 @@ function enforceOptionsForProduction(options) {
258
275
  */
259
276
  function removeIgnoredOptions(options) {
260
277
  const ignoredCompilerOptions = ['generate', 'format', 'filename'];
261
- if (options.hot && options.emitCss) {
278
+ if (options.compilerOptions.hmr && options.emitCss) {
262
279
  ignoredCompilerOptions.push('cssHash');
263
280
  }
264
281
  const passedCompilerOptions = Object.keys(options.compilerOptions || {});
@@ -383,7 +400,10 @@ export async function buildExtraViteConfig(options, config) {
383
400
  // Currently a placeholder as more information is needed after Vite config is resolved,
384
401
  // the real Svelte plugin is added in `patchResolvedViteConfig()`
385
402
  esbuildOptions: {
386
- plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
403
+ plugins: [
404
+ { name: facadeEsbuildSveltePluginName, setup: () => {} },
405
+ { name: facadeEsbuildSvelteModulePluginName, setup: () => {} }
406
+ ]
387
407
  }
388
408
  };
389
409
  }
@@ -583,6 +603,12 @@ export function patchResolvedViteConfig(viteConfig, options) {
583
603
  if (facadeEsbuildSveltePlugin) {
584
604
  Object.assign(facadeEsbuildSveltePlugin, esbuildSveltePlugin(options));
585
605
  }
606
+ const facadeEsbuildSvelteModulePlugin = viteConfig.optimizeDeps.esbuildOptions?.plugins?.find(
607
+ (plugin) => plugin.name === facadeEsbuildSvelteModulePluginName
608
+ );
609
+ if (facadeEsbuildSvelteModulePlugin) {
610
+ Object.assign(facadeEsbuildSvelteModulePlugin, esbuildSvelteModulePlugin(options));
611
+ }
586
612
  }
587
613
 
588
614
  /**
package/types/index.d.ts CHANGED
@@ -173,6 +173,15 @@ declare module '@sveltejs/vite-plugin-svelte' {
173
173
  }
174
174
 
175
175
  interface CompileModuleOptions {
176
+ /**
177
+ * infix that must be present in filename
178
+ * @default ['.svelte.']
179
+ */
180
+ infixes?: string[];
181
+ /**
182
+ * module extensions
183
+ * @default ['.ts','.js']
184
+ */
176
185
  extensions?: string[];
177
186
  include?: Arrayable<string>;
178
187
  exclude?: Arrayable<string>;
@@ -21,5 +21,5 @@
21
21
  null,
22
22
  null
23
23
  ],
24
- "mappings": ";;;;aAMYA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6GFC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqEZC,qBAAqBA;;;;;;;;;;;;;iBChKtBC,MAAMA;iBCTNC,cAAcA;iBCgBRC,gBAAgBA"
24
+ "mappings": ";;;;aAMYA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6GFC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA8EZC,qBAAqBA;;;;;;;;;;;;;iBCzKtBC,MAAMA;iBCTNC,cAAcA;iBCgBRC,gBAAgBA"
25
25
  }