@sveltejs/vite-plugin-svelte 3.0.0-next.0 → 3.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,19 +1,21 @@
1
1
  {
2
2
  "name": "@sveltejs/vite-plugin-svelte",
3
- "version": "3.0.0-next.0",
3
+ "version": "3.0.0-next.2",
4
4
  "license": "MIT",
5
5
  "author": "dominikg",
6
6
  "files": [
7
- "src"
7
+ "src",
8
+ "types"
8
9
  ],
9
10
  "type": "module",
10
- "types": "src/index.d.ts",
11
+ "types": "types/index.d.ts",
11
12
  "exports": {
12
13
  ".": {
13
- "types": "./src/index.d.ts",
14
- "import": "./src/index.js"
15
- },
16
- "./package.json": "./package.json"
14
+ "import": {
15
+ "types": "./types/index.d.ts",
16
+ "default": "./src/index.js"
17
+ }
18
+ }
17
19
  },
18
20
  "engines": {
19
21
  "node": "^18.0.0 || >=20"
@@ -34,26 +36,28 @@
34
36
  },
35
37
  "homepage": "https://github.com/sveltejs/vite-plugin-svelte#readme",
36
38
  "dependencies": {
39
+ "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0-next.0 || ^2.0.0",
37
40
  "debug": "^4.3.4",
38
41
  "deepmerge": "^4.3.1",
39
42
  "kleur": "^4.1.5",
40
- "magic-string": "^0.30.3",
43
+ "magic-string": "^0.30.5",
41
44
  "svelte-hmr": "^0.15.3",
42
- "vitefu": "^0.2.4",
43
- "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0-next.0"
45
+ "vitefu": "^0.2.5"
44
46
  },
45
47
  "peerDependencies": {
46
48
  "svelte": "^4.0.0",
47
49
  "vite": "^5.0.0-beta.1 || ^5.0.0"
48
50
  },
49
51
  "devDependencies": {
50
- "@types/debug": "^4.1.8",
51
- "esbuild": "^0.19.3",
52
- "svelte": "^4.2.0",
53
- "vite": "^5.0.0-beta.1"
52
+ "@types/debug": "^4.1.10",
53
+ "esbuild": "^0.19.5",
54
+ "sass": "^1.69.5",
55
+ "svelte": "^4.2.2",
56
+ "vite": "^5.0.0-beta.12"
54
57
  },
55
58
  "scripts": {
56
59
  "check:publint": "publint --strict",
57
- "check:types": "tsc --noEmit"
60
+ "check:types": "tsc --noEmit",
61
+ "generate:types": "dts-buddy -m \"@sveltejs/vite-plugin-svelte:src/public.d.ts\""
58
62
  }
59
63
  }
package/src/index.js CHANGED
@@ -20,7 +20,10 @@ import { saveSvelteMetadata } from './utils/optimizer.js';
20
20
  import { VitePluginSvelteCache } from './utils/vite-plugin-svelte-cache.js';
21
21
  import { loadRaw } from './utils/load-raw.js';
22
22
 
