@sveltejs/vite-plugin-svelte 1.0.0-next.3 → 1.0.0-next.33
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/LICENSE +18 -4
- package/README.md +28 -0
- package/dist/index.cjs +1581 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +1565 -0
- package/dist/index.js.map +1 -0
- package/package.json +75 -32
- package/src/handle-hot-update.ts +111 -0
- package/src/index.ts +225 -0
- package/src/utils/__tests__/dependencies.spec.ts +29 -0
- package/src/utils/__tests__/sourcemap.spec.ts +24 -0
- package/src/utils/compile.ts +148 -0
- package/src/utils/constants.ts +20 -0
- package/src/utils/dependencies.ts +223 -0
- package/src/utils/error.ts +92 -0
- package/src/utils/esbuild.ts +102 -0
- package/src/utils/hash.ts +32 -0
- package/src/utils/id.ts +135 -0
- package/src/utils/load-svelte-config.ts +108 -0
- package/src/utils/log.ts +170 -0
- package/src/utils/options.ts +513 -0
- package/src/utils/preprocess.ts +247 -0
- package/src/utils/resolve.ts +35 -0
- package/src/utils/sourcemap.ts +58 -0
- package/src/utils/vite-plugin-svelte-cache.ts +83 -0
- package/src/utils/watch.ts +106 -0
- package/CHANGELOG.md +0 -19
- package/index.js +0 -570
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
transformWithEsbuild,
|
|
3
|
+
ESBuildOptions,
|
|
4
|
+
ResolvedConfig,
|
|
5
|
+
TransformResult,
|
|
6
|
+
Plugin
|
|
7
|
+
} from 'vite';
|
|
8
|
+
import MagicString from 'magic-string';
|
|
9
|
+
import { preprocess } from 'svelte/compiler';
|
|
10
|
+
import { Preprocessor, PreprocessorGroup, Processed, ResolvedOptions } from './options';
|
|
11
|
+
import { TransformPluginContext } from 'rollup';
|
|
12
|
+
import { log } from './log';
|
|
13
|
+
import { buildSourceMap } from './sourcemap';
|
|
14
|
+
|
|
15
|
+
const supportedStyleLangs = ['css', 'less', 'sass', 'scss', 'styl', 'stylus', 'postcss'];
|
|
16
|
+
|
|
17
|
+
const supportedScriptLangs = ['ts'];
|
|
18
|
+
|
|
19
|
+
function createViteScriptPreprocessor(): Preprocessor {
|
|
20
|
+
return async ({ attributes, content, filename = '' }) => {
|
|
21
|
+
const lang = attributes.lang as string;
|
|
22
|
+
if (!supportedScriptLangs.includes(lang)) return;
|
|
23
|
+
const transformResult = await transformWithEsbuild(content, filename, {
|
|
24
|
+
loader: lang as ESBuildOptions['loader'],
|
|
25
|
+
tsconfigRaw: {
|
|
26
|
+
compilerOptions: {
|
|
27
|
+
// svelte typescript needs this flag to work with type imports
|
|
28
|
+
importsNotUsedAsValues: 'preserve'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
code: transformResult.code,
|
|
34
|
+
map: transformResult.map
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function createViteStylePreprocessor(config: ResolvedConfig): Preprocessor {
|
|
40
|
+
const pluginName = 'vite:css';
|
|
41
|
+
const plugin = config.plugins.find((p) => p.name === pluginName);
|
|
42
|
+
if (!plugin) {
|
|
43
|
+
throw new Error(`failed to find plugin ${pluginName}`);
|
|
44
|
+
}
|
|
45
|
+
if (!plugin.transform) {
|
|
46
|
+
throw new Error(`plugin ${pluginName} has no transform`);
|
|
47
|
+
}
|
|
48
|
+
const pluginTransform = plugin.transform!.bind(null as unknown as TransformPluginContext);
|
|
49
|
+
return async ({ attributes, content, filename = '' }) => {
|
|
50
|
+
const lang = attributes.lang as string;
|
|
51
|
+
if (!supportedStyleLangs.includes(lang)) return;
|
|
52
|
+
const moduleId = `${filename}.${lang}`;
|
|
53
|
+
const transformResult: TransformResult = (await pluginTransform(
|
|
54
|
+
content,
|
|
55
|
+
moduleId
|
|
56
|
+
)) as TransformResult;
|
|
57
|
+
// patch sourcemap source to point back to original filename
|
|
58
|
+
if (transformResult.map?.sources?.[0] === moduleId) {
|
|
59
|
+
transformResult.map.sources[0] = filename;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
code: transformResult.code,
|
|
63
|
+
map: transformResult.map ?? undefined
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function createVitePreprocessorGroup(config: ResolvedConfig): PreprocessorGroup {
|
|
69
|
+
return {
|
|
70
|
+
markup({ content, filename }) {
|
|
71
|
+
return preprocess(
|
|
72
|
+
content,
|
|
73
|
+
{
|
|
74
|
+
script: createViteScriptPreprocessor(),
|
|
75
|
+
style: createViteStylePreprocessor(config)
|
|
76
|
+
},
|
|
77
|
+
{ filename }
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
} as PreprocessorGroup;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* this appends a *{} rule to component styles to force the svelte compiler to add style classes to all nodes
|
|
85
|
+
* That means adding/removing class rules from <style> node won't trigger js updates as the scope classes are not changed
|
|
86
|
+
*
|
|
87
|
+
* only used during dev with enabled css hmr
|
|
88
|
+
*/
|
|
89
|
+
function createInjectScopeEverythingRulePreprocessorGroup(): PreprocessorGroup {
|
|
90
|
+
return {
|
|
91
|
+
style({ content, filename }) {
|
|
92
|
+
const s = new MagicString(content);
|
|
93
|
+
s.append(' *{}');
|
|
94
|
+
return {
|
|
95
|
+
code: s.toString(),
|
|
96
|
+
map: s.generateDecodedMap({ source: filename, hires: true })
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfig) {
|
|
103
|
+
const prependPreprocessors: PreprocessorGroup[] = [];
|
|
104
|
+
const appendPreprocessors: PreprocessorGroup[] = [];
|
|
105
|
+
|
|
106
|
+
if (options.experimental?.useVitePreprocess) {
|
|
107
|
+
log.debug('adding vite preprocessor');
|
|
108
|
+
prependPreprocessors.push(createVitePreprocessorGroup(config));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// @ts-ignore
|
|
112
|
+
const pluginsWithPreprocessorsDeprecated = config.plugins.filter((p) => p?.sveltePreprocess);
|
|
113
|
+
if (pluginsWithPreprocessorsDeprecated.length > 0) {
|
|
114
|
+
log.warn(
|
|
115
|
+
`The following plugins use the deprecated 'plugin.sveltePreprocess' field. Please contact their maintainers and ask them to move it to 'plugin.api.sveltePreprocess': ${pluginsWithPreprocessorsDeprecated
|
|
116
|
+
.map((p) => p.name)
|
|
117
|
+
.join(', ')}`
|
|
118
|
+
);
|
|
119
|
+
// patch plugin to avoid breaking
|
|
120
|
+
pluginsWithPreprocessorsDeprecated.forEach((p) => {
|
|
121
|
+
if (!p.api) {
|
|
122
|
+
p.api = {};
|
|
123
|
+
}
|
|
124
|
+
if (p.api.sveltePreprocess === undefined) {
|
|
125
|
+
// @ts-ignore
|
|
126
|
+
p.api.sveltePreprocess = p.sveltePreprocess;
|
|
127
|
+
} else {
|
|
128
|
+
log.error(
|
|
129
|
+
`ignoring plugin.sveltePreprocess of ${p.name} because it already defined plugin.api.sveltePreprocess.`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const pluginsWithPreprocessors: Plugin[] = config.plugins.filter((p) => p?.api?.sveltePreprocess);
|
|
136
|
+
const ignored: Plugin[] = [],
|
|
137
|
+
included: Plugin[] = [];
|
|
138
|
+
for (const p of pluginsWithPreprocessors) {
|
|
139
|
+
if (
|
|
140
|
+
options.ignorePluginPreprocessors === true ||
|
|
141
|
+
(Array.isArray(options.ignorePluginPreprocessors) &&
|
|
142
|
+
options.ignorePluginPreprocessors?.includes(p.name))
|
|
143
|
+
) {
|
|
144
|
+
ignored.push(p);
|
|
145
|
+
} else {
|
|
146
|
+
included.push(p);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (ignored.length > 0) {
|
|
150
|
+
log.debug(
|
|
151
|
+
`Ignoring svelte preprocessors defined by these vite plugins: ${ignored
|
|
152
|
+
.map((p) => p.name)
|
|
153
|
+
.join(', ')}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
if (included.length > 0) {
|
|
157
|
+
log.debug(
|
|
158
|
+
`Adding svelte preprocessors defined by these vite plugins: ${included
|
|
159
|
+
.map((p) => p.name)
|
|
160
|
+
.join(', ')}`
|
|
161
|
+
);
|
|
162
|
+
appendPreprocessors.push(...pluginsWithPreprocessors.map((p) => p.api.sveltePreprocess));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (options.hot && options.emitCss) {
|
|
166
|
+
appendPreprocessors.push(createInjectScopeEverythingRulePreprocessorGroup());
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { prependPreprocessors, appendPreprocessors };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function addExtraPreprocessors(options: ResolvedOptions, config: ResolvedConfig) {
|
|
173
|
+
const { prependPreprocessors, appendPreprocessors } = buildExtraPreprocessors(options, config);
|
|
174
|
+
if (prependPreprocessors.length > 0 || appendPreprocessors.length > 0) {
|
|
175
|
+
if (!options.preprocess) {
|
|
176
|
+
options.preprocess = [...prependPreprocessors, ...appendPreprocessors];
|
|
177
|
+
} else if (Array.isArray(options.preprocess)) {
|
|
178
|
+
options.preprocess.unshift(...prependPreprocessors);
|
|
179
|
+
options.preprocess.push(...appendPreprocessors);
|
|
180
|
+
} else {
|
|
181
|
+
options.preprocess = [...prependPreprocessors, options.preprocess, ...appendPreprocessors];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const generateMissingSourceMaps = !!options.experimental?.generateMissingPreprocessorSourcemaps;
|
|
185
|
+
if (options.preprocess && generateMissingSourceMaps) {
|
|
186
|
+
options.preprocess = Array.isArray(options.preprocess)
|
|
187
|
+
? options.preprocess.map((p, i) => validateSourceMapOutputWrapper(p, i))
|
|
188
|
+
: validateSourceMapOutputWrapper(options.preprocess, 0);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function validateSourceMapOutputWrapper(group: PreprocessorGroup, i: number): PreprocessorGroup {
|
|
193
|
+
const wrapper: PreprocessorGroup = {};
|
|
194
|
+
|
|
195
|
+
for (const [processorType, processorFn] of Object.entries(group) as Array<
|
|
196
|
+
// eslint-disable-next-line no-unused-vars
|
|
197
|
+
[keyof PreprocessorGroup, (options: { filename?: string; content: string }) => Processed]
|
|
198
|
+
>) {
|
|
199
|
+
wrapper[processorType] = async (options) => {
|
|
200
|
+
const result = await processorFn(options);
|
|
201
|
+
|
|
202
|
+
if (result && result.code !== options.content) {
|
|
203
|
+
let invalidMap = false;
|
|
204
|
+
if (!result.map) {
|
|
205
|
+
invalidMap = true;
|
|
206
|
+
log.warn.enabled &&
|
|
207
|
+
log.warn.once(
|
|
208
|
+
`preprocessor at index ${i} did not return a sourcemap for ${processorType} transform`,
|
|
209
|
+
{
|
|
210
|
+
filename: options.filename,
|
|
211
|
+
type: processorType,
|
|
212
|
+
processor: processorFn.toString()
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
} else if ((result.map as any)?.mappings === '') {
|
|
216
|
+
invalidMap = true;
|
|
217
|
+
log.warn.enabled &&
|
|
218
|
+
log.warn.once(
|
|
219
|
+
`preprocessor at index ${i} returned an invalid empty sourcemap for ${processorType} transform`,
|
|
220
|
+
{
|
|
221
|
+
filename: options.filename,
|
|
222
|
+
type: processorType,
|
|
223
|
+
processor: processorFn.toString()
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
if (invalidMap) {
|
|
228
|
+
try {
|
|
229
|
+
const map = await buildSourceMap(options.content, result.code, options.filename);
|
|
230
|
+
if (map) {
|
|
231
|
+
log.debug.enabled &&
|
|
232
|
+
log.debug(
|
|
233
|
+
`adding generated sourcemap to preprocesor result for ${options.filename}`
|
|
234
|
+
);
|
|
235
|
+
result.map = map;
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
log.error(`failed to build sourcemap`, e);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return wrapper;
|
|
247
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import relative from 'require-relative';
|
|
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);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isBareImport(importee: string): boolean {
|
|
17
|
+
if (
|
|
18
|
+
!importee ||
|
|
19
|
+
importee[0] === '.' ||
|
|
20
|
+
importee[0] === '\0' ||
|
|
21
|
+
importee.includes(':') ||
|
|
22
|
+
path.isAbsolute(importee)
|
|
23
|
+
) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const parts = importee.split('/');
|
|
27
|
+
switch (parts.length) {
|
|
28
|
+
case 1:
|
|
29
|
+
return true;
|
|
30
|
+
case 2:
|
|
31
|
+
return parts[0].startsWith('@');
|
|
32
|
+
default:
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import MagicString, { MagicStringOptions } from 'magic-string';
|
|
2
|
+
import { log } from './log';
|
|
3
|
+
|
|
4
|
+
export async function buildMagicString(
|
|
5
|
+
from: string,
|
|
6
|
+
to: string,
|
|
7
|
+
options?: MagicStringOptions
|
|
8
|
+
): Promise<MagicString | null> {
|
|
9
|
+
let diff_match_patch, DIFF_DELETE: number, DIFF_INSERT: number;
|
|
10
|
+
try {
|
|
11
|
+
const dmpPkg = await import('diff-match-patch');
|
|
12
|
+
diff_match_patch = dmpPkg.diff_match_patch;
|
|
13
|
+
DIFF_INSERT = dmpPkg.DIFF_INSERT;
|
|
14
|
+
DIFF_DELETE = dmpPkg.DIFF_DELETE;
|
|
15
|
+
} catch (e) {
|
|
16
|
+
log.error.once(
|
|
17
|
+
'Failed to import optional dependency "diff-match-patch". Please install it to enable generated sourcemaps.'
|
|
18
|
+
);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const dmp = new diff_match_patch();
|
|
23
|
+
const diffs = dmp.diff_main(from, to);
|
|
24
|
+
dmp.diff_cleanupSemantic(diffs);
|
|
25
|
+
const m = new MagicString(from, options);
|
|
26
|
+
let pos = 0;
|
|
27
|
+
for (let i = 0; i < diffs.length; i++) {
|
|
28
|
+
const diff = diffs[i];
|
|
29
|
+
const nextDiff = diffs[i + 1];
|
|
30
|
+
if (diff[0] === DIFF_DELETE) {
|
|
31
|
+
if (nextDiff?.[0] === DIFF_INSERT) {
|
|
32
|
+
// delete followed by insert, use overwrite and skip ahead
|
|
33
|
+
m.overwrite(pos, pos + diff[1].length, nextDiff[1]);
|
|
34
|
+
i++;
|
|
35
|
+
} else {
|
|
36
|
+
m.remove(pos, pos + diff[1].length);
|
|
37
|
+
}
|
|
38
|
+
pos += diff[1].length;
|
|
39
|
+
} else if (diff[0] === DIFF_INSERT) {
|
|
40
|
+
if (nextDiff) {
|
|
41
|
+
m.appendRight(pos, diff[1]);
|
|
42
|
+
} else {
|
|
43
|
+
m.append(diff[1]);
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
// unchanged block, advance pos
|
|
47
|
+
pos += diff[1].length;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// at this point m.toString() === to
|
|
51
|
+
return m;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function buildSourceMap(from: string, to: string, filename?: string) {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
const m = await buildMagicString(from, to, { filename });
|
|
57
|
+
return m ? m.generateDecodedMap({ source: filename, hires: true, includeContent: false }) : null;
|
|
58
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { SvelteRequest } from './id';
|
|
2
|
+
import { Code, CompileData } from './compile';
|
|
3
|
+
|
|
4
|
+
export class VitePluginSvelteCache {
|
|
5
|
+
private _css = new Map<string, Code>();
|
|
6
|
+
private _js = new Map<string, Code>();
|
|
7
|
+
private _dependencies = new Map<string, string[]>();
|
|
8
|
+
private _dependants = new Map<string, Set<string>>();
|
|
9
|
+
|
|
10
|
+
public update(compileData: CompileData) {
|
|
11
|
+
this.updateCSS(compileData);
|
|
12
|
+
this.updateJS(compileData);
|
|
13
|
+
this.updateDependencies(compileData);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private updateCSS(compileData: CompileData) {
|
|
17
|
+
this._css.set(compileData.normalizedFilename, compileData.compiled.css);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private updateJS(compileData: CompileData) {
|
|
21
|
+
if (!compileData.ssr) {
|
|
22
|
+
// do not cache SSR js
|
|
23
|
+
this._js.set(compileData.normalizedFilename, compileData.compiled.js);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private updateDependencies(compileData: CompileData) {
|
|
28
|
+
const id = compileData.normalizedFilename;
|
|
29
|
+
const prevDependencies = this._dependencies.get(id) || [];
|
|
30
|
+
const dependencies = compileData.dependencies;
|
|
31
|
+
this._dependencies.set(id, dependencies);
|
|
32
|
+
const removed = prevDependencies.filter((d) => !dependencies.includes(d));
|
|
33
|
+
const added = dependencies.filter((d) => !prevDependencies.includes(d));
|
|
34
|
+
added.forEach((d) => {
|
|
35
|
+
if (!this._dependants.has(d)) {
|
|
36
|
+
this._dependants.set(d, new Set<string>());
|
|
37
|
+
}
|
|
38
|
+
this._dependants.get(d)!.add(compileData.filename);
|
|
39
|
+
});
|
|
40
|
+
removed.forEach((d) => {
|
|
41
|
+
this._dependants.get(d)!.delete(compileData.filename);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public remove(svelteRequest: SvelteRequest): boolean {
|
|
46
|
+
const id = svelteRequest.normalizedFilename;
|
|
47
|
+
let removed = false;
|
|
48
|
+
if (this._js.delete(id)) {
|
|
49
|
+
removed = true;
|
|
50
|
+
}
|
|
51
|
+
if (this._css.delete(id)) {
|
|
52
|
+
removed = true;
|
|
53
|
+
}
|
|
54
|
+
const dependencies = this._dependencies.get(id);
|
|
55
|
+
if (dependencies) {
|
|
56
|
+
removed = true;
|
|
57
|
+
dependencies.forEach((d) => {
|
|
58
|
+
const dependants = this._dependants.get(d);
|
|
59
|
+
if (dependants && dependants.has(svelteRequest.filename)) {
|
|
60
|
+
dependants.delete(svelteRequest.filename);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
this._dependencies.delete(id);
|
|
64
|
+
}
|
|
65
|
+
return removed;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public getCSS(svelteRequest: SvelteRequest) {
|
|
69
|
+
return this._css.get(svelteRequest.normalizedFilename);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public getJS(svelteRequest: SvelteRequest) {
|
|
73
|
+
if (!svelteRequest.ssr) {
|
|
74
|
+
// SSR js isn't cached
|
|
75
|
+
return this._js.get(svelteRequest.normalizedFilename);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public getDependants(path: string): string[] {
|
|
80
|
+
const dependants = this._dependants.get(path);
|
|
81
|
+
return dependants ? [...dependants] : [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { VitePluginSvelteCache } from './vite-plugin-svelte-cache';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { log } from './log';
|
|
4
|
+
import { IdParser } from './id';
|
|
5
|
+
import { ResolvedOptions } from './options';
|
|
6
|
+
import { knownSvelteConfigNames } from './load-svelte-config';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { FSWatcher } from 'vite';
|
|
9
|
+
|
|
10
|
+
export function setupWatchers(
|
|
11
|
+
options: ResolvedOptions,
|
|
12
|
+
cache: VitePluginSvelteCache,
|
|
13
|
+
requestParser: IdParser
|
|
14
|
+
) {
|
|
15
|
+
const { server, configFile: svelteConfigFile } = options;
|
|
16
|
+
if (!server) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const { watcher, ws } = server;
|
|
20
|
+
const { root, server: serverConfig } = server.config;
|
|
21
|
+
|
|
22
|
+
const emitChangeEventOnDependants = (filename: string) => {
|
|
23
|
+
const dependants = cache.getDependants(filename);
|
|
24
|
+
dependants.forEach((dependant) => {
|
|
25
|
+
if (fs.existsSync(dependant)) {
|
|
26
|
+
log.debug(
|
|
27
|
+
`emitting virtual change event for "${dependant}" because depdendency "${filename}" changed`
|
|
28
|
+
);
|
|
29
|
+
watcher.emit('change', dependant);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const removeUnlinkedFromCache = (filename: string) => {
|
|
35
|
+
const svelteRequest = requestParser(filename, false);
|
|
36
|
+
if (svelteRequest) {
|
|
37
|
+
const removedFromCache = cache.remove(svelteRequest);
|
|
38
|
+
if (removedFromCache) {
|
|
39
|
+
log.debug(`cleared VitePluginSvelteCache for deleted file ${filename}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const triggerViteRestart = (filename: string) => {
|
|
45
|
+
if (serverConfig.middlewareMode) {
|
|
46
|
+
// in middlewareMode we can't restart the server automatically
|
|
47
|
+
// show the user an overlay instead
|
|
48
|
+
const message =
|
|
49
|
+
'Svelte config change detected, restart your dev process to apply the changes.';
|
|
50
|
+
log.info(message, filename);
|
|
51
|
+
ws.send({
|
|
52
|
+
type: 'error',
|
|
53
|
+
err: { message, stack: '', plugin: 'vite-plugin-svelte', id: filename }
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
log.info(`svelte config changed: restarting vite server. - file: ${filename}`);
|
|
57
|
+
server.restart(!!options.experimental?.prebundleSvelteLibraries);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const possibleSvelteConfigs = knownSvelteConfigNames.map((cfg) => path.join(root, cfg));
|
|
62
|
+
const restartOnConfigAdd = (filename: string) => {
|
|
63
|
+
if (possibleSvelteConfigs.includes(filename)) {
|
|
64
|
+
triggerViteRestart(filename);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const restartOnConfigChange = (filename: string) => {
|
|
69
|
+
if (filename === svelteConfigFile) {
|
|
70
|
+
triggerViteRestart(filename);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// collection of watcher listeners by event
|
|
75
|
+
const listenerCollection = {
|
|
76
|
+
add: [] as Array<Function>,
|
|
77
|
+
change: [emitChangeEventOnDependants],
|
|
78
|
+
unlink: [removeUnlinkedFromCache, emitChangeEventOnDependants]
|
|
79
|
+
};
|
|
80
|
+
if (svelteConfigFile) {
|
|
81
|
+
listenerCollection.change.push(restartOnConfigChange);
|
|
82
|
+
listenerCollection.unlink.push(restartOnConfigChange);
|
|
83
|
+
} else {
|
|
84
|
+
listenerCollection.add.push(restartOnConfigAdd);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Object.entries(listenerCollection).forEach(([evt, listeners]) => {
|
|
88
|
+
if (listeners.length > 0) {
|
|
89
|
+
watcher.on(evt, (filename) => listeners.forEach((listener) => listener(filename)));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// taken from vite utils
|
|
94
|
+
export function ensureWatchedFile(watcher: FSWatcher, file: string | null, root: string): void {
|
|
95
|
+
if (
|
|
96
|
+
file &&
|
|
97
|
+
// only need to watch if out of root
|
|
98
|
+
!file.startsWith(root + '/') &&
|
|
99
|
+
// some rollup plugins use null bytes for private resolved Ids
|
|
100
|
+
!file.includes('\0') &&
|
|
101
|
+
fs.existsSync(file)
|
|
102
|
+
) {
|
|
103
|
+
// resolve file to normalized system path
|
|
104
|
+
watcher.add(path.resolve(file));
|
|
105
|
+
}
|
|
106
|
+
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# @sveltejs/vite-plugin-svelte
|
|
2
|
-
|
|
3
|
-
## 1.0.0-next.3
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- c3cf3f3: Bump deps
|
|
8
|
-
|
|
9
|
-
## 1.0.0-next.2
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- Include index.js in package
|
|
14
|
-
|
|
15
|
-
## 1.0.0-next.1
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
18
|
-
|
|
19
|
-
- 865df9d: Bump version to allow publishing via pnpm
|