@rsvelte/vite-plugin-svelte 0.1.0

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.
@@ -0,0 +1,166 @@
1
+ import process from 'node:process';
2
+ import * as vite from 'vite';
3
+ import { mapToRelative, removeLangSuffix } from './utils/sourcemaps.js';
4
+ const {
5
+ isCSSRequest,
6
+ preprocessCSS,
7
+ resolveConfig,
8
+ transformWithEsbuild,
9
+ //@ts-ignore rolldown types don't exist
10
+ rolldownVersion,
11
+ //@ts-ignore rolldown types don't exist
12
+ transformWithOxc
13
+ } = vite;
14
+ /**
15
+ * @typedef {(code: string, filename: string) => Promise<{ code: string; map?: any; deps?: Set<string> }>} CssTransform
16
+ */
17
+
18
+ const supportedScriptLangs = ['ts'];
19
+
20
+ export const lang_sep = '.vite-preprocess';
21
+
22
+ /**
23
+ * @param {import('./public.d.ts').VitePreprocessOptions} [opts]
24
+ * @returns {import('@rsvelte/compiler').PreprocessorGroup}
25
+ */
26
+ export function vitePreprocess(opts) {
27
+ /** @type {import('@rsvelte/compiler').PreprocessorGroup} */
28
+ const preprocessor = { name: 'vite-preprocess' };
29
+ if (opts?.script === true) {
30
+ preprocessor.script = rolldownVersion ? viteScriptOxc().script : viteScript().script;
31
+ }
32
+ if (opts?.style !== false) {
33
+ const styleOpts = typeof opts?.style == 'object' ? opts?.style : undefined;
34
+ preprocessor.style = viteStyle(styleOpts).style;
35
+ }
36
+ return preprocessor;
37
+ }
38
+
39
+ /**
40
+ * @returns {{ script: import('@rsvelte/compiler').Preprocessor }}
41
+ */
42
+ function viteScript() {
43
+ return {
44
+ async script({ attributes, content, filename = '' }) {
45
+ const lang = /** @type {string} */ (attributes.lang);
46
+ if (!supportedScriptLangs.includes(lang)) return;
47
+ const { code, map } = await transformWithEsbuild(content, filename, {
48
+ loader: /** @type {import('vite').ESBuildOptions['loader']} */ (lang),
49
+ target: 'esnext',
50
+ tsconfigRaw: {
51
+ compilerOptions: {
52
+ // svelte typescript needs this flag to work with type imports
53
+ importsNotUsedAsValues: 'preserve',
54
+ preserveValueImports: true
55
+ }
56
+ }
57
+ });
58
+
59
+ mapToRelative(map, filename);
60
+
61
+ return {
62
+ code,
63
+ map
64
+ };
65
+ }
66
+ };
67
+ }
68
+
69
+ /**
70
+ * @returns {{ script: import('@rsvelte/compiler').Preprocessor }}
71
+ */
72
+ function viteScriptOxc() {
73
+ return {
74
+ async script({ attributes, content, filename = '' }) {
75
+ if (typeof attributes.lang !== 'string' || !supportedScriptLangs.includes(attributes.lang)) {
76
+ return;
77
+ }
78
+ const lang = /** @type {'ts'} */ (attributes.lang);
79
+ const { code, map } = await transformWithOxc(content, filename, {
80
+ lang,
81
+ target: 'esnext'
82
+ // TODO, how to pass tsconfig compilerOptions (or not needed as config is loaded for file
83
+ /*tsconfigRaw: {
84
+ compilerOptions: {
85
+ // svelte typescript needs this flag to work with type imports
86
+ importsNotUsedAsValues: 'preserve',
87
+ preserveValueImports: true
88
+ }
89
+ }*/
90
+ });
91
+
92
+ mapToRelative(map, filename);
93
+
94
+ return {
95
+ code,
96
+ map
97
+ };
98
+ }
99
+ };
100
+ }
101
+
102
+ /**
103
+ * @param {import('vite').ResolvedConfig | import('vite').InlineConfig} config
104
+ * @returns {{ style: import('@rsvelte/compiler').Preprocessor }}
105
+ */
106
+ function viteStyle(config = {}) {
107
+ /** @type {Promise<CssTransform> | CssTransform} */
108
+ let cssTransform;
109
+ /** @type {import('@rsvelte/compiler').Preprocessor} */
110
+ const style = async ({ attributes, content, filename = '' }) => {
111
+ const ext = attributes.lang ? `.${attributes.lang}` : '.css';
112
+ if (attributes.lang && !isCSSRequest(ext)) return;
113
+ if (!cssTransform) {
114
+ cssTransform = createCssTransform(style, config).then((t) => (cssTransform = t));
115
+ }
116
+ const transform = await cssTransform;
117
+ const suffix = `${lang_sep}${ext}`;
118
+ const moduleId = `${filename}${suffix}`;
119
+ const { code, map, deps } = await transform(content, moduleId);
120
+ removeLangSuffix(map, suffix);
121
+ mapToRelative(map, filename);
122
+ const dependencies = deps ? Array.from(deps).filter((d) => !d.endsWith(suffix)) : undefined;
123
+ return {
124
+ code,
125
+ map: map ?? undefined,
126
+ dependencies
127
+ };
128
+ };
129
+ // @ts-expect-error tag so can be found by v-p-s
130
+ style.__resolvedConfig = null;
131
+ return { style };
132
+ }
133
+
134
+ /**
135
+ * @param {import('@rsvelte/compiler').Preprocessor} style
136
+ * @param {import('vite').ResolvedConfig | import('vite').InlineConfig} config
137
+ * @returns {Promise<CssTransform>}
138
+ */
139
+ async function createCssTransform(style, config) {
140
+ /** @type {import('vite').ResolvedConfig} */
141
+ let resolvedConfig;
142
+ // @ts-expect-error special prop added if running in v-p-s
143
+ if (style.__resolvedConfig) {
144
+ // @ts-expect-error not typed
145
+ resolvedConfig = style.__resolvedConfig;
146
+ } else if (isResolvedConfig(config)) {
147
+ resolvedConfig = config;
148
+ } else {
149
+ // default to "build" if no NODE_ENV is set to avoid running in dev mode for svelte-check etc.
150
+ const useBuild = !process.env.NODE_ENV || process.env.NODE_ENV === 'production';
151
+ const command = useBuild ? 'build' : 'serve';
152
+ const defaultMode = useBuild ? 'production' : 'development';
153
+ resolvedConfig = await resolveConfig(config, command, defaultMode, defaultMode, false);
154
+ }
155
+ return async (code, filename) => {
156
+ return preprocessCSS(code, filename, resolvedConfig);
157
+ };
158
+ }
159
+
160
+ /**
161
+ * @param {any} config
162
+ * @returns {config is import('vite').ResolvedConfig}
163
+ */
164
+ function isResolvedConfig(config) {
165
+ return !!config.inlineConfig;
166
+ }
@@ -0,0 +1,217 @@
1
+ import type { InlineConfig, ResolvedConfig } from 'vite';
2
+ import type { CompileOptions, Warning, PreprocessorGroup } from '@rsvelte/compiler';
3
+ import type { Options as InspectorOptions } from '@sveltejs/vite-plugin-svelte-inspector';
4
+
5
+ export type Options = Omit<SvelteConfig, 'vitePlugin'> & PluginOptionsInline;
6
+
7
+ interface PluginOptionsInline extends PluginOptions {
8
+ /**
9
+ * Path to a svelte config file, either absolute or relative to Vite root
10
+ *
11
+ * set to `false` to ignore the svelte config file
12
+ *
13
+ * @see https://vitejs.dev/config/#root
14
+ */
15
+ configFile?: string | false;
16
+ }
17
+
18
+ export interface PluginOptions {
19
+ /**
20
+ * A `picomatch` pattern, or array of patterns, which specifies the files the plugin should
21
+ * operate on. By default, all svelte files are included.
22
+ *
23
+ * @see https://github.com/micromatch/picomatch
24
+ */
25
+ include?: Arrayable<string | RegExp>;
26
+ /**
27
+ * A `picomatch` pattern, or array of patterns, which specifies the files to be ignored by the
28
+ * plugin. By default, no files are ignored.
29
+ *
30
+ * @see https://github.com/micromatch/picomatch
31
+ */
32
+ exclude?: Arrayable<string | RegExp>;
33
+ /**
34
+ * Emit Svelte styles as virtual CSS files for Vite and other plugins to process
35
+ *
36
+ * @default true
37
+ */
38
+ emitCss?: boolean;
39
+ /**
40
+ * Enable or disable Hot Module Replacement.
41
+ * Deprecated, use compilerOptions.hmr instead!
42
+ *
43
+ * @deprecated
44
+ * @default true for development, always false for production
45
+ */
46
+ hot?: boolean;
47
+
48
+ /**
49
+ * Some Vite plugins can contribute additional preprocessors by defining `api.sveltePreprocess`.
50
+ * If you don't want to use them, set this to true to ignore them all or use an array of strings
51
+ * with plugin names to specify which.
52
+ *
53
+ * @default false
54
+ */
55
+ ignorePluginPreprocessors?: boolean | string[];
56
+ /**
57
+ * vite-plugin-svelte automatically handles excluding svelte libraries and reinclusion of their dependencies
58
+ * in vite.optimizeDeps.
59
+ *
60
+ * `disableDependencyReinclusion: true` disables all reinclusions
61
+ * `disableDependencyReinclusion: ['foo','bar']` disables reinclusions for dependencies of foo and bar
62
+ *
63
+ * This should be used for hybrid packages that contain both node and browser dependencies, eg Routify
64
+ *
65
+ * @default false
66
+ */
67
+ disableDependencyReinclusion?: boolean | string[];
68
+ /**
69
+ * Enable support for Vite's dependency optimization to prebundle Svelte libraries.
70
+ *
71
+ * To disable prebundling for a specific library, add it to `optimizeDeps.exclude`.
72
+ *
73
+ * @default true for dev, false for build
74
+ */
75
+ prebundleSvelteLibraries?: boolean;
76
+ /**
77
+ * toggle/configure Svelte Inspector
78
+ *
79
+ * @default unset for dev, always false for build
80
+ */
81
+ inspector?: InspectorOptions | boolean;
82
+
83
+ /**
84
+ * A function to update `compilerOptions` before compilation
85
+ *
86
+ * `data.filename` - The file to be compiled
87
+ * `data.code` - The preprocessed Svelte code
88
+ * `data.compileOptions` - The current compiler options
89
+ *
90
+ * To change part of the compiler options, return an object with the changes you need.
91
+ *
92
+ * @example
93
+ * ```
94
+ * ({ filename, compileOptions }) => {
95
+ * // Dynamically set runes mode per Svelte file
96
+ * if (forceRunesMode(filename) && !compileOptions.runes) {
97
+ * return { runes: true };
98
+ * }
99
+ * }
100
+ * ```
101
+ */
102
+ dynamicCompileOptions?: (data: {
103
+ filename: string;
104
+ code: string;
105
+ compileOptions: Partial<CompileOptions>;
106
+ }) => Promise<Partial<CompileOptions> | void> | Partial<CompileOptions> | void;
107
+
108
+ /**
109
+ * These options are considered experimental and breaking changes to them can occur in any release
110
+ */
111
+ experimental?: ExperimentalOptions;
112
+ }
113
+
114
+ export interface SvelteConfig {
115
+ /**
116
+ * A list of file extensions to be compiled by Svelte
117
+ *
118
+ * @default ['.svelte']
119
+ */
120
+ extensions?: string[];
121
+ /**
122
+ * An array of preprocessors to transform the Svelte source code before compilation
123
+ *
124
+ * @see https://svelte.dev/docs/svelte/svelte-compiler#PreprocessorGroup
125
+ */
126
+ preprocess?: Arrayable<PreprocessorGroup>;
127
+ /**
128
+ * The options to be passed to the Svelte compiler. A few options are set by default,
129
+ * including `dev` and `css`. However, some options are non-configurable, like
130
+ * `filename`, `format`, `generate`, and `cssHash` (in dev).
131
+ *
132
+ * @see https://svelte.dev/docs/svelte/svelte-compiler#CompileOptions
133
+ */
134
+ compilerOptions?: Omit<CompileOptions, 'filename' | 'format' | 'generate'>;
135
+
136
+ /**
137
+ * Handles warning emitted from the Svelte compiler
138
+ *
139
+ * warnings emitted for files in node_modules are logged at the debug level, to see them run
140
+ * `DEBUG=vite-plugin-svelte:node-modules-onwarn pnpm build`
141
+ *
142
+ * @example
143
+ * ```
144
+ * (warning, defaultHandler) => {
145
+ * // ignore some warnings
146
+ * if (!['foo','bar'].includes(warning.code)) {
147
+ * defaultHandler(warning);
148
+ * }
149
+ * }
150
+ * ```
151
+ *
152
+ */
153
+ onwarn?: (warning: Warning, defaultHandler: (warning: Warning) => void) => void;
154
+ /**
155
+ * Options for vite-plugin-svelte
156
+ */
157
+ vitePlugin?: PluginOptions;
158
+ }
159
+
160
+ /**
161
+ * These options are considered experimental and breaking changes to them can occur in any release
162
+ */
163
+ interface ExperimentalOptions {
164
+ /**
165
+ * send a websocket message with svelte compiler warnings during dev
166
+ *
167
+ */
168
+ sendWarningsToBrowser?: boolean;
169
+ /**
170
+ * disable svelte field resolve warnings
171
+ *
172
+ * @default false
173
+ */
174
+ disableSvelteResolveWarnings?: boolean;
175
+
176
+ /**
177
+ * disable api.sveltePreprocess deprecation warnings
178
+ *
179
+ * @default false
180
+ */
181
+ disableApiSveltePreprocessWarnings?: boolean;
182
+
183
+ compileModule?: CompileModuleOptions;
184
+ }
185
+
186
+ interface CompileModuleOptions {
187
+ /**
188
+ * infix that must be present in filename
189
+ * @default ['.svelte.']
190
+ */
191
+ infixes?: string[];
192
+ /**
193
+ * module extensions
194
+ * @default ['.ts','.js']
195
+ */
196
+ extensions?: string[];
197
+ include?: Arrayable<string | RegExp>;
198
+ exclude?: Arrayable<string | RegExp>;
199
+ }
200
+
201
+ type Arrayable<T> = T | T[];
202
+
203
+ export interface VitePreprocessOptions {
204
+ /**
205
+ * preprocess script block with vite pipeline.
206
+ * Since svelte5 this is not needed for typescript anymore
207
+ *
208
+ * @default false
209
+ */
210
+ script?: boolean;
211
+ /**
212
+ * preprocess style blocks with vite pipeline
213
+ */
214
+ style?: boolean | InlineConfig | ResolvedConfig;
215
+ }
216
+ // eslint-disable-next-line n/no-missing-import
217
+ export * from './index.js';
@@ -0,0 +1,37 @@
1
+ import type { Processed, CompileResult } from '@rsvelte/compiler';
2
+ import type { SvelteRequest } from './id.d.ts';
3
+ import type { ResolvedOptions } from './options.d.ts';
4
+ import type { CustomPluginOptionsVite, Rollup } from 'vite';
5
+
6
+ export type CompileSvelte = (
7
+ svelteRequest: SvelteRequest,
8
+ code: string,
9
+ options: Partial<ResolvedOptions>,
10
+ sourcemap?: Rollup.SourceMap
11
+ ) => Promise<CompileData>;
12
+
13
+ export type PreprocessSvelte = (
14
+ svelteRequest: SvelteRequest,
15
+ code: string,
16
+ options: Partial<ResolvedOptions>
17
+ ) => Promise<Processed | undefined>;
18
+
19
+ export interface Code {
20
+ code: string;
21
+ map?: any;
22
+ dependencies?: any[];
23
+ hasGlobal?: boolean;
24
+ moduleType?: string; //vite-8 beta
25
+ meta?: {
26
+ vite?: CustomPluginOptionsVite;
27
+ };
28
+ }
29
+
30
+ export interface CompileData {
31
+ filename: string;
32
+ normalizedFilename: string;
33
+ cssId: string;
34
+ lang: string;
35
+ compiled: CompileResult;
36
+ ssr: boolean | undefined;
37
+ }
@@ -0,0 +1,46 @@
1
+ export type SvelteQueryTypes = 'style';
2
+
3
+ export interface RequestQuery {
4
+ // our own
5
+ svelte?: boolean;
6
+ type?: SvelteQueryTypes;
7
+ // vite specific
8
+ url?: boolean;
9
+ raw?: boolean;
10
+ direct?: boolean;
11
+ inline?: boolean;
12
+ }
13
+
14
+ export interface SvelteRequest {
15
+ id: string;
16
+ cssId: string;
17
+ filename: string;
18
+ normalizedFilename: string;
19
+ query: RequestQuery;
20
+ timestamp: number;
21
+ ssr: boolean;
22
+ raw: boolean;
23
+ }
24
+
25
+ export interface SvelteModuleRequest {
26
+ id: string;
27
+ filename: string;
28
+ normalizedFilename: string;
29
+ query: RequestQuery;
30
+ timestamp: number;
31
+ ssr: boolean;
32
+ }
33
+
34
+ export type IdParser = (id: string, ssr: boolean, timestamp?: number) => SvelteRequest | undefined;
35
+
36
+ export type IdFilter = {
37
+ id: {
38
+ include: Array<string | RegExp>;
39
+ exclude: Array<string | RegExp>;
40
+ };
41
+ };
42
+ export type ModuleIdParser = (
43
+ id: string,
44
+ ssr: boolean,
45
+ timestamp?: number
46
+ ) => SvelteModuleRequest | undefined;
@@ -0,0 +1,24 @@
1
+ import type { Warning } from '@rsvelte/compiler';
2
+
3
+ export interface LogFn extends SimpleLogFn {
4
+ (message: string, payload?: unknown, namespace?: string): void;
5
+
6
+ enabled: boolean;
7
+ once: SimpleLogFn;
8
+ }
9
+
10
+ export interface SimpleLogFn {
11
+ (message: string, payload?: unknown, namespace?: string): void;
12
+ }
13
+
14
+ export type SvelteWarningsMessage = {
15
+ id: string;
16
+ filename: string;
17
+ normalizedFilename: string;
18
+ timestamp: number;
19
+ warnings: Warning[]; // allWarnings filtered by warnings where onwarn did not call the default handler
20
+ allWarnings: Warning[]; // includes warnings filtered by onwarn and our extra vite plugin svelte warnings
21
+ rawWarnings: Warning[]; // raw compiler output
22
+ };
23
+
24
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
@@ -0,0 +1,21 @@
1
+ import type { CompileOptions } from '@rsvelte/compiler';
2
+ import type { ViteDevServer } from 'vite';
3
+ // eslint-disable-next-line n/no-missing-import
4
+ import { VitePluginSvelteStats } from '../utils/vite-plugin-svelte-stats.js';
5
+ import type { Options } from '../public.d.ts';
6
+
7
+ export interface PreResolvedOptions extends Options {
8
+ // these options are non-nullable after resolve
9
+ compilerOptions: CompileOptions;
10
+ // extra options
11
+ root: string;
12
+ isBuild: boolean;
13
+ isServe: boolean;
14
+ isDebug: boolean;
15
+ }
16
+
17
+ export interface ResolvedOptions extends PreResolvedOptions {
18
+ isProduction: boolean;
19
+ server?: ViteDevServer;
20
+ stats?: VitePluginSvelteStats;
21
+ }
@@ -0,0 +1,15 @@
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';
4
+
5
+ export interface PluginAPI {
6
+ options: ResolvedOptions;
7
+ filter: IdFilter;
8
+ idParser: IdParser;
9
+ compileSvelte: CompileSvelte;
10
+ /**
11
+ * @deprecated use 'filter' instead
12
+ * // TODO remove in next major
13
+ */
14
+ idFilter: IdFilter;
15
+ }
@@ -0,0 +1,30 @@
1
+ export interface Stat {
2
+ file: string;
3
+ pkg?: string;
4
+ start: number;
5
+ end: number;
6
+ }
7
+
8
+ export interface StatCollection {
9
+ name: string;
10
+ options: CollectionOptions;
11
+
12
+ start: (file: string) => () => void;
13
+ stats: Stat[];
14
+ packageStats?: PackageStats[];
15
+ collectionStart: number;
16
+ duration?: number;
17
+ finish: () => Promise<void> | void;
18
+ finished: boolean;
19
+ }
20
+
21
+ export interface PackageStats {
22
+ pkg: string;
23
+ files: number;
24
+ duration: number;
25
+ }
26
+
27
+ export interface CollectionOptions {
28
+ logInProgress: (collection: StatCollection, now: number) => boolean;
29
+ logResult: (collection: StatCollection) => boolean;
30
+ }