23
- /** @type {import('./index.d.ts').svelte} */
23
+ /**
24
+ * @param {Partial<import('./public.d.ts').Options>} [inlineOptions]
25
+ * @returns {import('vite').Plugin[]}
26
+ */
24
27
  export function svelte(inlineOptions) {
25
28
  if (process.env.DEBUG != null) {
26
29
  log.setLevel('debug');
package/src/preprocess.js CHANGED
@@ -1,19 +1,21 @@
1
- import { preprocessCSS, resolveConfig, transformWithEsbuild } from 'vite';
1
+ import { isCSSRequest, preprocessCSS, resolveConfig, transformWithEsbuild } from 'vite';
2
2
  import { mapToRelative, removeLangSuffix } from './utils/sourcemaps.js';
3
3
 
4
4
  /**
5
5
  * @typedef {(code: string, filename: string) => Promise<{ code: string; map?: any; deps?: Set<string> }>} CssTransform
6
6
  */
7
7
 
8
- const supportedStyleLangs = ['css', 'less', 'sass', 'scss', 'styl', 'stylus', 'postcss', 'sss'];
9
8
  const supportedScriptLangs = ['ts'];
10
9
 
11
- export const lang_sep = '.vite-preprocess.';
10
+ export const lang_sep = '.vite-preprocess';
12
11
 
13
- /** @type {import('./index.d.ts').vitePreprocess} */
12
+ /**
13
+ * @param {import('./public.d.ts').VitePreprocessOptions} opts
14
+ * @returns {import('svelte/compiler').PreprocessorGroup}
15
+ */
14
16
  export function vitePreprocess(opts) {
15
- /** @type {import('svelte/types/compiler/preprocess').PreprocessorGroup} */
16
- const preprocessor = {};
17
+ /** @type {import('svelte/compiler').PreprocessorGroup} */
18
+ const preprocessor = { name: 'vite-preprocess' };
17
19
  if (opts?.script !== false) {
18
20
  preprocessor.script = viteScript().script;
19
21
  }
@@ -25,7 +27,7 @@ export function vitePreprocess(opts) {
25
27
  }
26
28
 
27
29
  /**
28
- * @returns {{ script: import('svelte/types/compiler/preprocess').Preprocessor }}
30
+ * @returns {{ script: import('svelte/compiler').Preprocessor }}
29
31
  */
30
32
  function viteScript() {
31
33
  return {
@@ -56,15 +58,15 @@ function viteScript() {
56
58
 
57
59
  /**
58
60
  * @param {import('vite').ResolvedConfig | import('vite').InlineConfig} config
59
- * @returns {{ style: import('svelte/types/compiler/preprocess').Preprocessor }}
61
+ * @returns {{ style: import('svelte/compiler').Preprocessor }}
60
62
  */
61
63
  function viteStyle(config = {}) {
62
64
  /** @type {CssTransform} */
63
65
  let transform;
64
- /** @type {import('svelte/types/compiler/preprocess').Preprocessor} */
66
+ /** @type {import('svelte/compiler').Preprocessor} */
65
67
  const style = async ({ attributes, content, filename = '' }) => {
66
- const lang = /** @type {string} */ (attributes.lang);
67
- if (!supportedStyleLangs.includes(lang)) return;
68
+ const ext = attributes.lang ? `.${attributes.lang}` : '.css';
69
+ if (attributes.lang && !isCSSRequest(ext)) return;
68
70
  if (!transform) {
69
71
  /** @type {import('vite').ResolvedConfig} */
70
72
  let resolvedConfig;
@@ -82,7 +84,7 @@ function viteStyle(config = {}) {
82
84
  }
83
85
  transform = getCssTransformFn(resolvedConfig);
84
86
  }
85
- const suffix = `${lang_sep}${lang}`;
87
+ const suffix = `${lang_sep}${ext}`;
86
88
  const moduleId = `${filename}${suffix}`;
87
89
  const { code, map, deps } = await transform(content, moduleId);
88
90
  removeLangSuffix(map, suffix);
@@ -1,9 +1,10 @@
1
- import type { InlineConfig, ResolvedConfig, UserConfig, Plugin } from 'vite';
2
- import type { CompileOptions, Warning } from 'svelte/types/compiler/interfaces';
3
- import type { PreprocessorGroup } from 'svelte/types/compiler/preprocess';
1
+ import type { InlineConfig, ResolvedConfig } from 'vite';
2
+ import type { CompileOptions } from 'svelte/compiler';
3
+ import type { Warning } from 'svelte/types/compiler/interfaces';
4
+ import type { PreprocessorGroup } from 'svelte/compiler';
4
5
  import type { Options as InspectorOptions } from '@sveltejs/vite-plugin-svelte-inspector';
5
6
 
6
- type Options = Omit<SvelteOptions, 'vitePlugin'> & PluginOptionsInline;
7
+ export type Options = Omit<SvelteConfig, 'vitePlugin'> & PluginOptionsInline;
7
8
 
8
9
  interface PluginOptionsInline extends PluginOptions {
9
10
  /**
@@ -94,13 +95,39 @@ interface PluginOptions {
94
95
  * @default unset for dev, always false for build
95
96
  */
96
97
  inspector?: InspectorOptions | boolean;
98
+
99
+ /**
100
+ * A function to update `compilerOptions` before compilation
101
+ *
102
+ * `data.filename` - The file to be compiled
103
+ * `data.code` - The preprocessed Svelte code
104
+ * `data.compileOptions` - The current compiler options
105
+ *
106
+ * To change part of the compiler options, return an object with the changes you need.
107
+ *
108
+ * @example
109
+ * ```
110
+ * ({ filename, compileOptions }) => {
111
+ * // Dynamically set hydration per Svelte file
112
+ * if (compileWithHydratable(filename) && !compileOptions.hydratable) {
113
+ * return { hydratable: true };
114
+ * }
115
+ * }
116
+ * ```
117
+ */
118
+ dynamicCompileOptions?: (data: {
119
+ filename: string;
120
+ code: string;
121
+ compileOptions: Partial<CompileOptions>;
122
+ }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
123
+
97
124
  /**
98
125
  * These options are considered experimental and breaking changes to them can occur in any release
99
126
  */
100
127
  experimental?: ExperimentalOptions;
101
128
  }
102
129
 
103
- interface SvelteOptions {
130
+ export interface SvelteConfig {
104
131
  /**
105
132
  * A list of file extensions to be compiled by Svelte
106
133
  *
@@ -121,6 +148,7 @@ interface SvelteOptions {
121
148
  * @see https://svelte.dev/docs#svelte_compile
122
149
  */
123
150
  compilerOptions?: Omit<CompileOptions, 'filename' | 'format' | 'generate'>;
151
+
124
152
  /**
125
153
  * Handles warning emitted from the Svelte compiler
126
154
  */
@@ -135,30 +163,6 @@ interface SvelteOptions {
135
163
  * These options are considered experimental and breaking changes to them can occur in any release
136
164
  */
137
165
  interface ExperimentalOptions {
138
- /**
139
- * A function to update `compilerOptions` before compilation
140
- *
141
- * `data.filename` - The file to be compiled
142
- * `data.code` - The preprocessed Svelte code
143
- * `data.compileOptions` - The current compiler options
144
- *
145
- * To change part of the compiler options, return an object with the changes you need.
146
- *
147
- * @example
148
- * ```
149
- * ({ filename, compileOptions }) => {
150
- * // Dynamically set hydration per Svelte file
151
- * if (compileWithHydratable(filename) && !compileOptions.hydratable) {
152
- * return { hydratable: true };
153
- * }
154
- * }
155
- * ```
156
- */
157
- dynamicCompileOptions?: (data: {
158
- filename: string;
159
- code: string;
160
- compileOptions: Partial<CompileOptions>;
161
- }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
162
166
  /**
163
167
  * send a websocket message with svelte compiler warnings during dev
164
168
  *
@@ -172,44 +176,11 @@ interface ExperimentalOptions {
172
176
  disableSvelteResolveWarnings?: boolean;
173
177
  }
174
178
 
175
- type ModuleFormat = NonNullable<'esm'>;
176
- type CssHashGetter = NonNullable<CompileOptions['cssHash']>;
177
179
  type Arrayable<T> = T | T[];
178
180
 
179
- interface VitePreprocessOptions {
181
+ export interface VitePreprocessOptions {
180
182
  script?: boolean;
181
183
  style?: boolean | InlineConfig | ResolvedConfig;
182
184
  }
183
185
 
184
- declare function vitePreprocess(opts?: VitePreprocessOptions): PreprocessorGroup;
185
-
186
- declare function loadSvelteConfig(
187
- viteConfig?: UserConfig,
188
- inlineOptions?: Partial<Options>
189
- ): Promise<Partial<SvelteOptions> | undefined>;
190
-
191
- declare function svelte(inlineOptions?: Partial<Options>): Plugin[];
192
-
193
- export {
194
- Arrayable,
195
- CssHashGetter,
196
- ModuleFormat,
197
- Options,
198
- PluginOptions,
199
- SvelteOptions,
200
- loadSvelteConfig,
201
- svelte,
202
- VitePreprocessOptions,
203
- vitePreprocess
204
- };
205
-
206
- // reexported types
207
-
208
- export { CompileOptions, Warning } from 'svelte/types/compiler/interfaces';
209
-
210
- export {
211
- MarkupPreprocessor,
212
- Preprocessor,
213
- PreprocessorGroup,
214
- Processed
215
- } from 'svelte/types/compiler/preprocess';
186
+ export * from './index.js';
@@ -1,4 +1,4 @@
1
- import type { Processed } from 'svelte/types/compiler/preprocess';
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
4
 
@@ -14,34 +14,11 @@ export interface Code {
14
14
  dependencies?: any[];
15
15
  }
16
16
 
17
- export interface Compiled {
18
- js: Code;
19
- css: Code;
20
- ast: any; // TODO type
21
- warnings: any[]; // TODO type
22
- vars: Array<{
23
- name: string;
24
- export_name: string;
25
- injected: boolean;
26
- module: boolean;
27
- mutated: boolean;
28
- reassigned: boolean;
29
- referenced: boolean;
30
- writable: boolean;
31
- referenced_from_script: boolean;
32
- }>;
33
- stats: {
34
- timings: {
35
- total: number;
36
- };
37
- };
38
- }
39
-
40
17
  export interface CompileData {
41
18
  filename: string;
42
19
  normalizedFilename: string;
43
20
  lang: string;
44
- compiled: Compiled;
21
+ compiled: CompileResult;
45
22
  ssr: boolean | undefined;
46
23
  dependencies: string[];
47
24
  preprocessed: Processed;
@@ -1,4 +1,4 @@
1
- import type { Warning } from '../index.d.ts';
1
+ import type { Warning } from 'svelte/types/compiler/interfaces';
2
2
 
3
3
  export interface LogFn extends SimpleLogFn {
4
4
  (message: string, payload?: any, namespace?: string): void;
@@ -1,7 +1,7 @@
1
1
  import type { CompileOptions } from 'svelte/types/compiler/interfaces';
2
2
  import type { ViteDevServer } from 'vite';
3
3
  import { VitePluginSvelteStats } from '../utils/vite-plugin-svelte-stats.js';
4
- import type { Options } from '../index.d.ts';
4
+ import type { Options } from '../public.d.ts';
5
5
 
6
6
  export interface PreResolvedOptions extends Options {
7
7
  // these options are non-nullable after resolve
@@ -4,8 +4,12 @@ import { createMakeHot } from 'svelte-hmr';
4
4
  import { safeBase64Hash } from './hash.js';
5
5
  import { log } from './log.js';
6
6
 
7
- import { createInjectScopeEverythingRulePreprocessorGroup } from './preprocess.js';
7
+ import {
8
+ checkPreprocessDependencies,
9
+ createInjectScopeEverythingRulePreprocessorGroup
10
+ } from './preprocess.js';
8
11
  import { mapToRelative } from './sourcemaps.js';
12
+ import { enhanceCompileError } from './error.js';
9
13
 
10
14
  const scriptLangRE = /<script [^>]*lang=["']?([^"' >]+)["']?[^>]*>/;
11
15
 
@@ -21,7 +25,10 @@ export const _createCompileSvelte = (makeHot) => {
21
25
  return async function compileSvelte(svelteRequest, code, options) {
22
26
  const { filename, normalizedFilename, cssId, ssr, raw } = svelteRequest;
23
27
  const { emitCss = true } = options;
28
+ /** @type {string[]} */
24
29
  const dependencies = [];
30
+ /** @type {import('svelte/types/compiler/interfaces').Warning[]} */
31
+ const warnings = [];
25
32
 
26
33
  if (options.stats) {
27
34
  if (options.isBuild) {
@@ -47,7 +54,7 @@ export const _createCompileSvelte = (makeHot) => {
47
54
  // also they for hmr updates too
48
55
  }
49
56
  }
50
- /** @type {import('../index.d.ts').CompileOptions} */
57
+ /** @type {import('svelte/compiler').CompileOptions} */
51
58
  const compileOptions = {
52
59
  ...options.compilerOptions,
53
60
  filename,
@@ -86,7 +93,16 @@ export const _createCompileSvelte = (makeHot) => {
86
93
  throw e;
87
94
  }
88
95
 
89
- if (preprocessed.dependencies) dependencies.push(...preprocessed.dependencies);
96
+ if (preprocessed.dependencies?.length) {
97
+ const checked = checkPreprocessDependencies(filename, preprocessed.dependencies);
98
+ if (checked.warnings.length) {
99
+ warnings.push(...checked.warnings);
100
+ }
101
+ if (checked.dependencies.length) {
102
+ dependencies.push(...checked.dependencies);
103
+ }
104
+ }
105
+
90
106
  if (preprocessed.map) compileOptions.sourcemap = preprocessed.map;
91
107
  }
92
108
  if (typeof preprocessed?.map === 'object') {
@@ -99,7 +115,7 @@ export const _createCompileSvelte = (makeHot) => {
99
115
  };
100
116
  }
101
117
  const finalCode = preprocessed ? preprocessed.code : code;
102
- const dynamicCompileOptions = await options.experimental?.dynamicCompileOptions?.({
118
+ const dynamicCompileOptions = await options?.dynamicCompileOptions?.({
103
119
  filename,
104
120
  code: finalCode,
105
121
  compileOptions
@@ -119,13 +135,26 @@ export const _createCompileSvelte = (makeHot) => {
119
135
  : compileOptions;
120
136
 
121
137
  const endStat = stats?.start(filename);
122
- const compiled = compile(finalCode, finalCompileOptions);
138
+ /** @type {import('svelte/types/compiler/interfaces').CompileResult} */
139
+ let compiled;
140
+ try {
141
+ compiled = compile(finalCode, finalCompileOptions);
142
+ } catch (e) {
143
+ enhanceCompileError(e, code, preprocessors);
144
+ throw e;
145
+ }
123
146
 
124
147
  if (endStat) {
125
148
  endStat();
126
149
  }
127
150
  mapToRelative(compiled.js?.map, filename);
128
151
  mapToRelative(compiled.css?.map, filename);
152
+ if (warnings.length) {
153
+ if (!compiled.warnings) {
154
+ compiled.warnings = [];
155
+ }
156
+ compiled.warnings.push(...warnings);
157
+ }
129
158
  if (!raw) {
130
159
  // wire css import and code for hmr
131
160
  const hasCss = compiled.css?.code?.trim().length > 0;
@@ -100,3 +100,79 @@ function formatFrameForVite(frame) {
100
100
  .map((line) => (line.match(/^\s+\^/) ? ' ' + line : ' ' + line.replace(':', ' | ')))
101
101
  .join('\n');
102
102
  }
103
+
104
+ /**
105
+ * @param {import('svelte/types/compiler/interfaces').Warning & Error} err a svelte compiler error, which is a mix of Warning and an error
106
+ * @param {string} originalCode
107
+ * @param {import('../public.d.ts').Options['preprocess']} [preprocessors]
108
+ */
109
+ export function enhanceCompileError(err, originalCode, preprocessors) {
110
+ preprocessors = arraify(preprocessors ?? []);
111
+
112
+ /** @type {string[]} */
113
+ const additionalMessages = [];
114
+
115
+ // Handle incorrect TypeScript usage
116
+ if (err.code === 'parse-error') {
117
+ // Reference from Svelte: https://github.com/sveltejs/svelte/blob/800f6c076be5dd87dd4d2e9d66c59b973d54d84b/packages/svelte/src/compiler/preprocess/index.js#L262
118
+ const scriptRe = /<script(\s[^]*?)?(?:>([^]*?)<\/script>|\/>)/gi;
119
+ const errIndex = err.pos ?? -1;
120
+
121
+ let m;
122
+ while ((m = scriptRe.exec(originalCode))) {
123
+ const matchStart = m.index;
124
+ const matchEnd = matchStart + m[0].length;
125
+ const isErrorInScript = matchStart <= errIndex && errIndex <= matchEnd;
126
+ if (isErrorInScript) {
127
+ // Warn missing lang="ts"
128
+ const hasLangTs = m[1]?.includes('lang="ts"');
129
+ if (!hasLangTs) {
130
+ additionalMessages.push('Did you forget to add lang="ts" to your script tag?');
131
+ }
132
+ // Warn missing script preprocessor
133
+ if (preprocessors.every((p) => p.script == null)) {
134
+ const preprocessorType = hasLangTs ? 'TypeScript' : 'script';
135
+ additionalMessages.push(
136
+ `Did you forget to add a ${preprocessorType} preprocessor? See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/preprocess.md for more information.`
137
+ );
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ // Handle incorrect CSS preprocessor usage
144
+ if (err.code === 'css-syntax-error') {
145
+ const styleRe = /<style(\s[^]*?)?(?:>([^]*?)<\/style>|\/>)/gi;
146
+
147
+ let m;
148
+ while ((m = styleRe.exec(originalCode))) {
149
+ // Warn missing lang attribute
150
+ if (!m[1]?.includes('lang=')) {
151
+ additionalMessages.push('Did you forget to add a lang attribute to your style tag?');
152
+ }
153
+ // Warn missing style preprocessor
154
+ if (
155
+ preprocessors.every((p) => p.style == null || p.name === 'inject-scope-everything-rule')
156
+ ) {
157
+ const preprocessorType = m[1]?.match(/lang="(.+?)"/)?.[1] ?? 'style';
158
+ additionalMessages.push(
159
+ `Did you forget to add a ${preprocessorType} preprocessor? See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/preprocess.md for more information.`
160
+ );
161
+ }
162
+ }
163
+ }
164
+
165
+ if (additionalMessages.length) {
166
+ err.message += '\n\n- ' + additionalMessages.join('\n- ');
167
+ }
168
+
169
+ return err;
170
+ }
171
+
172
+ /**
173
+ * @param {T | T[]} value
174
+ * @template T
175
+ */
176
+ function arraify(value) {
177
+ return Array.isArray(value) ? value : [value];
178
+ }
@@ -59,7 +59,7 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
59
59
  // TODO ideally we'd be able to externalize prebundled styles too, but for now always put them in the js
60
60
  css = 'injected';
61
61
  }
62
- /** @type {import('../index.d.ts').CompileOptions} */
62
+ /** @type {import('svelte/compiler').CompileOptions} */
63
63
  const compileOptions = {
64
64
  ...options.compilerOptions,
65
65
  css,
@@ -81,14 +81,18 @@ async function compileSvelte(options, { filename, code }, statsCollection) {
81
81
 
82
82
  const finalCode = preprocessed ? preprocessed.code : code;
83
83
 
84
- const dynamicCompileOptions = await options.experimental?.dynamicCompileOptions?.({
84
+ const dynamicCompileOptions = await options?.dynamicCompileOptions?.({
85
85
  filename,
86
86
  code: finalCode,
87
87
  compileOptions
88
88
  });
89
89
 
90
90
  if (dynamicCompileOptions && log.debug.enabled) {
91
- log.debug(`dynamic compile options for ${filename}: ${JSON.stringify(dynamicCompileOptions)}`);
91
+ log.debug(
92
+ `dynamic compile options for ${filename}: ${JSON.stringify(dynamicCompileOptions)}`,
93
+ undefined,
94
+ 'compile'
95
+ );
92
96
  }
93
97
 
94
98
  const finalCompileOptions = dynamicCompileOptions
package/src/utils/id.js CHANGED
@@ -159,8 +159,8 @@ function stripRoot(normalizedFilename, normalizedRoot) {
159
159
  }
160
160
 
161
161
  /**
162
- * @param {import('../index.d.ts').Arrayable<string> | undefined} include
163
- * @param {import('../index.d.ts').Arrayable<string> | undefined} exclude
162
+ * @param {import('../public.d.ts').Options['include'] | undefined} include
163
+ * @param {import('../public.d.ts').Options['exclude'] | undefined} exclude
164
164
  * @param {string[]} extensions
165
165
  * @returns {(filename: string) => boolean}
166
166
  */
@@ -16,16 +16,19 @@ export const knownSvelteConfigNames = [
16
16
  'svelte.config.mjs'
17
17
  ];
18
18
 
19
- // hide dynamic import from ts transform to prevent it turning into a require
20
- // see https://github.com/microsoft/TypeScript/issues/43329#issuecomment-811606238
21
- // also use timestamp query to avoid caching on reload
22
- const dynamicImportDefault = new Function(
23
- 'path',
24
- 'timestamp',
25
- 'return import(path + "?t=" + timestamp).then(m => m.default)'
26
- );
19
+ /**
20
+ * @param {string} filePath
21
+ * @param {number} timestamp
22
+ */
23
+ async function dynamicImportDefault(filePath, timestamp) {
24
+ return await import(filePath + '?t=' + timestamp).then((m) => m.default);
25
+ }
27
26
 
28
- /** @type {import('../index.d.ts').loadSvelteConfig} */
27
+ /**
28
+ * @param {import('vite').UserConfig} viteConfig
29
+ * @param {Partial<import('../public.d.ts').Options>} inlineOptions
30
+ * @returns {Promise<Partial<import('../public.d.ts').SvelteConfig> | undefined>}
31
+ */
29
32
  export async function loadSvelteConfig(viteConfig, inlineOptions) {
30
33
  if (inlineOptions?.configFile === false) {
31
34
  return;
@@ -59,7 +62,8 @@ export async function loadSvelteConfig(viteConfig, inlineOptions) {
59
62
  // identify which require function to use (esm and cjs mode)
60
63
  const _require = import.meta.url
61
64
  ? esmRequire ?? (esmRequire = createRequire(import.meta.url))
62
- : require;
65
+ : // eslint-disable-next-line no-undef
66
+ require;
63
67
 
64
68
  // avoid loading cached version on reload
65
69
  delete _require.cache[_require.resolve(configFile)];
@@ -86,7 +90,7 @@ export async function loadSvelteConfig(viteConfig, inlineOptions) {
86
90
 
87
91
  /**
88
92
  * @param {import('vite').UserConfig | undefined} viteConfig
89
- * @param {Partial<import('../index.d.ts').Options> | undefined} inlineOptions
93
+ * @param {Partial<import('../public.d.ts').Options> | undefined} inlineOptions
90
94
  * @returns {string | undefined}
91
95
  */
92
96
  function findConfigToLoad(viteConfig, inlineOptions) {
@@ -36,6 +36,7 @@ const allowedPluginOptions = new Set([
36
36
  'disableDependencyReinclusion',
37
37
  'prebundleSvelteLibraries',
38
38
  'inspector',
39
+ 'dynamicCompileOptions',
39
40
  'experimental'
40
41
  ]);
41
42
 
@@ -44,7 +45,7 @@ const knownRootOptions = new Set(['extensions', 'compilerOptions', 'preprocess',
44
45
  const allowedInlineOptions = new Set(['configFile', ...allowedPluginOptions, ...knownRootOptions]);
45
46
 
46
47
  /**
47
- * @param {Partial<import('../index.d.ts').Options>} [inlineOptions]
48
+ * @param {Partial<import('../public.d.ts').Options>} [inlineOptions]
48
49
  */
49
50
  export function validateInlineOptions(inlineOptions) {
50
51
  const invalidKeys = Object.keys(inlineOptions || {}).filter(
@@ -56,8 +57,8 @@ export function validateInlineOptions(inlineOptions) {
56
57
  }
57
58
 
58
59
  /**
59
- * @param {Partial<import('../index.d.ts').SvelteOptions>} [config]
60
- * @returns {Partial<import('../index.d.ts').Options> | undefined}
60
+ * @param {Partial<import('../public.d.ts').SvelteConfig>} [config]
61
+ * @returns {Partial<import('../public.d.ts').Options> | undefined}
61
62
  */
62
63
  function convertPluginOptions(config) {
63
64
  if (!config) {
@@ -107,7 +108,7 @@ function convertPluginOptions(config) {
107
108
  delete pluginOptions[unkownOption];
108
109
  });
109
110
  }
110
- /** @type {import('../index.d.ts').Options} */
111
+ /** @type {import('../public.d.ts').Options} */
111
112
  const result = {
112
113
  ...config,
113
114
  ...pluginOptions
@@ -120,7 +121,7 @@ function convertPluginOptions(config) {
120
121
 
121
122
  /**
122
123
  * used in config phase, merges the default options, svelte config, and inline options
123
- * @param {Partial<import('../index.d.ts').Options> | undefined} inlineOptions
124
+ * @param {Partial<import('../public.d.ts').Options> | undefined} inlineOptions
124
125
  * @param {import('vite').UserConfig} viteUserConfig
125
126
  * @param {import('vite').ConfigEnv} viteEnv
126
127
  * @returns {Promise<import('../types/options.d.ts').PreResolvedOptions>}
@@ -190,7 +191,7 @@ function mergeConfigs(...configs) {
190
191
  */
191
192
  export function resolveOptions(preResolveOptions, viteConfig, cache) {
192
193
  const css = preResolveOptions.emitCss ? 'external' : 'injected';
193
- /** @type {Partial<import('../index.d.ts').Options>} */
194
+ /** @type {Partial<import('../public.d.ts').Options>} */
194
195
  const defaultOptions = {
195
196
  hot: viteConfig.isProduction
196
197
  ? false
@@ -316,13 +317,13 @@ function removeIgnoredOptions(options) {
316
317
  function handleDeprecatedOptions(options) {
317
318
  const experimental = /** @type {Record<string, any>} */ (options.experimental);
318
319
  if (experimental) {
319
- for (const promoted of ['prebundleSvelteLibraries', 'inspector']) {
320
+ for (const promoted of ['prebundleSvelteLibraries', 'inspector', 'dynamicCompileOptions']) {
320
321
  if (experimental[promoted]) {
321
322
  //@ts-expect-error untyped assign
322
323
  options[promoted] = experimental[promoted];
323
324
  delete experimental[promoted];
324
325
  log.warn(
325
- `Option "vitePlugin.experimental.${promoted}" is no longer experimental and has moved to "vitePlugin.${promoted}". Please update your svelte config.`
326
+ `Option "experimental.${promoted}" is no longer experimental and has moved to "${promoted}". Please update your Svelte or Vite config.`
326
327
  );
327
328
  }
328
329
  }
@@ -1,6 +1,7 @@
1
1
  import MagicString from 'magic-string';
2
2
  import { log } from './log.js';
3
3
  import path from 'node:path';
4
+ import { normalizePath } from 'vite';
4
5
 
5
6
  /**
6
7
  * this appends a *{} rule to component styles to force the svelte compiler to add style classes to all nodes
@@ -8,10 +9,11 @@ import path from 'node:path';
8
9
  *
9
10
  * only used during dev with enabled css hmr
10
11
  *
11
- * @returns {import('svelte/types/compiler/preprocess').PreprocessorGroup}
12
+ * @returns {import('svelte/compiler').PreprocessorGroup}
12
13
  */
13
14
  export function createInjectScopeEverythingRulePreprocessorGroup() {
14
15
  return {
16
+ name: 'inject-scope-everything-rule',
15
17
  style({ content, filename }) {
16
18
  const s = new MagicString(content);
17
19
  s.append(' *{}');
@@ -30,14 +32,14 @@ export function createInjectScopeEverythingRulePreprocessorGroup() {
30
32
  * @param {import('../types/options.d.ts').ResolvedOptions} options
31
33
  * @param {import('vite').ResolvedConfig} config
32
34
  * @returns {{
33
- * prependPreprocessors: import('svelte/types/compiler/preprocess').PreprocessorGroup[],
34
- * appendPreprocessors: import('svelte/types/compiler/preprocess').PreprocessorGroup[]
35
+ * prependPreprocessors: import('svelte/compiler').PreprocessorGroup[],
36
+ * appendPreprocessors: import('svelte/compiler').PreprocessorGroup[]
35
37
  * }}
36
38
  */
37
39
  function buildExtraPreprocessors(options, config) {
38
- /** @type {import('svelte/types/compiler/preprocess').PreprocessorGroup[]} */
40
+ /** @type {import('svelte/compiler').PreprocessorGroup[]} */
39
41
  const prependPreprocessors = [];
40
- /** @type {import('svelte/types/compiler/preprocess').PreprocessorGroup[]} */
42
+ /** @type {import('svelte/compiler').PreprocessorGroup[]} */
41
43
  const appendPreprocessors = [];
42
44
 
43
45
  // @ts-ignore
@@ -120,3 +122,52 @@ export function addExtraPreprocessors(options, config) {
120
122
  }
121
123
  }
122
124
  }
125
+
126
+ /**
127
+ *
128
+ * @param filename {string}
129
+ * @param dependencies {string[]}
130
+ * @returns {({dependencies: string[], warnings:import('svelte/types/compiler/interfaces').Warning[] })}
131
+ */
132
+ export function checkPreprocessDependencies(filename, dependencies) {
133
+ /** @type {import('svelte/types/compiler/interfaces').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
+ }
@@ -0,0 +1,189 @@
1
+ declare module '@sveltejs/vite-plugin-svelte' {
2
+ import type { InlineConfig, ResolvedConfig } from 'vite';
3
+ import type { CompileOptions, PreprocessorGroup } from 'svelte/compiler';
4
+ import type { Warning } from 'svelte/types/compiler/interfaces';
5
+ import type { Options as InspectorOptions } from '@sveltejs/vite-plugin-svelte-inspector';
6
+ export type Options = Omit<SvelteConfig, 'vitePlugin'> & PluginOptionsInline;
7
+
8
+ interface PluginOptionsInline extends PluginOptions {
9
+ /**
10
+ * Path to a svelte config file, either absolute or relative to Vite root
11
+ *
12
+ * set to `false` to ignore the svelte config file
13
+ *
14
+ * @see https://vitejs.dev/config/#root
15
+ */
16
+ configFile?: string | false;
17
+ }
18
+
19
+ interface PluginOptions {
20
+ /**
21
+ * A `picomatch` pattern, or array of patterns, which specifies the files the plugin should
22
+ * operate on. By default, all svelte files are included.
23
+ *
24
+ * @see https://github.com/micromatch/picomatch
25
+ */
26
+ include?: Arrayable<string>;
27
+ /**
28
+ * A `picomatch` pattern, or array of patterns, which specifies the files to be ignored by the
29
+ * plugin. By default, no files are ignored.
30
+ *
31
+ * @see https://github.com/micromatch/picomatch
32
+ */
33
+ exclude?: Arrayable<string>;
34
+ /**
35
+ * Emit Svelte styles as virtual CSS files for Vite and other plugins to process
36
+ *
37
+ * @default true
38
+ */
39
+ emitCss?: boolean;
40
+ /**
41
+ * Enable or disable Hot Module Replacement.
42
+ *
43
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
44
+ *
45
+ * DO NOT CUSTOMIZE SVELTE-HMR OPTIONS UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING
46
+ *
47
+ * YOU HAVE BEEN WARNED
48
+ *
49
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
50
+ *
51
+ * Set an object to pass custom options to svelte-hmr
52
+ *
53
+ * @see https://github.com/rixo/svelte-hmr#options
54
+ * @default true for development, always false for production
55
+ */
56
+ hot?:
57
+ | boolean
58
+ | {
59
+ injectCss?: boolean;
60
+ partialAccept?: boolean;
61
+ [key: string]: any;
62
+ };
63
+ /**
64
+ * Some Vite plugins can contribute additional preprocessors by defining `api.sveltePreprocess`.
65
+ * If you don't want to use them, set this to true to ignore them all or use an array of strings
66
+ * with plugin names to specify which.
67
+ *
68
+ * @default false
69
+ */
70
+ ignorePluginPreprocessors?: boolean | string[];
71
+ /**
72
+ * vite-plugin-svelte automatically handles excluding svelte libraries and reinclusion of their dependencies
73
+ * in vite.optimizeDeps.
74
+ *
75
+ * `disableDependencyReinclusion: true` disables all reinclusions
76
+ * `disableDependencyReinclusion: ['foo','bar']` disables reinclusions for dependencies of foo and bar
77
+ *
78
+ * This should be used for hybrid packages that contain both node and browser dependencies, eg Routify
79
+ *
80
+ * @default false
81
+ */
82
+ disableDependencyReinclusion?: boolean | string[];
83
+ /**
84
+ * Enable support for Vite's dependency optimization to prebundle Svelte libraries.
85
+ *
86
+ * To disable prebundling for a specific library, add it to `optimizeDeps.exclude`.
87
+ *
88
+ * @default true for dev, false for build
89
+ */
90
+ prebundleSvelteLibraries?: boolean;
91
+ /**
92
+ * toggle/configure Svelte Inspector
93
+ *
94
+ * @default unset for dev, always false for build
95
+ */
96
+ inspector?: InspectorOptions | boolean;
97
+
98
+ /**
99
+ * A function to update `compilerOptions` before compilation
100
+ *
101
+ * `data.filename` - The file to be compiled
102
+ * `data.code` - The preprocessed Svelte code
103
+ * `data.compileOptions` - The current compiler options
104
+ *
105
+ * To change part of the compiler options, return an object with the changes you need.
106
+ *
107
+ * @example
108
+ * ```
109
+ * ({ filename, compileOptions }) => {
110
+ * // Dynamically set hydration per Svelte file
111
+ * if (compileWithHydratable(filename) && !compileOptions.hydratable) {
112
+ * return { hydratable: true };
113
+ * }
114
+ * }
115
+ * ```
116
+ */
117
+ dynamicCompileOptions?: (data: {
118
+ filename: string;
119
+ code: string;
120
+ compileOptions: Partial<CompileOptions>;
121
+ }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
122
+
123
+ /**
124
+ * These options are considered experimental and breaking changes to them can occur in any release
125
+ */
126
+ experimental?: ExperimentalOptions;
127
+ }
128
+
129
+ export interface SvelteConfig {
130
+ /**
131
+ * A list of file extensions to be compiled by Svelte
132
+ *
133
+ * @default ['.svelte']
134
+ */
135
+ extensions?: string[];
136
+ /**
137
+ * An array of preprocessors to transform the Svelte source code before compilation
138
+ *
139
+ * @see https://svelte.dev/docs#svelte_preprocess
140
+ */
141
+ preprocess?: Arrayable<PreprocessorGroup>;
142
+ /**
143
+ * The options to be passed to the Svelte compiler. A few options are set by default,
144
+ * including `dev` and `css`. However, some options are non-configurable, like
145
+ * `filename`, `format`, `generate`, and `cssHash` (in dev).
146
+ *
147
+ * @see https://svelte.dev/docs#svelte_compile
148
+ */
149
+ compilerOptions?: Omit<CompileOptions, 'filename' | 'format' | 'generate'>;
150
+
151
+ /**
152
+ * Handles warning emitted from the Svelte compiler
153
+ */
154
+ onwarn?: (warning: Warning, defaultHandler?: (warning: Warning) => void) => void;
155
+ /**
156
+ * Options for vite-plugin-svelte
157
+ */
158
+ vitePlugin?: PluginOptions;
159
+ }
160
+
161
+ /**
162
+ * These options are considered experimental and breaking changes to them can occur in any release
163
+ */
164
+ interface ExperimentalOptions {
165
+ /**
166
+ * send a websocket message with svelte compiler warnings during dev
167
+ *
168
+ */
169
+ sendWarningsToBrowser?: boolean;
170
+ /**
171
+ * disable svelte field resolve warnings
172
+ *
173
+ * @default false
174
+ */
175
+ disableSvelteResolveWarnings?: boolean;
176
+ }
177
+
178
+ type Arrayable<T> = T | T[];
179
+
180
+ export interface VitePreprocessOptions {
181
+ script?: boolean;
182
+ style?: boolean | InlineConfig | ResolvedConfig;
183
+ }
184
+ export function svelte(inlineOptions?: Partial<Options> | undefined): import('vite').Plugin[];
185
+ export function vitePreprocess(opts: VitePreprocessOptions): import('svelte/compiler').PreprocessorGroup;
186
+ export function loadSvelteConfig(viteConfig: import('vite').UserConfig, inlineOptions: Partial<Options>): Promise<Partial<SvelteConfig> | undefined>;
187
+ }
188
+
189
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,25 @@
1
+ {
2
+ "version": 3,
3
+ "file": "index.d.ts",
4
+ "names": [
5
+ "Options",
6
+ "SvelteConfig",
7
+ "VitePreprocessOptions",
8
+ "svelte",
9
+ "vitePreprocess",
10
+ "loadSvelteConfig"
11
+ ],
12
+ "sources": [
13
+ "../src/public.d.ts",
14
+ "../src/index.js",
15
+ "../src/preprocess.js",
16
+ "../src/utils/load-svelte-config.js"
17
+ ],
18
+ "sourcesContent": [
19
+ null,
20
+ null,
21
+ null,
22
+ null
23
+ ],
24
+ "mappings": ";;;;;aAMYA,OAAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2HFC,YAAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmDZC,qBAAqBA;;;;iBC1JtBC,MAAMA;iBCXNC,cAAcA;iBCgBRC,gBAAgBA"
25
+ }