@sveltejs/vite-plugin-svelte 1.0.0-next.31 → 1.0.0-next.35

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/src/index.ts CHANGED
@@ -9,15 +9,17 @@ import {
9
9
  validateInlineOptions,
10
10
  Options,
11
11
  ResolvedOptions,
12
- resolveOptions
12
+ resolveOptions,
13
+ patchResolvedViteConfig,
14
+ preResolveOptions
13
15
  } from './utils/options';
14
16
  import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache';
15
17
 
16
18
  import { ensureWatchedFile, setupWatchers } from './utils/watch';
17
19
  import { resolveViaPackageJsonSvelte } from './utils/resolve';
18
- import { addExtraPreprocessors } from './utils/preprocess';
19
20
  import { PartialResolvedId } from 'rollup';
20
21
  import { toRollupError } from './utils/error';
22
+ import { handleOptimizeDeps } from './utils/optimizer';
21
23
 
22
24
  export function svelte(inlineOptions?: Partial<Options>): Plugin {
23
25
  if (process.env.DEBUG != null) {
@@ -25,7 +27,7 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
25
27
  }
26
28
  validateInlineOptions(inlineOptions);
27
29
  const cache = new VitePluginSvelteCache();
28
- const pkg_export_errors = new Set();
30
+ const pkg_resolve_errors = new Set();
29
31
  // updated in configResolved hook
30
32
  let requestParser: IdParser;
31
33
  let options: ResolvedOptions;
@@ -51,21 +53,27 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
51
53
  } else if (config.logLevel) {
52
54
  log.setLevel(config.logLevel);
53
55
  }
54
- options = await resolveOptions(inlineOptions, config, configEnv);
56
+ // @ts-expect-error temporarily lend the options variable until fixed in configResolved
57
+ options = await preResolveOptions(inlineOptions, config, configEnv);
55
58
  // extra vite config
56
59
  const extraViteConfig = buildExtraViteConfig(options, config, configEnv);
57
60
  log.debug('additional vite config', extraViteConfig);
58
- return extraViteConfig as Partial<UserConfig>;
61
+ return extraViteConfig;
59
62
  },
60
63
 
61
64
  async configResolved(config) {
62
- addExtraPreprocessors(options, config);
65
+ options = resolveOptions(options, config);
66
+ patchResolvedViteConfig(config, options);
63
67
  requestParser = buildIdParser(options);
64
68
  compileSvelte = createCompileSvelte(options);
65
69
  viteConfig = config;
66
70
  log.debug('resolved options', options);
67
71
  },
68
72
 
73
+ async buildStart() {
74
+ await handleOptimizeDeps(options, viteConfig);
75
+ },
76
+
69
77
  configureServer(server) {
70
78
  // eslint-disable-next-line no-unused-vars
71
79
  options.server = server;
@@ -95,11 +103,9 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
95
103
  }
96
104
  },
97
105
 
