@sveltejs/vite-plugin-svelte 6.0.0-next.1 → 6.0.0-next.3

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.
@@ -1,14 +1,21 @@
1
1
  import type { Processed, CompileResult } from 'svelte/compiler';
2
2
  import type { SvelteRequest } from './id.d.ts';
3
3
  import type { ResolvedOptions } from './options.d.ts';
4
- import type { CustomPluginOptionsVite } from 'vite';
4
+ import type { CustomPluginOptionsVite, Rollup } from 'vite';
5
5
 
6
6
  export type CompileSvelte = (
7
7
  svelteRequest: SvelteRequest,
8
8
  code: string,
9
- options: Partial<ResolvedOptions>
9
+ options: Partial<ResolvedOptions>,
10
+ sourcemap?: Rollup.SourceMap
10
11
  ) => Promise<CompileData>;
11
12
 
13
+ export type PreprocessSvelte = (
14
+ svelteRequest: SvelteRequest,
15
+ code: string,
16
+ options: Partial<ResolvedOptions>
17
+ ) => Promise<Processed | undefined>;
18
+
12
19
  export interface Code {
13
20
  code: string;
14
21
  map?: any;
@@ -23,9 +30,8 @@ export interface Code {
23
30
  export interface CompileData {
24
31
  filename: string;
25
32
  normalizedFilename: string;
33
+ cssId: string;
26
34
  lang: string;
27
35
  compiled: CompileResult;
28
36
  ssr: boolean | undefined;
29
- dependencies: string[];
30
- preprocessed: Processed;
31
37
  }
package/src/types/id.d.ts CHANGED
@@ -1,16 +1,9 @@
1
- import type { CompileOptions } from 'svelte/compiler';
2
-
3
- export type SvelteQueryTypes = 'style' | 'script' | 'preprocessed' | 'all';
1
+ export type SvelteQueryTypes = 'style';
4
2
 
5
3
  export interface RequestQuery {
6
4
  // our own
7
5
  svelte?: boolean;
8
6
  type?: SvelteQueryTypes;
9
- sourcemap?: boolean;
10
- compilerOptions?: Pick<
11
- CompileOptions,
12
- 'generate' | 'dev' | 'css' | 'customElement' | 'immutable'
13
- >;
14
7
  // vite specific
15
8
  url?: boolean;
16
9
  raw?: boolean;
@@ -1,11 +1,10 @@
1
1
  import type { ResolvedOptions } from './options.d.ts';
2
+ import type { IdFilter, IdParser } from './id.d.ts';
3
+ import type { CompileSvelte } from './compile.d.ts';
2
4
 
3
5
  export interface PluginAPI {
4
- /**
5
- * must not be modified, should not be used outside of vite-plugin-svelte repo
6
- * @internal
7
- * @experimental
8
- */
9
- options?: ResolvedOptions;
10
- // TODO expose compile cache here so other utility plugins can use it
6
+ options: ResolvedOptions;
7
+ idFilter: IdFilter;
8
+ idParser: IdParser;
9
+ compileSvelte: CompileSvelte;
11
10
  }
@@ -2,10 +2,6 @@ import * as svelte from 'svelte/compiler';
2
2
  import { safeBase64Hash } from './hash.js';
3
3
  import { log } from './log.js';
4
4
 
5
- import {
6
- checkPreprocessDependencies,
7
- createInjectScopeEverythingRulePreprocessorGroup
8
- } from './preprocess.js';
9
5
  import { mapToRelative } from './sourcemaps.js';
10
6
  import { enhanceCompileError } from './error.js';
11
7
 
@@ -21,13 +17,10 @@ const scriptLangRE =
21
17
  export function createCompileSvelte() {
22
18
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection | undefined} */
23
19
  let stats;
24
- const devStylePreprocessor = createInjectScopeEverythingRulePreprocessorGroup();
25
20
  /** @type {import('../types/compile.d.ts').CompileSvelte} */
26
- return async function compileSvelte(svelteRequest, code, options) {
21
+ return async function compileSvelte(svelteRequest, code, options, sourcemap) {
27
22
  const { filename, normalizedFilename, cssId, ssr, raw } = svelteRequest;
28
23
  const { emitCss = true } = options;
29
- /** @type {string[]} */
30
- const dependencies = [];
31
24
  /** @type {import('svelte/compiler').Warning[]} */
32
25
  const warnings = [];
33
26
 
@@ -55,6 +48,7 @@ export function createCompileSvelte() {
55
48
  // also they for hmr updates too
56
49
  }
57
50
  }
51
+
58
52
  /** @type {import('svelte/compiler').CompileOptions} */
59
53
  const compileOptions = {
60
54
  ...options.compilerOptions,
@@ -62,53 +56,18 @@ export function createCompileSvelte() {
62
56
  generate: ssr ? 'server' : 'client'
63
57
  };
64
58
 
59
+ let finalCode = code;
65
60
  if (compileOptions.hmr && options.emitCss) {
66
61
  const hash = `s-${safeBase64Hash(normalizedFilename)}`;
67
62
  compileOptions.cssHash = () => hash;
68
- }
69
-
70
- let preprocessed;
71
- let preprocessors = options.preprocess;
72
- if (!options.isBuild && options.emitCss && compileOptions.hmr) {
73
- // inject preprocessor that ensures css hmr works better
74
- if (!Array.isArray(preprocessors)) {
75
- preprocessors = preprocessors
76
- ? [preprocessors, devStylePreprocessor]
77
- : [devStylePreprocessor];
78
- } else {
79
- preprocessors = preprocessors.concat(devStylePreprocessor);
63
+ const closeStylePos = code.lastIndexOf('</style>');
64
+ if (closeStylePos > -1) {
65
+ // inject rule that forces compile to attach scope class to every node in the template
66
+ // this reduces the amount of js hot updates when editing css in .svelte files
67
+ finalCode = finalCode.slice(0, closeStylePos) + ' *{}' + finalCode.slice(closeStylePos);
80
68
  }
81
69
  }
82
- if (preprocessors) {
83
- try {
84
- preprocessed = await svelte.preprocess(code, preprocessors, { filename }); // full filename here so postcss works
85
- } catch (e) {
86
- e.message = `Error while preprocessing ${filename}${e.message ? ` - ${e.message}` : ''}`;
87
- throw e;
88
- }
89
70
 
90
- if (preprocessed.dependencies?.length) {
91
- const checked = checkPreprocessDependencies(filename, preprocessed.dependencies);
92
- if (checked.warnings.length) {
93
- warnings.push(...checked.warnings);
94
- }
95
- if (checked.dependencies.length) {
96
- dependencies.push(...checked.dependencies);
97
- }
98
- }
99
-
100
- if (preprocessed.map) compileOptions.sourcemap = preprocessed.map;
101
- }
102
- if (typeof preprocessed?.map === 'object') {
103
- mapToRelative(preprocessed?.map, filename);
104
- }
105
- if (raw && svelteRequest.query.type === 'preprocessed') {
106
- // @ts-expect-error shortcut
107
- return /** @type {import('../types/compile.d.ts').CompileData} */ {
108
- preprocessed: preprocessed ?? { code }
109
- };
110
- }
111
- const finalCode = preprocessed ? preprocessed.code : code;
112
71
  const dynamicCompileOptions = await options?.dynamicCompileOptions?.({
113
72
  filename,
114
73
  code: finalCode,
@@ -127,6 +86,9 @@ export function createCompileSvelte() {
127
86
  ...dynamicCompileOptions
128
87
  }
129
88
  : compileOptions;
89
+ if (sourcemap) {
90
+ finalCompileOptions.sourcemap = sourcemap;
91
+ }
130
92
  const endStat = stats?.start(filename);
131
93
  /** @type {import('svelte/compiler').CompileResult} */
132
94
  let compiled;
@@ -145,7 +107,7 @@ export function createCompileSvelte() {
145
107
  );
146
108
  }
147
109
  } catch (e) {
148
- enhanceCompileError(e, code, preprocessors);
110
+ enhanceCompileError(e, code, options.preprocess);
149
111
  throw e;
150
112
  }
151
113
 
@@ -181,11 +143,10 @@ export function createCompileSvelte() {
181
143
  return {
182
144
  filename,
183
145
  normalizedFilename,
146
+ cssId,
184
147
  lang,
185
148
  compiled,
186
- ssr,
187
- dependencies,
188
- preprocessed: preprocessed ?? { code }
149
+ ssr
189
150
  };
190
151
  };
191
152
  }
@@ -26,11 +26,11 @@ export const SVELTE_EXPORT_CONDITIONS = ['svelte'];
26
26
  export const FAQ_LINK_MISSING_EXPORTS_CONDITION =
27
27
  'https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#missing-exports-condition';
28
28
 
29
+ export const LINK_TRANSFORM_WITH_PLUGIN =
30
+ 'https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/advanced-usage.md#transform-svelte-files-with-vite-plugins';
31
+
29
32
  export const DEFAULT_SVELTE_EXT = ['.svelte'];
30
33
  export const DEFAULT_SVELTE_MODULE_INFIX = ['.svelte.'];
31
34
  export const DEFAULT_SVELTE_MODULE_EXT = ['.js', '.ts'];
32
35
 
33
- export const SVELTE_VIRTUAL_STYLE_SUFFIX = '?svelte&type=style&lang.css';
34
- export const SVELTE_VIRTUAL_STYLE_ID_REGEX = new RegExp(
35
- `${SVELTE_VIRTUAL_STYLE_SUFFIX.replace(/[?.]/g, '\\$&')}$`
36
- );
36
+ export const SVELTE_VIRTUAL_STYLE_ID_REGEX = /[?&]svelte&type=style&lang.css$/;
@@ -1,32 +1,3 @@
1
- import path from 'node:path';
2
- import fs from 'node:fs/promises';
3
- import { findDepPkgJsonPath } from 'vitefu';
4
-
5
- /**
6
- * @typedef {{
7
- * dir: string;
8
- * pkg: Record<string, any>;
9
- * }} DependencyData
10
- */
11
-
12
- /**
13
- * @param {string} dep
14
- * @param {string} parent
15
- * @returns {Promise<DependencyData | undefined>}
16
- */
17
- export async function resolveDependencyData(dep, parent) {
18
- const depDataPath = await findDepPkgJsonPath(dep, parent);
19
- if (!depDataPath) return undefined;
20
- try {
21
- return {
22
- dir: path.dirname(depDataPath),
23
- pkg: JSON.parse(await fs.readFile(depDataPath, 'utf-8'))
24
- };
25
- } catch {
26
- return undefined;
27
- }
28
- }
29
-
30
1
  const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
31
2
  '@lukeed/uuid',
32
3
  '@playwright/test',
package/src/utils/id.js CHANGED
@@ -5,7 +5,8 @@ import { log } from './log.js';
5
5
  import {
6
6
  DEFAULT_SVELTE_EXT,
7
7
  DEFAULT_SVELTE_MODULE_EXT,
8
- DEFAULT_SVELTE_MODULE_INFIX
8
+ DEFAULT_SVELTE_MODULE_INFIX,
9
+ SVELTE_VIRTUAL_STYLE_ID_REGEX
9
10
  } from './constants.js';
10
11
  import { arraify } from './options.js';
11
12
 
@@ -179,13 +180,15 @@ export function buildIdFilter(options) {
179
180
  .map(escapeRE)
180
181
  .join('|')})(?:[?#]|$)`
181
182
  );
182
- const filter = {
183
+ return {
183
184
  id: {
184
185
  include: [extensionsRE, .../**@type {Array<string|RegExp>}*/ arraify(include)],
185
- exclude: /**@type {Array<string|RegExp>}*/ arraify(exclude)
186
+ exclude: /**@type {Array<string|RegExp>}*/ [
187
+ SVELTE_VIRTUAL_STYLE_ID_REGEX, // exclude from regular pipeline, we load it in a separate plugin
188
+ ...arraify(exclude)
189
+ ]
186
190
  }
187
191
  };
188
- return filter;
189
192
  }
190
193
 
191
194
  /**
@@ -6,10 +6,9 @@ const {
6
6
  defaultClientConditions,
7
7
  defaultServerConditions,
8
8
  normalizePath,
9
- //@ts-expect-error rolldownVersion not in type
10
- rolldownVersion
9
+ searchForWorkspaceRoot
11
10
  } = vite;
12
- import { isDebugNamespaceEnabled, log } from './log.js';
11
+ import { log } from './log.js';
13
12
  import { loadSvelteConfig } from './load-svelte-config.js';
14
13
  import {
15
14
  DEFAULT_SVELTE_EXT,
@@ -20,12 +19,6 @@ import {
20
19
  } from './constants.js';
21
20
 
22
21
  import path from 'node:path';
23
- import {
24
- optimizeSvelteModulePluginName,
25
- optimizeSveltePluginName,
26
- patchESBuildOptimizerPlugin,
27
- patchRolldownOptimizerPlugin
28
- } from './optimizer-plugins.js';
29
22
  import { addExtraPreprocessors } from './preprocess.js';
30
23
  import deepmerge from 'deepmerge';
31
24
  import {
@@ -37,7 +30,6 @@ import {
37
30
  } from 'vitefu';
38
31
 
39
32
  import { isCommonDepWithoutSvelteField } from './dependencies.js';
40
- import { VitePluginSvelteStats } from './vite-plugin-svelte-stats.js';
41
33
 
42
34
  const allowedPluginOptions = new Set([
43
35
  'include',
@@ -198,10 +190,9 @@ function mergeConfigs(...configs) {
198
190
  *
199
191
  * @param {import('../types/options.d.ts').PreResolvedOptions} preResolveOptions
200
192
  * @param {import('vite').ResolvedConfig} viteConfig
201
- * @param {import('./vite-plugin-svelte-cache.js').VitePluginSvelteCache} cache
202
193
  * @returns {import('../types/options.d.ts').ResolvedOptions}
203
194
  */
204
- export function resolveOptions(preResolveOptions, viteConfig, cache) {
195
+ export function resolveOptions(preResolveOptions, viteConfig) {
205
196
  const css = preResolveOptions.emitCss ? 'external' : 'injected';
206
197
  /** @type {Partial<import('../public.d.ts').Options>} */
207
198
  const defaultOptions = {
@@ -230,10 +221,7 @@ export function resolveOptions(preResolveOptions, viteConfig, cache) {
230
221
  addExtraPreprocessors(merged, viteConfig);
231
222
  enforceOptionsForHmr(merged, viteConfig);
232
223
  enforceOptionsForProduction(merged);
233
- // mergeConfigs would mangle functions on the stats class, so do this afterwards
234
- if (log.debug.enabled && isDebugNamespaceEnabled('stats')) {
235
- merged.stats = new VitePluginSvelteStats(cache);
236
- }
224
+
237
225
  return merged;
238
226
  }
239
227
 
@@ -384,46 +372,6 @@ export async function buildExtraViteConfig(options, config) {
384
372
  ]
385
373
  };
386
374
 
387
- // handle prebundling for svelte files
388
- if (options.prebundleSvelteLibraries) {
389
- extraViteConfig.optimizeDeps = {
390
- ...extraViteConfig.optimizeDeps,
391
- // Experimental Vite API to allow these extensions to be scanned and prebundled
392
- extensions: options.extensions ?? ['.svelte']
393
- };
394
- // Add optimizer plugins to prebundle Svelte files.
395
- // Currently a placeholder as more information is needed after Vite config is resolved,
396
- // the added plugins are patched in `patchResolvedViteConfig()`
397
- if (rolldownVersion) {
398
- /**
399
- *
400
- * @param {string} name
401
- * @returns {import('vite').Rollup.Plugin}
402
- */
403
- const placeholderRolldownOptimizerPlugin = (name) => ({
404
- name,
405
- options() {},
406
- buildStart() {},
407
- buildEnd() {},
408
- transform: { filter: { id: /^$/ }, handler() {} }
409
- });
410
- //@ts-expect-error rolldown types not finished
411
- extraViteConfig.optimizeDeps.rollupOptions = {
412
- plugins: [
413
- placeholderRolldownOptimizerPlugin(optimizeSveltePluginName),
414
- placeholderRolldownOptimizerPlugin(optimizeSvelteModulePluginName)
415
- ]
416
- };
417
- } else {
418
- extraViteConfig.optimizeDeps.esbuildOptions = {
419
- plugins: [
420
- { name: optimizeSveltePluginName, setup: () => {} },
421
- { name: optimizeSvelteModulePluginName, setup: () => {} }
422
- ]
423
- };
424
- }
425
- }
426
-
427
375
  // enable hmrPartialAccept if not explicitly disabled
428
376
  if (config.experimental?.hmrPartialAccept !== false) {
429
377
  log.debug('enabling "experimental.hmrPartialAccept" in vite config', undefined, 'config');
@@ -482,6 +430,7 @@ async function buildExtraConfigForDependencies(options, config) {
482
430
  const packagesWithoutSvelteExportsCondition = new Set();
483
431
  const depsConfig = await crawlFrameworkPkgs({
484
432
  root: options.root,
433
+ workspaceRoot: searchForWorkspaceRoot(options.root),
485
434
  isBuild: options.isBuild,
486
435
  viteUserConfig: config,
487
436
  isFrameworkPkgByJson(pkgJson) {
@@ -514,11 +463,12 @@ async function buildExtraConfigForDependencies(options, config) {
514
463
  }
515
464
  });
516
465
  if (
466
+ !options.isBuild &&
517
467
  !options.experimental?.disableSvelteResolveWarnings &&
518
468
  packagesWithoutSvelteExportsCondition?.size > 0
519
469
  ) {
520
- log.warn(
521
- `WARNING: The following packages have a svelte field in their package.json but no exports condition for svelte.\n\n${[
470
+ log.info.once(
471
+ `The following packages have a svelte field in their package.json but no exports condition for svelte.\n\n${[
522
472
  ...packagesWithoutSvelteExportsCondition
523
473
  ].join('\n')}\n\nPlease see ${FAQ_LINK_MISSING_EXPORTS_CONDITION} for details.`
524
474
  );
@@ -607,38 +557,6 @@ function buildExtraConfigForSvelte(config) {
607
557
  return { optimizeDeps: { include, exclude }, ssr: { noExternal, external } };
608
558
  }
609
559
 
610
- /**
611
- * @param {import('vite').ResolvedConfig} viteConfig
612
- * @param {import('../types/options.d.ts').ResolvedOptions} options
613
- */
614
- export function patchResolvedViteConfig(viteConfig, options) {
615
- if (options.preprocess) {
616
- for (const preprocessor of arraify(options.preprocess)) {
617
- if (preprocessor.style && '__resolvedConfig' in preprocessor.style) {
618
- preprocessor.style.__resolvedConfig = viteConfig;
619
- }
620
- }
621
- }
622
- if (rolldownVersion) {
623
- const plugins =
624
- // @ts-expect-error not typed
625
- viteConfig.optimizeDeps.rollupOptions?.plugins?.filter((p) =>
626
- [optimizeSveltePluginName, optimizeSvelteModulePluginName].includes(p.name)
627
- ) ?? [];
628
- for (const plugin of plugins) {
629
- patchRolldownOptimizerPlugin(plugin, options);
630
- }
631
- } else {
632
- const plugins =
633
- viteConfig.optimizeDeps.esbuildOptions?.plugins?.filter((p) =>
634
- [optimizeSveltePluginName, optimizeSvelteModulePluginName].includes(p.name)
635
- ) ?? [];
636
- for (const plugin of plugins) {
637
- patchESBuildOptimizerPlugin(plugin, options);
638
- }
639
- }
640
- }
641
-
642
560
  /**
643
561
  * Mutates `config` to ensure `resolve.mainFields` is set. If unset, it emulates Vite's default fallback.
644
562
  * @param {string} name
@@ -1,32 +1,5 @@
1
- import MagicString from 'magic-string';
2
1
  import { log } from './log.js';
3
- import path from 'node:path';
4
- import { normalizePath } from 'vite';
5
-
6
- /**
7
- * this appends a *{} rule to component styles to force the svelte compiler to add style classes to all nodes
8
- * That means adding/removing class rules from <style> node won't trigger js updates as the scope classes are not changed
9
- *
10
- * only used during dev with enabled css hmr
11
- *
12
- * @returns {import('svelte/compiler').PreprocessorGroup}
13
- */
14
- export function createInjectScopeEverythingRulePreprocessorGroup() {
15
- return {
16
- name: 'inject-scope-everything-rule',
17
- style({ content, filename }) {
18
- const s = new MagicString(content);
19
- s.append(' *{}');
20
- return {
21
- code: s.toString(),
22
- map: s.generateDecodedMap({
23
- source: filename ? path.basename(filename) : undefined,
24
- hires: true
25
- })
26
- };
27
- }
28
- };
29
- }
2
+ import { LINK_TRANSFORM_WITH_PLUGIN } from './constants.js';
30
3
 
31
4
  /**
32
5
  * @param {import('../types/options.d.ts').ResolvedOptions} options
@@ -42,32 +15,24 @@ function buildExtraPreprocessors(options, config) {
42
15
  /** @type {import('svelte/compiler').PreprocessorGroup[]} */
43
16
  const appendPreprocessors = [];
44
17
 
45
- // @ts-expect-error not typed
46
- const pluginsWithPreprocessorsDeprecated = config.plugins.filter((p) => p?.sveltePreprocess);
47
- if (pluginsWithPreprocessorsDeprecated.length > 0) {
48
- log.warn(
49
- `The following plugins use the deprecated 'plugin.sveltePreprocess' field. Please contact their maintainers and ask them to move it to 'plugin.api.sveltePreprocess': ${pluginsWithPreprocessorsDeprecated
18
+ /** @type {import('vite').Plugin[]} */
19
+ const pluginsWithPreprocessors = config.plugins.filter((p) => p?.api?.sveltePreprocess);
20
+
21
+ if (
22
+ !options.isBuild &&
23
+ !options.experimental?.disableApiSveltePreprocessWarnings &&
24
+ pluginsWithPreprocessors.length > 0
25
+ ) {
26
+ log.info.once(
27
+ `The following plugins use the deprecated 'plugin.api.sveltePreprocess' field: ${pluginsWithPreprocessors
50
28
  .map((p) => p.name)
51
- .join(', ')}`
29
+ .join(', ')}
30
+ Please contact their maintainers and ask them to use a vite plugin transform instead.
31
+ See ${LINK_TRANSFORM_WITH_PLUGIN} for more information.
32
+ `.replace(/\t+/g, '\t')
52
33
  );
53
- // patch plugin to avoid breaking
54
- pluginsWithPreprocessorsDeprecated.forEach((p) => {
55
- if (!p.api) {
56
- p.api = {};
57
- }
58
- if (p.api.sveltePreprocess === undefined) {
59
- // @ts-expect-error not typed
60
- p.api.sveltePreprocess = p.sveltePreprocess;
61
- } else {
62
- log.error(
63
- `ignoring plugin.sveltePreprocess of ${p.name} because it already defined plugin.api.sveltePreprocess.`
64
- );
65
- }
66
- });
67
34
  }
68
35
  /** @type {import('vite').Plugin[]} */
69
- const pluginsWithPreprocessors = config.plugins.filter((p) => p?.api?.sveltePreprocess);
70
- /** @type {import('vite').Plugin[]} */
71
36
  const ignored = [];
72
37
  /** @type {import('vite').Plugin[]} */
73
38
  const included = [];
@@ -122,52 +87,3 @@ export function addExtraPreprocessors(options, config) {
122
87
  }
123
88
  }
124
89
  }
125
-
126
- /**
127
- *
128
- * @param filename {string}
129
- * @param dependencies {string[]}
130
- * @returns {({dependencies: string[], warnings:import('svelte/compiler').Warning[] })}
131
- */
132
- export function checkPreprocessDependencies(filename, dependencies) {
133
- /** @type {import('svelte/compiler').Warning[]} */
134
- const warnings = [];
135
-
136
- // to find self, we have to compare normalized filenames, but must keep the original values in `dependencies`
137
- // because otherwise file watching on windows doesn't work
138
- // so we track idx and filter by that in the end
139
- /** @type {number[]} */
140
- const selfIdx = [];
141
- const normalizedFullFilename = normalizePath(filename);
142
- const normalizedDeps = dependencies.map(normalizePath);
143
- for (let i = 0; i < normalizedDeps.length; i++) {
144
- if (normalizedDeps[i] === normalizedFullFilename) {
145
- selfIdx.push(i);
146
- }
147
- }
148
- const hasSelfDependency = selfIdx.length > 0;
149
- if (hasSelfDependency) {
150
- warnings.push({
151
- code: 'vite-plugin-svelte-preprocess-depends-on-self',
152
- message:
153
- 'svelte.preprocess returned this file as a dependency of itself. This can be caused by an invalid configuration or importing generated code that depends on .svelte files (eg. tailwind base css)',
154
- filename
155
- });
156
- }
157
-
158
- if (dependencies.length > 10) {
159
- warnings.push({
160
- code: 'vite-plugin-svelte-preprocess-many-dependencies',
161
- message: `svelte.preprocess depends on more than 10 external files which can cause slow builds and poor DX, try to reduce them. Found: ${dependencies.join(
162
- ', '
163
- )}`,
164
- filename
165
- });
166
- }
167
- return {
168
- dependencies: hasSelfDependency
169
- ? dependencies.filter((_, i) => !selfIdx.includes(i)) // remove self dependency
170
- : dependencies,
171
- warnings
172
- };
173
- }
@@ -1,6 +1,9 @@
1
1
  import { log } from './log.js';
2
2
  import { performance } from 'node:perf_hooks';
3
3
  import { normalizePath } from 'vite';
4
+ import { findClosestPkgJsonPath } from 'vitefu';
5
+ import { readFileSync } from 'node:fs';
6
+ import { dirname } from 'node:path';
4
7
 
5
8
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').CollectionOptions} */
6
9
  const defaultCollectionOptions = {
@@ -63,19 +66,12 @@ function formatPackageStats(pkgStats) {
63
66
  * @class
64
67
  */
65
68
  export class VitePluginSvelteStats {
66
- // package directory -> package name
67
- /** @type {import('./vite-plugin-svelte-cache.js').VitePluginSvelteCache} */
68
- #cache;
69
+ /** @type {PackageInfo[]} */
70
+ #packageInfos = [];
71
+
69
72
  /** @type {import('../types/vite-plugin-svelte-stats.d.ts').StatCollection[]} */
70
73
  #collections = [];
71
74
 
72
- /**
73
- * @param {import('./vite-plugin-svelte-cache.js').VitePluginSvelteCache} cache
74
- */
75
- constructor(cache) {
76
- this.#cache = cache;
77
- }
78
-
79
75
  /**
80
76
  * @param {string} name
81
77
  * @param {Partial<import('../types/vite-plugin-svelte-stats.d.ts').CollectionOptions>} [opts]
@@ -173,7 +169,7 @@ export class VitePluginSvelteStats {
173
169
  async #aggregateStatsResult(collection) {
174
170
  const stats = collection.stats;
175
171
  for (const stat of stats) {
176
- stat.pkg = (await this.#cache.getPackageInfo(stat.file)).name;
172
+ stat.pkg = (await this.#getPackageInfo(stat.file)).name;
177
173
  }
178
174
 
179
175
  // group stats
@@ -197,4 +193,56 @@ export class VitePluginSvelteStats {
197
193
  groups.sort((a, b) => b.duration - a.duration);
198
194
  collection.packageStats = groups;
199
195
  }
196
+ /**
197
+ * @param {string} file
198
+ * @returns {Promise<PackageInfo>}
199
+ */
200
+ async #getPackageInfo(file) {
201
+ let info = this.#packageInfos.find((pi) => file.startsWith(pi.path));
202
+ if (!info) {
203
+ info = await findPackageInfo(file);
204
+ this.#packageInfos.push(info);
205
+ }
206
+ return info;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * @typedef {{
212
+ * name: string;
213
+ * version: string;
214
+ * svelte?: string;
215
+ * path: string;
216
+ * }} PackageInfo
217
+ */
218
+
219
+ /**
220
+ * utility to get some info from the closest package.json with a "name" set
221
+ *
222
+ * @param {string} file to find info for
223
+ * @returns {Promise<PackageInfo>}
224
+ */
225
+ async function findPackageInfo(file) {
226
+ /** @type {PackageInfo} */
227
+ const info = {
228
+ name: '$unknown',
229
+ version: '0.0.0-unknown',
230
+ path: '$unknown'
231
+ };
232
+ let path = await findClosestPkgJsonPath(file, (pkgPath) => {
233
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
234
+ if (pkg.name != null) {
235
+ info.name = pkg.name;
236
+ if (pkg.version != null) {
237
+ info.version = pkg.version;
238
+ }
239
+ info.svelte = pkg.svelte;
240
+ return true;
241
+ }
242
+ return false;
243
+ });
244
+ // return normalized path with appended '/' so .startsWith works for future file checks
245
+ path = normalizePath(dirname(path ?? file)) + '/';
246
+ info.path = path;
247
+ return info;
200
248
  }