@sveltejs/vite-plugin-svelte 1.0.0-next.39 → 1.0.0-next.42

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.39",
3
+ "version": "1.0.0-next.42",
4
4
  "license": "MIT",
5
5
  "author": "dominikg",
6
6
  "files": [
@@ -40,16 +40,16 @@
40
40
  },
41
41
  "homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
42
42
  "dependencies": {
43
- "@rollup/pluginutils": "^4.1.2",
44
- "debug": "^4.3.3",
43
+ "@rollup/pluginutils": "^4.2.1",
44
+ "debug": "^4.3.4",
45
45
  "kleur": "^4.1.4",
46
- "magic-string": "^0.25.7",
47
- "svelte-hmr": "^0.14.9"
46
+ "magic-string": "^0.26.1",
47
+ "svelte-hmr": "^0.14.11"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "diff-match-patch": "^1.0.5",
51
51
  "svelte": "^3.44.0",
52
- "vite": "^2.7.0"
52
+ "vite": "^2.9.0"
53
53
  },
54
54
  "peerDependenciesMeta": {
55
55
  "diff-match-patch": {
@@ -60,16 +60,16 @@
60
60
  "@types/debug": "^4.1.7",
61
61
  "@types/diff-match-patch": "^1.0.32",
62
62
  "diff-match-patch": "^1.0.5",
63
- "esbuild": "^0.14.23",
64
- "rollup": "^2.68.0",
65
- "svelte": "^3.46.4",
66
- "tsup": "^5.11.13",
67
- "vite": "^2.8.4"
63
+ "esbuild": "^0.14.36",
64
+ "rollup": "^2.70.2",
65
+ "svelte": "^3.47.0",
66
+ "tsup": "^5.12.5",
67
+ "vite": "^2.9.5"
68
68
  },
69
69
  "scripts": {
70
70
  "dev": "pnpm run build:ci -- --sourcemap --watch src",
71
71
  "build:ci": "rimraf dist && tsup-node src/index.ts --format esm,cjs --no-splitting --target node14",
72
72
  "build": "pnpm run build:ci -- --dts --sourcemap"
73
73
  },
74
- "readme": "# @sveltejs/vite-plugin-svelte\n\nThe official [Svelte](https://svelte.dev) plugin for [Vite](https://vitejs.dev).\n\n## Usage\n\n```js\n// vite.config.js\nimport { defineConfig } from 'vite';\nimport { svelte } from '@sveltejs/vite-plugin-svelte';\n\nexport default defineConfig({\n\tplugins: [\n\t\tsvelte({\n\t\t\t/* plugin options */\n\t\t})\n\t]\n});\n```\n\n## Documentation\n\n- [Plugin options](../../docs/config.md)\n- [FAQ](../../docs/faq.md)\n\n## License\n\n[MIT](./LICENSE)\n"
74
+ "readme": "# @sveltejs/vite-plugin-svelte\n\nThe official [Svelte](https://svelte.dev) plugin for [Vite](https://vitejs.dev).\n\n## Usage\n\n```js\n// vite.config.js\nimport { defineConfig } from 'vite';\nimport { svelte } from '@sveltejs/vite-plugin-svelte';\n\nexport default defineConfig({\n plugins: [\n svelte({\n /* plugin options */\n })\n ]\n});\n```\n\n## Documentation\n\n- [Plugin options](../../docs/config.md)\n- [FAQ](../../docs/faq.md)\n\n## License\n\n[MIT](./LICENSE)\n"
75
75
  }
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ import { ensureWatchedFile, setupWatchers } from './utils/watch';
19
19
  import { resolveViaPackageJsonSvelte } from './utils/resolve';
20
20
  import { PartialResolvedId } from 'rollup';
21
21
  import { toRollupError } from './utils/error';
22
- import { handleOptimizeDeps } from './utils/optimizer';
22
+ import { saveSvelteMetadata } from './utils/optimizer';
23
23
 
24
24
  export function svelte(inlineOptions?: Partial<Options>): Plugin {
25
25
  if (process.env.DEBUG != null) {
@@ -55,7 +55,7 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
55
55
  // @ts-expect-error temporarily lend the options variable until fixed in configResolved
56
56
  options = await preResolveOptions(inlineOptions, config, configEnv);
57
57
  // extra vite config
58
- const extraViteConfig = buildExtraViteConfig(options, config, configEnv);
58
+ const extraViteConfig = buildExtraViteConfig(options, config);
59
59
  log.debug('additional vite config', extraViteConfig);
60
60
  return extraViteConfig;
61
61
  },
@@ -70,7 +70,13 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
70
70
  },
71
71
 