98
- async resolveId(importee, importer, opts, _ssr) {
99
- // @ts-expect-error anticipate vite deprecating forth parameter and rely on `opts.ssr` instead`
100
- // see https://github.com/vitejs/vite/discussions/5109
101
- const ssr: boolean = _ssr === true || opts.ssr;
102
- const svelteRequest = requestParser(importee, !!ssr);
106
+ async resolveId(importee, importer, opts) {
107
+ const ssr = !!opts?.ssr;
108
+ const svelteRequest = requestParser(importee, ssr);
103
109
  if (svelteRequest?.query.svelte) {
104
110
  if (svelteRequest.query.type === 'style') {
105
111
  // return cssId with root prefix so postcss pipeline of vite finds the directory correctly
@@ -131,29 +137,19 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
131
137
  }
132
138
 
133
139
  try {
134
- const resolved = resolveViaPackageJsonSvelte(importee, importer);
140
+ const resolved = resolveViaPackageJsonSvelte(importee, importer, cache);
135
141
  if (resolved) {
136
142
  log.debug(`resolveId resolved ${resolved} via package.json svelte field of ${importee}`);
137
143
  return resolved;
138
144
  }
139
145
  } catch (err) {
140
- switch (err.code) {
141
- case 'ERR_PACKAGE_PATH_NOT_EXPORTED':
142
- pkg_export_errors.add(importee);
143
- return null;
144
- case 'MODULE_NOT_FOUND':
145
- return null;
146
- default:
147
- throw err;
148
- }
146
+ pkg_resolve_errors.add(importee);
149
147
  }
150
148
  },
151
149
 
152
150
  async transform(code, id, opts) {
153
- // @ts-expect-error anticipate vite changing third parameter as options object
154
- // see https://github.com/vitejs/vite/discussions/5109
155
- const ssr: boolean = opts === true || opts?.ssr;
156
- const svelteRequest = requestParser(id, !!ssr);
151
+ const ssr = !!opts?.ssr;
152
+ const svelteRequest = requestParser(id, ssr);
157
153
  if (!svelteRequest) {
158
154
  return;
159
155
  }
@@ -202,10 +198,11 @@ export function svelte(inlineOptions?: Partial<Options>): Plugin {
202
198
  */
203
199
  // TODO generateBundle isn't called by vite, is buildEnd enough or should it be logged once per violation in resolve
204
200
  buildEnd() {
205
- if (pkg_export_errors.size > 0) {
201
+ if (pkg_resolve_errors.size > 0) {
206
202
  log.warn(
207
- `The following packages did not export their \`package.json\` file so we could not check the "svelte" field. If you had difficulties importing svelte components from a package, then please contact the author and ask them to export the package.json file.`,
208
- Array.from(pkg_export_errors, (s) => `- ${s}`).join('\n')
203
+ `vite-plugin-svelte was unable to find package.json of the following packages and wasn't able to resolve via their "svelte" field.
204
+ If you had difficulties importing svelte components from a package, then please contact the author and ask them to export the package.json file.
205
+ ${Array.from(pkg_resolve_errors, (s) => `- ${s}`).join('\n')}`.replace(/\t/g, '')
209
206
  );
210
207
  }
211
208
  }
@@ -66,7 +66,10 @@ function getSvelteDependencies(
66
66
  return result;
67
67
  }
68
68
 
69
- function resolveDependencyData(dep: string, localRequire: NodeRequire): DependencyData | void {
69
+ export function resolveDependencyData(
70
+ dep: string,
71
+ localRequire: NodeRequire
72
+ ): DependencyData | void {
70
73
  try {
71
74
  const pkgJson = `${dep}/package.json`;
72
75
  const pkg = localRequire(pkgJson);
@@ -166,7 +169,7 @@ const COMMON_PREFIXES_WITHOUT_SVELTE_FIELD = [
166
169
  * @param dependency {string}
167
170
  * @returns {boolean} true if it is a dependency without a svelte field
168
171
  */
169
- function is_common_without_svelte_field(dependency: string): boolean {
172
+ export function is_common_without_svelte_field(dependency: string): boolean {
170
173
  return (
171
174
  COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD.includes(dependency) ||
172
175
  COMMON_PREFIXES_WITHOUT_SVELTE_FIELD.some(
@@ -184,7 +187,12 @@ export function needsOptimization(dep: string, localRequire: NodeRequire): boole
184
187
  const pkg = depData.pkg;
185
188
  // only optimize if is cjs, using the below as heuristic
186
189
  // see https://github.com/sveltejs/vite-plugin-svelte/issues/162
187
- return pkg.main && !pkg.module && !pkg.exports;
190
+ const isCjs = pkg.main && !pkg.module && !pkg.exports;
191
+ if (!isCjs) return false;
192
+ // ensure entry is js so vite can prebundle it
193
+ // see https://github.com/sveltejs/vite-plugin-svelte/issues/233
194
+ const entryExt = path.extname(pkg.main);
195
+ return !entryExt || entryExt === '.js' || entryExt === '.cjs';
188
196
  }
189
197
 
190
198
  interface DependencyData {
@@ -10,6 +10,8 @@ type EsbuildOptions = NonNullable<DepOptimizationOptions['esbuildOptions']>;
10
10
  type EsbuildPlugin = NonNullable<EsbuildOptions['plugins']>[number];
11
11
  type EsbuildPluginBuild = Parameters<EsbuildPlugin['setup']>[0];
12
12
 
13
+ export const facadeEsbuildSveltePluginName = 'vite-plugin-svelte:facade';
14
+
13
15
  export function esbuildSveltePlugin(options: ResolvedOptions): EsbuildPlugin {
14
16
  return {
15
17
  name: 'vite-plugin-svelte:optimize-svelte',
@@ -64,6 +66,7 @@ async function compileSvelte(
64
66
  ...options.compilerOptions,
65
67
  css: true,
66
68
  filename,
69
+ format: 'esm',
67
70
  generate: 'dom'
68
71
  };
69
72
 
@@ -0,0 +1,43 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { optimizeDeps, ResolvedConfig } from 'vite';
4
+ import { ResolvedOptions } from './options';
5
+
6
+ // List of options that changes the prebundling result
7
+ const PREBUNDLE_SENSITIVE_OPTIONS: (keyof ResolvedOptions)[] = [
8
+ 'compilerOptions',
9
+ 'configFile',
10
+ 'experimental',
11
+ 'extensions',
12
+ 'ignorePluginPreprocessors',
13
+ 'preprocess'
14
+ ];
15
+
16
+ export async function handleOptimizeDeps(options: ResolvedOptions, viteConfig: ResolvedConfig) {
17
+ if (!options.experimental.prebundleSvelteLibraries || !viteConfig.cacheDir) return;
18
+
19
+ const viteMetadataPath = path.resolve(viteConfig.cacheDir, '_metadata.json');
20
+
21
+ if (!fs.existsSync(viteMetadataPath)) return;
22
+
23
+ const svelteMetadataPath = path.resolve(viteConfig.cacheDir, '_svelte_metadata.json');
24
+ const currentSvelteMetadata = JSON.stringify(generateSvelteMetadata(options), (_, value) => {
25
+ return typeof value === 'function' ? value.toString() : value;
26
+ });
27
+
28
+ if (fs.existsSync(svelteMetadataPath)) {
29
+ const existingSvelteMetadata = fs.readFileSync(svelteMetadataPath, 'utf8');
30
+ if (existingSvelteMetadata === currentSvelteMetadata) return;
31
+ }
32
+
33
+ await optimizeDeps(viteConfig, true);
34
+ fs.writeFileSync(svelteMetadataPath, currentSvelteMetadata);
35
+ }
36
+
37
+ function generateSvelteMetadata(options: ResolvedOptions) {
38
+ const metadata: Record<string, any> = {};
39
+ for (const key of PREBUNDLE_SENSITIVE_OPTIONS) {
40
+ metadata[key] = options[key];
41
+ }
42
+ return metadata;
43
+ }
@@ -1,5 +1,12 @@
1
1
  /* eslint-disable no-unused-vars */
2
- import { ConfigEnv, DepOptimizationOptions, UserConfig, ViteDevServer, normalizePath } from 'vite';
2
+ import {
3
+ ConfigEnv,
4
+ DepOptimizationOptions,
5
+ ResolvedConfig,
6
+ UserConfig,
7
+ ViteDevServer,
8
+ normalizePath
9
+ } from 'vite';
3
10
  import { log } from './log';
4
11
  import { loadSvelteConfig } from './load-svelte-config';
5
12
  import { SVELTE_HMR_IMPORTS, SVELTE_IMPORTS, SVELTE_RESOLVE_MAIN_FIELDS } from './constants';
@@ -15,7 +22,8 @@ import {
15
22
  import path from 'path';
16
23
  import { findRootSvelteDependencies, needsOptimization, SvelteDependency } from './dependencies';
17
24
  import { createRequire } from 'module';
18
- import { esbuildSveltePlugin } from './esbuild';
25
+ import { esbuildSveltePlugin, facadeEsbuildSveltePluginName } from './esbuild';
26
+ import { addExtraPreprocessors } from './preprocess';
19
27
 
20
28
  const knownOptions = new Set([
21
29
  'configFile',
@@ -32,33 +40,85 @@ const knownOptions = new Set([
32
40
  'experimental'
33
41
  ]);
34
42
 
35
- function buildDefaultOptions(isProduction: boolean, emitCss = true): Partial<Options> {
36
- // no hmr in prod, only inject css in dev if emitCss is false
37
- const hot = isProduction
38
- ? false
39
- : {
40
- // emit for prod, emit in dev unless css hmr is disabled
41
- injectCss: !emitCss
42
- };
43
+ export function validateInlineOptions(inlineOptions?: Partial<Options>) {
44
+ const invalidKeys = Object.keys(inlineOptions || {}).filter((key) => !knownOptions.has(key));
45
+ if (invalidKeys.length) {
46
+ log.warn(`invalid plugin options "${invalidKeys.join(', ')}" in config`, inlineOptions);
47
+ }
48
+ }
49
+
50
+ // used in config phase, merges the default options, svelte config, and inline options
51
+ export async function preResolveOptions(
52
+ inlineOptions: Partial<Options> = {},
53
+ viteUserConfig: UserConfig,
54
+ viteEnv: ConfigEnv
55
+ ): Promise<PreResolvedOptions> {
56
+ const viteConfigWithResolvedRoot: UserConfig = {
57
+ ...viteUserConfig,
58
+ root: resolveViteRoot(viteUserConfig)
59
+ };
43
60
  const defaultOptions: Partial<Options> = {
44
61
  extensions: ['.svelte'],
45
- hot,
46
- emitCss,
62
+ emitCss: true,
47
63
  compilerOptions: {
48
- format: 'esm',
49
- css: !emitCss,
50
- dev: !isProduction
64
+ format: 'esm'
51
65
  }
52
66
  };
53
- log.debug(`default options for ${isProduction ? 'production' : 'development'}`, defaultOptions);
54
- return defaultOptions;
67
+ const svelteConfig = await loadSvelteConfig(viteConfigWithResolvedRoot, inlineOptions);
68
+ const merged = {
69
+ ...defaultOptions,
70
+ ...svelteConfig,
71
+ ...inlineOptions,
72
+ compilerOptions: {
73
+ ...defaultOptions?.compilerOptions,
74
+ ...svelteConfig?.compilerOptions,
75
+ ...inlineOptions?.compilerOptions
76
+ },
77
+ experimental: {
78
+ ...defaultOptions?.experimental,
79
+ ...svelteConfig?.experimental,
80
+ ...inlineOptions?.experimental
81
+ },
82
+ // extras
83
+ root: viteConfigWithResolvedRoot.root!,
84
+ isBuild: viteEnv.command === 'build',
85
+ isServe: viteEnv.command === 'serve'
86
+ };
87
+ // configFile of svelteConfig contains the absolute path it was loaded from,
88
+ // prefer it over the possibly relative inline path
89
+ if (svelteConfig?.configFile) {
90
+ merged.configFile = svelteConfig.configFile;
91
+ }
92
+ return merged;
55
93
  }
56
94
 
57
- export function validateInlineOptions(inlineOptions?: Partial<Options>) {
58
- const invalidKeys = Object.keys(inlineOptions || {}).filter((key) => !knownOptions.has(key));
59
- if (invalidKeys.length) {
60
- log.warn(`invalid plugin options "${invalidKeys.join(', ')}" in config`, inlineOptions);
61
- }
95
+ // used in configResolved phase, merges a contextual default config, pre-resolved options, and some preprocessors.
96
+ // also validates the final config.
97
+ export function resolveOptions(
98
+ preResolveOptions: PreResolvedOptions,
99
+ viteConfig: ResolvedConfig
100
+ ): ResolvedOptions {
101
+ const defaultOptions: Partial<Options> = {
102
+ hot: viteConfig.isProduction ? false : { injectCss: !preResolveOptions.emitCss },
103
+ compilerOptions: {
104
+ css: !preResolveOptions.emitCss,
105
+ dev: !viteConfig.isProduction
106
+ }
107
+ };
108
+ const merged: ResolvedOptions = {
109
+ ...defaultOptions,
110
+ ...preResolveOptions,
111
+ compilerOptions: {
112
+ ...defaultOptions.compilerOptions,
113
+ ...preResolveOptions.compilerOptions
114
+ },
115
+ root: viteConfig.root,
116
+ isProduction: viteConfig.isProduction
117
+ };
118
+ addExtraPreprocessors(merged, viteConfig);
119
+ enforceOptionsForHmr(merged);
120
+ enforceOptionsForProduction(merged);
121
+ return merged;
62
122
  }
63
123
 
64
124
  function enforceOptionsForHmr(options: ResolvedOptions) {
@@ -114,66 +174,6 @@ function enforceOptionsForProduction(options: ResolvedOptions) {
114
174
  }
115
175
  }
116
176
 
117
- function mergeOptions(
118
- defaultOptions: Partial<Options>,
119
- svelteConfig: Partial<Options>,
120
- inlineOptions: Partial<Options>,
121
- viteConfig: UserConfig,
122
- viteEnv: ConfigEnv
123
- ): ResolvedOptions {
124
- const merged = {
125
- ...defaultOptions,
126
- ...svelteConfig,
127
- ...inlineOptions,
128
- compilerOptions: {
129
- ...defaultOptions.compilerOptions,
130
- ...(svelteConfig?.compilerOptions || {}),
131
- ...(inlineOptions?.compilerOptions || {})
132
- },
133
- experimental: {
134
- ...(svelteConfig?.experimental || {}),
135
- ...(inlineOptions?.experimental || {})
136
- },
137
- root: viteConfig.root!,
138
- isProduction: viteEnv.mode === 'production',
139
- isBuild: viteEnv.command === 'build',
140
- isServe: viteEnv.command === 'serve'
141
- };
142
- // configFile of svelteConfig contains the absolute path it was loaded from,
143
- // prefer it over the possibly relative inline path
144
- if (svelteConfig?.configFile) {
145
- merged.configFile = svelteConfig.configFile;
146
- }
147
- return merged;
148
- }
149
-
150
- export async function resolveOptions(
151
- inlineOptions: Partial<Options> = {},
152
- viteConfig: UserConfig,
153
- viteEnv: ConfigEnv
154
- ): Promise<ResolvedOptions> {
155
- const viteConfigWithResolvedRoot = {
156
- ...viteConfig,
157
- root: resolveViteRoot(viteConfig)
158
- };
159
- const svelteConfig = (await loadSvelteConfig(viteConfigWithResolvedRoot, inlineOptions)) || {};
160
- const defaultOptions = buildDefaultOptions(
161
- viteEnv.mode === 'production',
162
- inlineOptions.emitCss ?? svelteConfig.emitCss
163
- );
164
- const resolvedOptions = mergeOptions(
165
- defaultOptions,
166
- svelteConfig,
167
- inlineOptions,
168
- viteConfigWithResolvedRoot,
169
- viteEnv
170
- );
171
-
172
- enforceOptionsForProduction(resolvedOptions);
173
- enforceOptionsForHmr(resolvedOptions);
174
- return resolvedOptions;
175
- }
176
-
177
177
  // vite passes unresolved `root`option to config hook but we need the resolved value, so do it here
178
178
  // https://github.com/sveltejs/vite-plugin-svelte/issues/113
179
179
  // https://github.com/vitejs/vite/blob/43c957de8a99bb326afd732c962f42127b0a4d1e/packages/vite/src/node/config.ts#L293
@@ -182,7 +182,7 @@ function resolveViteRoot(viteConfig: UserConfig): string | undefined {
182
182
  }
183
183
 
184
184
  export function buildExtraViteConfig(
185
- options: ResolvedOptions,
185
+ options: PreResolvedOptions,
186
186
  config: UserConfig,
187
187
  configEnv: ConfigEnv
188
188
  ): Partial<UserConfig> {
@@ -215,7 +215,7 @@ export function buildExtraViteConfig(
215
215
 
216
216
  function buildOptimizeDepsForSvelte(
217
217
  svelteDeps: SvelteDependency[],
218
- options: ResolvedOptions,
218
+ options: PreResolvedOptions,
219
219
  optimizeDeps?: DepOptimizationOptions
220
220
  ): DepOptimizationOptions {
221
221
  // include svelte imports for optimization unless explicitly excluded
@@ -246,7 +246,7 @@ function buildOptimizeDepsForSvelte(
246
246
  include,
247
247
  exclude,
248
248
  esbuildOptions: {
249
- plugins: [esbuildSveltePlugin(options)]
249
+ plugins: [{ name: facadeEsbuildSveltePluginName, setup: () => {} }]
250
250
  }
251
251
  };
252
252
  }
@@ -317,6 +317,14 @@ function buildSSROptionsForSvelte(
317
317
  };
318
318
  }
319
319
 
320
+ export function patchResolvedViteConfig(viteConfig: ResolvedConfig, options: ResolvedOptions) {
321
+ const facadeEsbuildSveltePlugin = viteConfig.optimizeDeps.esbuildOptions?.plugins?.find(
322
+ (plugin) => plugin.name === facadeEsbuildSveltePluginName
323
+ );
324
+ if (facadeEsbuildSveltePlugin) {
325
+ Object.assign(facadeEsbuildSveltePlugin, esbuildSveltePlugin(options));
326
+ }
327
+ }
320
328
  export interface Options {
321
329
  /**
322
330
  * Path to a svelte config file, either absolute or relative to Vite root
@@ -475,15 +483,18 @@ export interface ExperimentalOptions {
475
483
  }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
476
484
  }
477
485
 
478
- export interface ResolvedOptions extends Options {
486
+ export interface PreResolvedOptions extends Options {
479
487
  // these options are non-nullable after resolve
480
488
  compilerOptions: CompileOptions;
481
489
  experimental: ExperimentalOptions;
482
490
  // extra options
483
491
  root: string;
484
- isProduction: boolean;
485
492
  isBuild: boolean;
486
493
  isServe: boolean;
494
+ }
495
+
496
+ export interface ResolvedOptions extends PreResolvedOptions {
497
+ isProduction: boolean;
487
498
  server?: ViteDevServer;
488
499
  }
489
500
 
@@ -17,7 +17,6 @@ const supportedStyleLangs = ['css', 'less', 'sass', 'scss', 'styl', 'stylus', 'p
17
17
  const supportedScriptLangs = ['ts'];
18
18
 
19
19
  function createViteScriptPreprocessor(): Preprocessor {
20
- // @ts-expect-error - allow return void
21
20
  return async ({ attributes, content, filename = '' }) => {
22
21
  const lang = attributes.lang as string;
23
22
  if (!supportedScriptLangs.includes(lang)) return;
@@ -26,7 +25,8 @@ function createViteScriptPreprocessor(): Preprocessor {
26
25
  tsconfigRaw: {
27
26
  compilerOptions: {
28
27
  // svelte typescript needs this flag to work with type imports
29
- importsNotUsedAsValues: 'preserve'
28
+ importsNotUsedAsValues: 'preserve',
29
+ preserveValueImports: true
30
30
  }
31
31
  }
32
32
  });
@@ -47,7 +47,6 @@ function createViteStylePreprocessor(config: ResolvedConfig): Preprocessor {
47
47
  throw new Error(`plugin ${pluginName} has no transform`);
48
48
  }
49
49
  const pluginTransform = plugin.transform!.bind(null as unknown as TransformPluginContext);
50
- // @ts-expect-error - allow return void
51
50
  return async ({ attributes, content, filename = '' }) => {
52
51
  const lang = attributes.lang as string;
53
52
  if (!supportedStyleLangs.includes(lang)) return;
@@ -56,20 +55,18 @@ function createViteStylePreprocessor(config: ResolvedConfig): Preprocessor {
56
55
  content,
57
56
  moduleId
58
57
  )) as TransformResult;
59
- // vite returns empty mappings that would kill svelte compiler before 3.43.0
60
- const hasMap = transformResult.map && transformResult.map.mappings !== '';
61
58
  // patch sourcemap source to point back to original filename
62
- if (hasMap && transformResult.map?.sources?.[0] === moduleId) {
59
+ if (transformResult.map?.sources?.[0] === moduleId) {
63
60
  transformResult.map.sources[0] = filename;
64
61
  }
65
62
  return {
66
63
  code: transformResult.code,
67
- map: hasMap ? transformResult.map : undefined
64
+ map: transformResult.map ?? undefined
68
65
  };
69
66
  };
70
67
  }
71
68
 
72
- export function createVitePreprocessorGroup(config: ResolvedConfig): PreprocessorGroup {
69
+ function createVitePreprocessorGroup(config: ResolvedConfig): PreprocessorGroup {
73
70
  return {
74
71
  markup({ content, filename }) {
75
72
  return preprocess(
@@ -1,20 +1,41 @@
1
1
  import path from 'path';
2
- import fs from 'fs';
3
- // @ts-ignore
4
- import relative from 'require-relative';
2
+ import { createRequire } from 'module';
3
+ import { is_common_without_svelte_field, resolveDependencyData } from './dependencies';
4
+ import { VitePluginSvelteCache } from './vite-plugin-svelte-cache';
5
5
 
6
- export function resolveViaPackageJsonSvelte(importee: string, importer?: string): string | void {
7
- if (importer && isBareImport(importee)) {
8
- const importeePkgFile = relative.resolve(`${importee}/package.json`, path.dirname(importer));
9
- const importeePkg = JSON.parse(fs.readFileSync(importeePkgFile, { encoding: 'utf-8' }));
10
- if (importeePkg.svelte) {
11
- return path.resolve(path.dirname(importeePkgFile), importeePkg.svelte);
6
+ export function resolveViaPackageJsonSvelte(
7
+ importee: string,
8
+ importer: string | undefined,
9
+ cache: VitePluginSvelteCache
10
+ ): string | void {
11
+ if (importer && isBareImport(importee) && !is_common_without_svelte_field(importee)) {
12
+ const cached = cache.getResolvedSvelteField(importee, importer);
13
+ if (cached) {
14
+ return cached;
15
+ }
16
+ const localRequire = createRequire(importer);
17
+ const pkgData = resolveDependencyData(importee, localRequire);
18
+ if (pkgData) {
19
+ const { pkg, dir } = pkgData;
20
+ if (pkg.svelte) {
21
+ const result = path.resolve(dir, pkg.svelte);
22
+ cache.setResolvedSvelteField(importee, importer, result);
23
+ return result;
24
+ }
25
+ } else {
26
+ throw new Error(`failed to resolve package.json of ${importee} imported by ${importer}`);
12
27
  }
13
28
  }
14
29
  }
15
30
 
16
31
  function isBareImport(importee: string): boolean {
17
- if (!importee || importee[0] === '.' || importee[0] === '\0' || path.isAbsolute(importee)) {
32
+ if (
33
+ !importee ||
34
+ importee[0] === '.' ||
35
+ importee[0] === '\0' ||
36
+ importee.includes(':') ||
37
+ path.isAbsolute(importee)
38
+ ) {
18
39
  return false;
19
40
  }
20
41
  const parts = importee.split('/');
@@ -6,6 +6,7 @@ export class VitePluginSvelteCache {
6
6
  private _js = new Map<string, Code>();
7
7
  private _dependencies = new Map<string, string[]>();
8
8
  private _dependants = new Map<string, Set<string>>();
9
+ private _resolvedSvelteFields = new Map<string, string>();
9
10
 
10
11
  public update(compileData: CompileData) {
11
12
  this.updateCSS(compileData);
@@ -80,4 +81,23 @@ export class VitePluginSvelteCache {
80
81
  const dependants = this._dependants.get(path);
81
82
  return dependants ? [...dependants] : [];
82
83
  }
84
+
85
+ public getResolvedSvelteField(name: string, importer?: string): string | void {
86
+ return this._resolvedSvelteFields.get(this._getResolvedSvelteFieldKey(name, importer));
87
+ }
88
+
89
+ public setResolvedSvelteField(
90
+ importee: string,
91
+ importer: string | undefined = undefined,
92
+ resolvedSvelte: string
93
+ ) {
94
+ this._resolvedSvelteFields.set(
95
+ this._getResolvedSvelteFieldKey(importee, importer),
96
+ resolvedSvelte
97
+ );
98
+ }
99
+
100
+ private _getResolvedSvelteFieldKey(importee: string, importer?: string): string {
101
+ return importer ? `${importer} > ${importee}` : importee;
102
+ }
83
103
  }
@@ -17,7 +17,7 @@ export function setupWatchers(
17
17
  return;
18
18
  }
19
19
  const { watcher, ws } = server;
20
- const { configFile: viteConfigFile, root, server: serverConfig } = server.config;
20
+ const { root, server: serverConfig } = server.config;
21
21
 
22
22
  const emitChangeEventOnDependants = (filename: string) => {
23
23
  const dependants = cache.getDependants(filename);
@@ -42,12 +42,9 @@ export function setupWatchers(
42
42
  };
43
43
 
44
44
  const triggerViteRestart = (filename: string) => {
45
- // vite restart is triggered by simulating a change to vite config. This requires that vite config exists
46
- // also we do not restart in middleware-mode as it could be risky
47
- if (!!viteConfigFile && !serverConfig.middlewareMode) {
48
- log.info(`svelte config changed: restarting vite server. - file: ${filename}`);
49
- watcher.emit('change', viteConfigFile);
50
- } else {
45
+ if (serverConfig.middlewareMode) {
46
+ // in middlewareMode we can't restart the server automatically
47
+ // show the user an overlay instead
51
48
  const message =
52
49
  'Svelte config change detected, restart your dev process to apply the changes.';
53
50
  log.info(message, filename);
@@ -55,6 +52,9 @@ export function setupWatchers(
55
52
  type: 'error',
56
53
  err: { message, stack: '', plugin: 'vite-plugin-svelte', id: filename }
57
54
  });
55
+ } else {
56
+ log.info(`svelte config changed: restarting vite server. - file: ${filename}`);
57
+ server.restart();
58
58
  }
59
59
  };
60
60