72
72
  async buildStart() {
73
- await handleOptimizeDeps(options, viteConfig);
73
+ if (!options.experimental.prebundleSvelteLibraries) return;
74
+ const isSvelteMetadataChanged = await saveSvelteMetadata(viteConfig.cacheDir, options);
75
+ if (isSvelteMetadataChanged) {
76
+ // Force Vite to optimize again. Although we mutate the config here, it works because
77
+ // Vite's optimizer runs after `buildStart()`.
78
+ viteConfig.server.force = true;
79
+ }
74
80
  },
75
81
 
76
82
  configureServer(server) {
@@ -8,7 +8,6 @@ import { toESBuildError } from './error';
8
8
 
9
9
  type EsbuildOptions = NonNullable<DepOptimizationOptions['esbuildOptions']>;
10
10
  type EsbuildPlugin = NonNullable<EsbuildOptions['plugins']>[number];
11
- type EsbuildPluginBuild = Parameters<EsbuildPlugin['setup']>[0];
12
11
 
13
12
  export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade';
14
13
 
@@ -16,7 +15,9 @@ export function esbuildSveltePlugin(options: ResolvedOptions): EsbuildPlugin {
16
15
  return {
17
16
  name: 'vite-plugin-svelte:optimize-svelte',
18
17
  setup(build) {
19
- disableVitePrebundleSvelte(build);
18
+ // Skip in scanning phase as Vite already handles scanning Svelte files.
19
+ // Otherwise this would heavily slow down the scanning phase.
20
+ if (build.initialOptions.plugins?.some((v) => v.name === 'vite:dep-scan')) return;
20
21
 
21
22
  const svelteExtensions = (options.extensions ?? ['.svelte']).map((ext) => ext.slice(1));
22
23
  const svelteFilter = new RegExp(`\\.(` + svelteExtensions.join('|') + `)(\\?.*)?$`);
@@ -34,30 +35,6 @@ export function esbuildSveltePlugin(options: ResolvedOptions): EsbuildPlugin {
34
35
  };
35
36
  }
36
37
 
37
- function disableVitePrebundleSvelte(build: EsbuildPluginBuild) {
38
- const viteDepPrebundlePlugin = build.initialOptions.plugins?.find(
39
- (v) => v.name === 'vite:dep-pre-bundle'
40
- );
41
-
42
- if (!viteDepPrebundlePlugin) return;
43
-
44
- // Prevent vite:dep-pre-bundle from externalizing svelte files
45
- const _setup = viteDepPrebundlePlugin.setup.bind(viteDepPrebundlePlugin);
46
- viteDepPrebundlePlugin.setup = function (build) {
47
- const _onResolve = build.onResolve.bind(build);
48
- build.onResolve = function (options, callback) {
49
- if (options.filter.source.includes('svelte')) {
50
- options.filter = new RegExp(
51
- options.filter.source.replace('|svelte', ''),
52
- options.filter.flags
53
- );
54
- }
55
- return _onResolve(options, callback);
56
- };
57
- return _setup(build);
58
- };
59
- }
60
-
61
38
  async function compileSvelte(
62
39
  options: ResolvedOptions,
63
40
  { filename, code }: { filename: string; code: string }
package/src/utils/hash.ts CHANGED
@@ -14,7 +14,7 @@ export function safeBase64Hash(input: string) {
14
14
  // OR DON'T USE A HASH AT ALL, what about a simple counter?
15
15
  const md5 = crypto.createHash('md5');
16
16
  md5.update(input);
17
- const hash = toSafe(md5.digest('base64')).substr(0, hash_length);
17
+ const hash = toSafe(md5.digest('base64')).slice(0, hash_length);
18
18
  hashes[input] = hash;
19
19
  return hash;
20
20
  }
@@ -29,6 +29,9 @@ export async function loadSvelteConfig(
29
29
  viteConfig: UserConfig,
30
30
  inlineOptions: Partial<Options>
31
31
  ): Promise<Partial<Options> | undefined> {
32
+ if (inlineOptions.configFile === false) {
33
+ return;
34
+ }
32
35
  const configFile = findConfigToLoad(viteConfig, inlineOptions);
33
36
  if (configFile) {
34
37
  let err;
@@ -1,6 +1,5 @@
1
- import fs from 'fs';
1
+ import { promises as fs } from 'fs';
2
2
  import path from 'path';
3
- import { optimizeDeps, ResolvedConfig } from 'vite';
4
3
  import { ResolvedOptions } from './options';
5
4
 
6
5
  // List of options that changes the prebundling result
@@ -13,24 +12,28 @@ const PREBUNDLE_SENSITIVE_OPTIONS: (keyof ResolvedOptions)[] = [
13
12
  'preprocess'
14
13
  ];
15
14
 
16
- export async function handleOptimizeDeps(options: ResolvedOptions, viteConfig: ResolvedConfig) {
17
- if (!options.experimental.prebundleSvelteLibraries || !viteConfig.cacheDir) return;
15
+ /**
16
+ * @returns Whether the Svelte metadata has changed
17
+ */
18
+ export async function saveSvelteMetadata(cacheDir: string, options: ResolvedOptions) {
19
+ const svelteMetadata = generateSvelteMetadata(options);
20
+ const svelteMetadataPath = path.resolve(cacheDir, '_svelte_metadata.json');
18
21
 
19
- const viteMetadataPath = findViteMetadataPath(viteConfig.cacheDir);
20
- if (!viteMetadataPath) return;
21
-
22
- const svelteMetadataPath = path.resolve(viteMetadataPath, '../_svelte_metadata.json');
23
- const currentSvelteMetadata = JSON.stringify(generateSvelteMetadata(options), (_, value) => {
22
+ const currentSvelteMetadata = JSON.stringify(svelteMetadata, (_, value) => {
23
+ // Handle preprocessors
24
24
  return typeof value === 'function' ? value.toString() : value;
25
25
  });
26
26
 
27
- if (fs.existsSync(svelteMetadataPath)) {
28
- const existingSvelteMetadata = fs.readFileSync(svelteMetadataPath, 'utf8');
29
- if (existingSvelteMetadata === currentSvelteMetadata) return;
27
+ let existingSvelteMetadata: string | undefined;
28
+ try {
29
+ existingSvelteMetadata = await fs.readFile(svelteMetadataPath, 'utf8');
30
+ } catch {
31
+ // ignore
30
32
  }
31
33
 
32
- await optimizeDeps(viteConfig, true);
33
- fs.writeFileSync(svelteMetadataPath, currentSvelteMetadata);
34
+ await fs.mkdir(cacheDir, { recursive: true });
35
+ await fs.writeFile(svelteMetadataPath, currentSvelteMetadata);
36
+ return currentSvelteMetadata !== existingSvelteMetadata;
34
37
  }
35
38
 
36
39
  function generateSvelteMetadata(options: ResolvedOptions) {
@@ -40,11 +43,3 @@ function generateSvelteMetadata(options: ResolvedOptions) {
40
43
  }
41
44
  return metadata;
42
45
  }
43
-
44
- function findViteMetadataPath(cacheDir: string) {
45
- const metadataPaths = ['_metadata.json', 'deps/_metadata.json'];
46
- for (const metadataPath of metadataPaths) {
47
- const viteMetadataPath = path.resolve(cacheDir, metadataPath);
48
- if (fs.existsSync(viteMetadataPath)) return viteMetadataPath;
49
- }
50
- }
@@ -184,8 +184,7 @@ function resolveViteRoot(viteConfig: UserConfig): string | undefined {
184
184
 
185
185
  export function buildExtraViteConfig(
186
186
  options: PreResolvedOptions,
187
- config: UserConfig,
188
- configEnv: ConfigEnv
187
+ config: UserConfig
189
188
  ): Partial<UserConfig> {
190
189
  // extra handling for svelte dependencies in the project
191
190
  const svelteDeps = findRootSvelteDependencies(options.root);
@@ -200,7 +199,7 @@ export function buildExtraViteConfig(
200
199
  // knownJsSrcExtensions: options.extensions
201
200
  };
202
201
 
203
- if (configEnv.command === 'serve') {
202
+ if (options.isServe) {
204
203
  extraViteConfig.optimizeDeps = buildOptimizeDepsForSvelte(
205
204
  svelteDeps,
206
205
  options,
@@ -208,8 +207,23 @@ export function buildExtraViteConfig(
208
207
  );
209
208
  }
210
209
 
210
+ if (options.experimental.prebundleSvelteLibraries) {
211
+ extraViteConfig.optimizeDeps = {
212
+ ...extraViteConfig.optimizeDeps,
213
+ // Experimental Vite API to allow these extensions to be scanned and prebundled
214
+ // @ts-ignore
215
+ extensions: options.extensions ?? ['.svelte'],
216
+ // Add esbuild plugin to prebundle Svelte files.
217
+ // Currently a placeholder as more information is needed after Vite config is resolved,
218
+ // the real Svelte plugin is added in `patchResolvedViteConfig()`
219
+ esbuildOptions: {
220
+ plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
221
+ }
222
+ };
223
+ }
224
+
211
225
  // @ts-ignore
212
- extraViteConfig.ssr = buildSSROptionsForSvelte(svelteDeps, options, config);
226
+ extraViteConfig.ssr = buildSSROptionsForSvelte(svelteDeps, options, config, extraViteConfig);
213
227
 
214
228
  return extraViteConfig;
215
229
  }
@@ -243,13 +257,7 @@ function buildOptimizeDepsForSvelte(
243
257
 
244
258
  // If we prebundle svelte libraries, we can skip the whole prebundling dance below
245
259
  if (options.experimental.prebundleSvelteLibraries) {
246
- return {
247
- include,
248
- exclude,
249
- esbuildOptions: {
250
- plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
251
- }
252
- };
260
+ return { include, exclude };
253
261
  }
254
262
 
255
263
  // only svelte component libraries needs to be processed for optimizeDeps, js libraries work fine
@@ -294,7 +302,7 @@ function buildSSROptionsForSvelte(
294
302
  // add svelte to ssr.noExternal unless it is present in ssr.external
295
303
  // so we can resolve it with svelte/ssr
296
304
  if (options.isBuild && config.build?.ssr) {
297
- // @ts-ignore
305
+ // @ts-expect-error ssr still flagged in vite
298
306
  if (!config.ssr?.external?.includes('svelte')) {
299
307
  noExternal.push('svelte');
300
308
  }
@@ -309,13 +317,30 @@ function buildSSROptionsForSvelte(
309
317
  // add svelte dependencies to ssr.noExternal unless present in ssr.external or optimizeDeps.include
310
318
  noExternal.push(
311
319
  ...Array.from(new Set(svelteDeps.map((s) => s.name))).filter((x) => {
312
- // @ts-ignore
320
+ // @ts-expect-error ssr still flagged in vite
313
321
  return !config.ssr?.external?.includes(x) && !config.optimizeDeps?.include?.includes(x);
314
322
  })
315
323
  );
316
- return {
324
+ const ssr = {
317
325
  noExternal
318
326
  };
327
+
328
+ if (options.isServe) {
329
+ // during dev, we have to externalize transitive dependencies, see https://github.com/sveltejs/vite-plugin-svelte/issues/281
330
+ // @ts-expect-error ssr still flagged in vite
331
+ ssr.external = Array.from(
332
+ new Set(svelteDeps.flatMap((dep) => Object.keys(dep.pkg.dependencies || {})))
333
+ ).filter(
334
+ (dep) =>
335
+ !ssr.noExternal.includes(dep) &&
336
+ // @ts-expect-error ssr still flagged in vite
337
+ !config.ssr?.noExternal?.includes(dep) &&
338
+ // @ts-expect-error ssr still flagged in vite
339
+ !config.ssr?.external?.includes(dep)
340
+ );
341
+ }
342
+
343
+ return ssr;
319
344
  }
320
345
 
321
346
  export function patchResolvedViteConfig(viteConfig: ResolvedConfig, options: ResolvedOptions) {
@@ -330,9 +355,11 @@ export interface Options {
330
355
  /**
331
356
  * Path to a svelte config file, either absolute or relative to Vite root
332
357
  *
358
+ * set to `false` to skip reading config from a file
359
+ *
333
360
  * @see https://vitejs.dev/config/#root
334
361
  */
335
- configFile?: string;
362
+ configFile?: string | false;
336
363
 
337
364
  /**
338
365
  * A `picomatch` pattern, or array of patterns, which specifies the files the plugin should
@@ -11,6 +11,7 @@ import { Preprocessor, PreprocessorGroup, Processed, ResolvedOptions } from './o
11
11
  import { TransformPluginContext } from 'rollup';
12
12
  import { log } from './log';
13
13
  import { buildSourceMap } from './sourcemap';
14
+ import path from 'path';
14
15
 
15
16
  const supportedStyleLangs = ['css', 'less', 'sass', 'scss', 'styl', 'stylus', 'postcss'];
16
17
 
@@ -57,7 +58,7 @@ function createViteStylePreprocessor(config: ResolvedConfig): Preprocessor {
57
58
  )) as TransformResult;
58
59
  // patch sourcemap source to point back to original filename
59
60
  if (transformResult.map?.sources?.[0] === moduleId) {
60
- transformResult.map.sources[0] = filename;
61
+ transformResult.map.sources[0] = path.basename(filename);
61
62
  }
62
63
  return {
63
64
  code: transformResult.code,
@@ -94,7 +95,10 @@ function createInjectScopeEverythingRulePreprocessorGroup(): PreprocessorGroup {
94
95
  s.append(' *{}');
95
96
  return {
96
97
  code: s.toString(),
97
- map: s.generateDecodedMap({ source: filename, hires: true })
98
+ map: s.generateDecodedMap({
99
+ source: filename ? path.basename(filename) : undefined,
100
+ hires: true
101
+ })
98
102
  };
99
103
  }
100
104
  };