@vigla/vite-plugin 0.0.0-stage → 0.1.1
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/dist/api.d.ts +12 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +1 -0
- package/dist/api.js.map +1 -0
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +48 -0
- package/dist/compile.js.map +1 -0
- package/dist/compiler.d.ts +115 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +1 -0
- package/dist/compiler.js.map +1 -0
- package/dist/config-file.d.ts +10 -0
- package/dist/config-file.d.ts.map +1 -0
- package/dist/config-file.js +63 -0
- package/dist/config-file.js.map +1 -0
- package/dist/dependencies.d.ts +3 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +40 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/error.d.ts +7 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +49 -0
- package/dist/error.js.map +1 -0
- package/dist/front-end.d.ts +24 -0
- package/dist/front-end.d.ts.map +1 -0
- package/dist/front-end.js +120 -0
- package/dist/front-end.js.map +1 -0
- package/dist/id.d.ts +40 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +144 -0
- package/dist/id.js.map +1 -0
- package/dist/identity.d.ts +41 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +31 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +17 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +92 -0
- package/dist/log.js.map +1 -0
- package/dist/maps.d.ts +8 -0
- package/dist/maps.d.ts.map +1 -0
- package/dist/maps.js +37 -0
- package/dist/maps.js.map +1 -0
- package/dist/messages.d.ts +17 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +16 -0
- package/dist/messages.js.map +1 -0
- package/dist/options.d.ts +26 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +187 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/compile-module.d.ts +5 -0
- package/dist/plugins/compile-module.d.ts.map +1 -0
- package/dist/plugins/compile-module.js +50 -0
- package/dist/plugins/compile-module.js.map +1 -0
- package/dist/plugins/compile.d.ts +5 -0
- package/dist/plugins/compile.d.ts.map +1 -0
- package/dist/plugins/compile.js +40 -0
- package/dist/plugins/compile.js.map +1 -0
- package/dist/plugins/configure.d.ts +6 -0
- package/dist/plugins/configure.d.ts.map +1 -0
- package/dist/plugins/configure.js +54 -0
- package/dist/plugins/configure.js.map +1 -0
- package/dist/plugins/hot-update.d.ts +5 -0
- package/dist/plugins/hot-update.d.ts.map +1 -0
- package/dist/plugins/hot-update.js +137 -0
- package/dist/plugins/hot-update.js.map +1 -0
- package/dist/plugins/load.d.ts +6 -0
- package/dist/plugins/load.d.ts.map +1 -0
- package/dist/plugins/load.js +79 -0
- package/dist/plugins/load.js.map +1 -0
- package/dist/plugins/optimizer.d.ts +5 -0
- package/dist/plugins/optimizer.d.ts.map +1 -0
- package/dist/plugins/optimizer.js +174 -0
- package/dist/plugins/optimizer.js.map +1 -0
- package/dist/plugins/preprocess.d.ts +11 -0
- package/dist/plugins/preprocess.d.ts.map +1 -0
- package/dist/plugins/preprocess.js +142 -0
- package/dist/plugins/preprocess.js.map +1 -0
- package/dist/plugins/runtime-scan.d.ts +4 -0
- package/dist/plugins/runtime-scan.d.ts.map +1 -0
- package/dist/plugins/runtime-scan.js +56 -0
- package/dist/plugins/runtime-scan.js.map +1 -0
- package/dist/plugins/scan.d.ts +5 -0
- package/dist/plugins/scan.d.ts.map +1 -0
- package/dist/plugins/scan.js +198 -0
- package/dist/plugins/scan.js.map +1 -0
- package/dist/preprocess.d.ts +6 -0
- package/dist/preprocess.d.ts.map +1 -0
- package/dist/preprocess.js +164 -0
- package/dist/preprocess.js.map +1 -0
- package/dist/public.d.ts +47 -0
- package/dist/public.d.ts.map +1 -0
- package/dist/public.js +1 -0
- package/dist/public.js.map +1 -0
- package/dist/vite-config.d.ts +14 -0
- package/dist/vite-config.d.ts.map +1 -0
- package/dist/vite-config.js +167 -0
- package/dist/vite-config.js.map +1 -0
- package/dist/warnings.d.ts +6 -0
- package/dist/warnings.d.ts.map +1 -0
- package/dist/warnings.js +57 -0
- package/dist/warnings.js.map +1 -0
- package/package.json +24 -5
- package/src/api.ts +12 -0
- package/src/compile.ts +96 -0
- package/src/compiler.ts +129 -0
- package/src/config-file.ts +75 -0
- package/src/dependencies.ts +47 -0
- package/src/error.ts +64 -0
- package/src/front-end.ts +146 -0
- package/src/id.ts +225 -0
- package/src/identity.ts +74 -0
- package/src/index.ts +61 -0
- package/src/log.ts +105 -0
- package/src/maps.ts +36 -0
- package/src/messages.ts +40 -0
- package/src/options.ts +257 -0
- package/src/plugins/compile-module.ts +65 -0
- package/src/plugins/compile.ts +49 -0
- package/src/plugins/configure.ts +63 -0
- package/src/plugins/hot-update.ts +159 -0
- package/src/plugins/load.ts +91 -0
- package/src/plugins/optimizer.ts +262 -0
- package/src/plugins/preprocess.ts +163 -0
- package/src/plugins/runtime-scan.ts +75 -0
- package/src/plugins/scan.ts +206 -0
- package/src/preprocess.ts +190 -0
- package/src/public.ts +56 -0
- package/src/vite-config.ts +252 -0
- package/src/warnings.ts +66 -0
- package/README.md +0 -3
package/src/options.ts
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import deepmerge from 'deepmerge';
|
|
4
|
+
import {
|
|
5
|
+
normalizePath,
|
|
6
|
+
type ConfigEnv,
|
|
7
|
+
type ResolvedConfig,
|
|
8
|
+
type UserConfig,
|
|
9
|
+
type ViteDevServer
|
|
10
|
+
} from 'vite';
|
|
11
|
+
import type { CompileOptions } from './compiler.ts';
|
|
12
|
+
import { loadConfigFile } from './config-file.ts';
|
|
13
|
+
import type { FrontEnd } from './front-end.ts';
|
|
14
|
+
import { ownNames, type Identity, type Names } from './identity.ts';
|
|
15
|
+
import type { Log } from './log.ts';
|
|
16
|
+
import type { Config, Options } from './public.ts';
|
|
17
|
+
|
|
18
|
+
export type RawOptions = Partial<Options>;
|
|
19
|
+
|
|
20
|
+
export interface PreResolvedOptions extends Options {
|
|
21
|
+
root: string;
|
|
22
|
+
isBuild: boolean;
|
|
23
|
+
isServe: boolean;
|
|
24
|
+
isDebug: boolean;
|
|
25
|
+
extensions: string[];
|
|
26
|
+
emitCss: boolean;
|
|
27
|
+
prebundleLibraries: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ResolvedOptions extends PreResolvedOptions {
|
|
31
|
+
compilerOptions: CompileOptions;
|
|
32
|
+
isProduction: boolean;
|
|
33
|
+
server?: ViteDevServer;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const rootOptions = new Set(['extensions', 'compilerOptions', 'preprocess', 'onwarn']);
|
|
37
|
+
|
|
38
|
+
function pluginOptions(names: Names): Set<string> {
|
|
39
|
+
return new Set([
|
|
40
|
+
'include',
|
|
41
|
+
'exclude',
|
|
42
|
+
'emitCss',
|
|
43
|
+
'disableDependencyReinclusion',
|
|
44
|
+
names.prebundle,
|
|
45
|
+
'inspector',
|
|
46
|
+
'dynamicCompileOptions',
|
|
47
|
+
'experimental'
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function toOwnNames(source: Record<string, unknown>, names: Names): Record<string, unknown> {
|
|
52
|
+
const result = { ...source };
|
|
53
|
+
if (names.prebundle !== ownNames.prebundle && names.prebundle in result) {
|
|
54
|
+
result[ownNames.prebundle] = result[names.prebundle];
|
|
55
|
+
delete result[names.prebundle];
|
|
56
|
+
}
|
|
57
|
+
const experimental = result.experimental as Record<string, unknown> | undefined;
|
|
58
|
+
if (
|
|
59
|
+
names.resolveWarnings !== ownNames.resolveWarnings &&
|
|
60
|
+
experimental != null &&
|
|
61
|
+
names.resolveWarnings in experimental
|
|
62
|
+
) {
|
|
63
|
+
const renamed = {
|
|
64
|
+
...experimental,
|
|
65
|
+
[ownNames.resolveWarnings]: experimental[names.resolveWarnings]
|
|
66
|
+
};
|
|
67
|
+
delete renamed[names.resolveWarnings];
|
|
68
|
+
result.experimental = renamed;
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function arraify<T>(value: T | T[] | null | undefined): T[] {
|
|
74
|
+
return value == null ? [] : Array.isArray(value) ? value : [value];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function validateInlineOptions(
|
|
78
|
+
options: RawOptions | undefined,
|
|
79
|
+
{ names, log }: Identity
|
|
80
|
+
): void {
|
|
81
|
+
const accepted = new Set(['configFile', ...pluginOptions(names), ...rootOptions]);
|
|
82
|
+
const invalid = Object.keys(options ?? {}).filter((key) => !accepted.has(key));
|
|
83
|
+
if (invalid.length > 0) {
|
|
84
|
+
log.warn(
|
|
85
|
+
`invalid plugin ${invalid.length === 1 ? 'option' : 'options'} ${invalid.map((key) => `\`${key}\``).join(', ')} in inline config`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function convertPluginOptions(
|
|
91
|
+
config: (Partial<Config> & { configFile?: string }) | undefined,
|
|
92
|
+
{ names, messages, log }: Identity
|
|
93
|
+
): RawOptions | undefined {
|
|
94
|
+
if (!config) return undefined;
|
|
95
|
+
const pluginKeys = pluginOptions(names);
|
|
96
|
+
const misplaced = Object.keys(config).filter((key) => pluginKeys.has(key));
|
|
97
|
+
if (misplaced.length > 0) {
|
|
98
|
+
throw new Error(messages.optionsMisplaced(misplaced.join(', ')));
|
|
99
|
+
}
|
|
100
|
+
if (!config.vitePlugin) return config as RawOptions;
|
|
101
|
+
const plugin = config.vitePlugin as Record<string, unknown>;
|
|
102
|
+
const keys = Object.keys(plugin);
|
|
103
|
+
const atRoot = keys.filter((key) => rootOptions.has(key));
|
|
104
|
+
if (atRoot.length > 0) {
|
|
105
|
+
throw new Error(messages.optionsAtRoot(atRoot.join(', ')));
|
|
106
|
+
}
|
|
107
|
+
const duplicate = keys.filter((key) => Object.prototype.hasOwnProperty.call(config, key));
|
|
108
|
+
if (duplicate.length > 0) {
|
|
109
|
+
throw new Error(messages.optionsDuplicate(duplicate.join(', ')));
|
|
110
|
+
}
|
|
111
|
+
const unknown = keys.filter((key) => !pluginKeys.has(key));
|
|
112
|
+
if (unknown.length > 0) {
|
|
113
|
+
log.warn(messages.optionsUnknown(unknown.join(', ')));
|
|
114
|
+
for (const key of unknown) delete plugin[key];
|
|
115
|
+
}
|
|
116
|
+
const result: Record<string, unknown> = { ...config, ...plugin };
|
|
117
|
+
delete result.vitePlugin;
|
|
118
|
+
return result as RawOptions;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function mergeConfigs<T>(...configs: (object | undefined)[]): T {
|
|
122
|
+
let result: object = {};
|
|
123
|
+
for (const config of configs) {
|
|
124
|
+
if (config == null) continue;
|
|
125
|
+
result = deepmerge(result, config, { arrayMerge: (target, source) => source ?? target });
|
|
126
|
+
}
|
|
127
|
+
return result as T;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function viteRoot(config: UserConfig): string {
|
|
131
|
+
return normalizePath(config.root ? path.resolve(config.root) : process.cwd());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function preResolveOptions(
|
|
135
|
+
inline: RawOptions | undefined,
|
|
136
|
+
viteUserConfig: UserConfig,
|
|
137
|
+
viteEnv: ConfigEnv,
|
|
138
|
+
frontEnds: readonly FrontEnd[],
|
|
139
|
+
identity: Identity
|
|
140
|
+
): Promise<PreResolvedOptions> {
|
|
141
|
+
const { names, history, log } = identity;
|
|
142
|
+
const root = viteRoot(viteUserConfig);
|
|
143
|
+
const isBuild = viteEnv.command === 'build';
|
|
144
|
+
const defaults = {
|
|
145
|
+
extensions: [...new Set(frontEnds.flatMap((frontEnd) => frontEnd.components))],
|
|
146
|
+
emitCss: true,
|
|
147
|
+
[names.prebundle]: !isBuild
|
|
148
|
+
};
|
|
149
|
+
const stems = frontEnds.map((frontEnd) => frontEnd.config);
|
|
150
|
+
const loaded = convertPluginOptions(
|
|
151
|
+
await loadConfigFile({ ...viteUserConfig, root }, inline, stems, identity),
|
|
152
|
+
identity
|
|
153
|
+
);
|
|
154
|
+
const extra = {
|
|
155
|
+
root,
|
|
156
|
+
isBuild,
|
|
157
|
+
isServe: viteEnv.command === 'serve',
|
|
158
|
+
isDebug: process.env.DEBUG != null
|
|
159
|
+
};
|
|
160
|
+
const merged = mergeConfigs<Record<string, unknown>>(defaults, loaded, inline ?? {}, extra);
|
|
161
|
+
if (loaded?.configFile) merged.configFile = loaded.configFile;
|
|
162
|
+
history.options?.(merged, log);
|
|
163
|
+
return toOwnNames(merged, names) as unknown as PreResolvedOptions;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function enforceOptionsForHmr(
|
|
167
|
+
options: ResolvedOptions,
|
|
168
|
+
viteConfig: ResolvedConfig,
|
|
169
|
+
frontEnds: readonly FrontEnd[],
|
|
170
|
+
{ names, messages, log }: Identity
|
|
171
|
+
): void {
|
|
172
|
+
const compilerOptions = options.compilerOptions;
|
|
173
|
+
if (compilerOptions.hmr && viteConfig.server?.hmr === false) {
|
|
174
|
+
log.warn(
|
|
175
|
+
'vite config server.hmr is false but compilerOptions.hmr is true. Forcing compilerOptions.hmr to false as it would not work.'
|
|
176
|
+
);
|
|
177
|
+
compilerOptions.hmr = false;
|
|
178
|
+
}
|
|
179
|
+
const extension = frontEnds[0]?.components[0];
|
|
180
|
+
if (
|
|
181
|
+
extension &&
|
|
182
|
+
options.isServe &&
|
|
183
|
+
compilerOptions.hmr &&
|
|
184
|
+
options.emitCss &&
|
|
185
|
+
compilerOptions.cssHash
|
|
186
|
+
) {
|
|
187
|
+
let usesFilename = false;
|
|
188
|
+
let usesCss = false;
|
|
189
|
+
compilerOptions.cssHash({
|
|
190
|
+
get filename() {
|
|
191
|
+
usesFilename = true;
|
|
192
|
+
return `Foo${extension}`;
|
|
193
|
+
},
|
|
194
|
+
get css() {
|
|
195
|
+
usesCss = true;
|
|
196
|
+
return '.foo{}';
|
|
197
|
+
},
|
|
198
|
+
name: 'Foo',
|
|
199
|
+
hash: (input) => input
|
|
200
|
+
});
|
|
201
|
+
if (!usesFilename || usesCss) {
|
|
202
|
+
const link = names.links.cssHash;
|
|
203
|
+
log.warn(`${messages.cssHash}${link ? ` See ${link} for more information.` : ''}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function enforceOptionsForProduction(options: ResolvedOptions, log: Log): void {
|
|
209
|
+
if (!options.isProduction) return;
|
|
210
|
+
if (options.compilerOptions.hmr) {
|
|
211
|
+
log.warn(
|
|
212
|
+
'you are building for production but compilerOptions.hmr is true, forcing it to false'
|
|
213
|
+
);
|
|
214
|
+
options.compilerOptions.hmr = false;
|
|
215
|
+
}
|
|
216
|
+
if (options.compilerOptions.dev) {
|
|
217
|
+
log.warn(
|
|
218
|
+
'you are building for production but compilerOptions.dev is true, forcing it to false'
|
|
219
|
+
);
|
|
220
|
+
options.compilerOptions.dev = false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function removeIgnoredOptions(options: ResolvedOptions, { name, messages, log }: Identity): void {
|
|
225
|
+
const ignored = ['generate', 'format', 'filename'];
|
|
226
|
+
const passed = Object.keys(options.compilerOptions ?? {}).filter((key) => ignored.includes(key));
|
|
227
|
+
if (passed.length === 0) return;
|
|
228
|
+
log.warn(messages.controlledOptions(name, passed.join(', ')));
|
|
229
|
+
for (const key of passed) delete options.compilerOptions[key];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function resolveOptions(
|
|
233
|
+
preResolved: PreResolvedOptions,
|
|
234
|
+
viteConfig: ResolvedConfig,
|
|
235
|
+
frontEnds: readonly FrontEnd[],
|
|
236
|
+
identity: Identity
|
|
237
|
+
): ResolvedOptions {
|
|
238
|
+
const defaults = {
|
|
239
|
+
compilerOptions: {
|
|
240
|
+
css: preResolved.emitCss ? 'external' : 'injected',
|
|
241
|
+
dev: !viteConfig.isProduction,
|
|
242
|
+
hmr:
|
|
243
|
+
!viteConfig.isProduction &&
|
|
244
|
+
!preResolved.isBuild &&
|
|
245
|
+
viteConfig.server &&
|
|
246
|
+
viteConfig.server.hmr !== false
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
const extra = { root: viteConfig.root, isProduction: viteConfig.isProduction };
|
|
250
|
+
const merged = mergeConfigs<ResolvedOptions>(defaults, preResolved, extra);
|
|
251
|
+
const { log } = identity;
|
|
252
|
+
removeIgnoredOptions(merged, identity);
|
|
253
|
+
identity.history.config?.(viteConfig, log);
|
|
254
|
+
enforceOptionsForHmr(merged, viteConfig, frontEnds, identity);
|
|
255
|
+
enforceOptionsForProduction(merged, log);
|
|
256
|
+
return merged;
|
|
257
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { PluginAPI } from '../api.ts';
|
|
3
|
+
import { dynamicOptions } from '../compile.ts';
|
|
4
|
+
import type { CompileError, CompileOptions } from '../compiler.ts';
|
|
5
|
+
import { toRollupError } from '../error.ts';
|
|
6
|
+
import { buildModuleIdFilter, buildModuleIdParser, type ModuleIdParser } from '../id.ts';
|
|
7
|
+
import type { Identity } from '../identity.ts';
|
|
8
|
+
import { logCompilerWarnings } from '../warnings.ts';
|
|
9
|
+
|
|
10
|
+
export function compileModule(api: PluginAPI, identity: Identity): Plugin {
|
|
11
|
+
const { name, log } = identity;
|
|
12
|
+
let idParser: ModuleIdParser;
|
|
13
|
+
const plugin: Plugin = {
|
|
14
|
+
name: `${name}:compile-module`,
|
|
15
|
+
enforce: 'post',
|
|
16
|
+
configResolved() {
|
|
17
|
+
Object.assign(plugin.transform as object, {
|
|
18
|
+
filter: buildModuleIdFilter(api.options, api.frontEnds)
|
|
19
|
+
});
|
|
20
|
+
idParser = buildModuleIdParser(api.options, api.frontEnds, identity);
|
|
21
|
+
},
|
|
22
|
+
transform: {
|
|
23
|
+
async handler(code, id) {
|
|
24
|
+
const ssr = this.environment.config.consumer === 'server';
|
|
25
|
+
const request = idParser(id, ssr);
|
|
26
|
+
if (!request) return undefined;
|
|
27
|
+
const filename = request.filename;
|
|
28
|
+
const compileOptions: CompileOptions = {
|
|
29
|
+
...api.moduleOptions,
|
|
30
|
+
generate: ssr ? 'server' : 'client',
|
|
31
|
+
filename
|
|
32
|
+
};
|
|
33
|
+
const dynamic = await dynamicOptions(
|
|
34
|
+
api.options,
|
|
35
|
+
filename,
|
|
36
|
+
code,
|
|
37
|
+
compileOptions,
|
|
38
|
+
this.environment,
|
|
39
|
+
log,
|
|
40
|
+
'compileModule'
|
|
41
|
+
);
|
|
42
|
+
const final: CompileOptions = dynamic ? { ...compileOptions, ...dynamic } : compileOptions;
|
|
43
|
+
if (dynamic?.experimental) {
|
|
44
|
+
final.experimental = { ...compileOptions.experimental, ...dynamic.experimental };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (log.debug.enabled) {
|
|
48
|
+
log.debug(
|
|
49
|
+
`final module options for ${filename}: ${JSON.stringify(final)}`,
|
|
50
|
+
undefined,
|
|
51
|
+
'compileModule'
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const result = request.frontEnd.compiler.compileModule(code, final);
|
|
56
|
+
logCompilerWarnings(request, result.warnings, api.options, identity);
|
|
57
|
+
return { code: result.js.code, map: result.js.map as never };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw toRollupError(error as CompileError, api.options);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return plugin;
|
|
65
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
import type { PluginAPI } from '../api.ts';
|
|
3
|
+
import { compileComponent, type Compiled } from '../compile.ts';
|
|
4
|
+
import type { CompileError } from '../compiler.ts';
|
|
5
|
+
import { toRollupError } from '../error.ts';
|
|
6
|
+
import type { Identity } from '../identity.ts';
|
|
7
|
+
import { logCompilerWarnings } from '../warnings.ts';
|
|
8
|
+
|
|
9
|
+
export function compile(api: PluginAPI, identity: Identity): Plugin {
|
|
10
|
+
const { name, names } = identity;
|
|
11
|
+
const plugin: Plugin = {
|
|
12
|
+
name: `${name}:compile`,
|
|
13
|
+
configResolved() {
|
|
14
|
+
Object.assign(plugin.transform as object, { filter: api.filter });
|
|
15
|
+
},
|
|
16
|
+
transform: {
|
|
17
|
+
async handler(code, id) {
|
|
18
|
+
const ssr = this.environment.config.consumer === 'server';
|
|
19
|
+
const request = api.idParser(id, ssr);
|
|
20
|
+
if (!request || request.raw) return undefined;
|
|
21
|
+
let compiled: Compiled;
|
|
22
|
+
try {
|
|
23
|
+
compiled = await compileComponent(
|
|
24
|
+
request,
|
|
25
|
+
code,
|
|
26
|
+
api.options,
|
|
27
|
+
this.environment,
|
|
28
|
+
identity,
|
|
29
|
+
this.getCombinedSourcemap() as unknown as object
|
|
30
|
+
);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
throw toRollupError(error as CompileError, api.options);
|
|
33
|
+
}
|
|
34
|
+
if (compiled.compiled.warnings) {
|
|
35
|
+
logCompilerWarnings(request, compiled.compiled.warnings, api.options, identity);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
code: compiled.compiled.js.code,
|
|
39
|
+
map: compiled.compiled.js.map as never,
|
|
40
|
+
moduleType: 'js',
|
|
41
|
+
meta: {
|
|
42
|
+
[names.metaKey]: { css: compiled.compiled.css }
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return plugin;
|
|
49
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import type { Plugin } from 'vite';
|
|
3
|
+
import type { PluginAPI } from '../api.ts';
|
|
4
|
+
import { frontEnds } from '../front-end.ts';
|
|
5
|
+
import { buildIdFilter, buildIdParser } from '../id.ts';
|
|
6
|
+
import type { Identity } from '../identity.ts';
|
|
7
|
+
import {
|
|
8
|
+
arraify,
|
|
9
|
+
preResolveOptions,
|
|
10
|
+
resolveOptions,
|
|
11
|
+
validateInlineOptions,
|
|
12
|
+
viteRoot,
|
|
13
|
+
type PreResolvedOptions,
|
|
14
|
+
type RawOptions
|
|
15
|
+
} from '../options.ts';
|
|
16
|
+
import { configureStyles } from '../preprocess.ts';
|
|
17
|
+
import { buildExtraViteConfig, ensureEnvironmentResolve } from '../vite-config.ts';
|
|
18
|
+
|
|
19
|
+
export function configure(api: PluginAPI, identity: Identity, inline?: RawOptions): Plugin {
|
|
20
|
+
const { log } = identity;
|
|
21
|
+
validateInlineOptions(inline, identity);
|
|
22
|
+
let preResolved: PreResolvedOptions;
|
|
23
|
+
return {
|
|
24
|
+
name: `${identity.name}:config`,
|
|
25
|
+
api,
|
|
26
|
+
enforce: 'pre',
|
|
27
|
+
config: {
|
|
28
|
+
order: 'pre',
|
|
29
|
+
async handler(config, env) {
|
|
30
|
+
if (process.env.DEBUG) log.setLevel('debug');
|
|
31
|
+
else if (config.logLevel) log.setLevel(config.logLevel);
|
|
32
|
+
api.frontEnds = await frontEnds(viteRoot(config));
|
|
33
|
+
preResolved = await preResolveOptions(inline, config, env, api.frontEnds, identity);
|
|
34
|
+
await configureStyles(arraify(preResolved.preprocess), config);
|
|
35
|
+
const extra = await buildExtraViteConfig(preResolved, config, api.frontEnds, identity);
|
|
36
|
+
log.debug('additional vite config', extra, 'config');
|
|
37
|
+
return extra;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
configResolved: {
|
|
41
|
+
order: 'pre',
|
|
42
|
+
handler(config) {
|
|
43
|
+
api.options = resolveOptions(preResolved, config, api.frontEnds, identity);
|
|
44
|
+
api.moduleOptions = {
|
|
45
|
+
...preResolved.compilerOptions,
|
|
46
|
+
dev: api.options.compilerOptions.dev
|
|
47
|
+
};
|
|
48
|
+
api.filter = buildIdFilter(api.options, api.frontEnds, identity);
|
|
49
|
+
api.idParser = buildIdParser(api.options, api.frontEnds, identity);
|
|
50
|
+
log.debug('resolved options', api.options, 'config');
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
configEnvironment(name, config, opts) {
|
|
54
|
+
const resolve = ensureEnvironmentResolve(name, config, opts);
|
|
55
|
+
const conditions = [...new Set(api.frontEnds.map((frontEnd) => frontEnd.condition))];
|
|
56
|
+
resolve.mainFields.unshift(...conditions);
|
|
57
|
+
resolve.conditions.push(...conditions);
|
|
58
|
+
},
|
|
59
|
+
configureServer(server) {
|
|
60
|
+
api.options.server = server;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import type { EnvironmentModuleNode, Plugin, ViteDevServer } from 'vite';
|
|
3
|
+
import type { PluginAPI } from '../api.ts';
|
|
4
|
+
import { configNames } from '../config-file.ts';
|
|
5
|
+
import type { Identity } from '../identity.ts';
|
|
6
|
+
import type { Log } from '../log.ts';
|
|
7
|
+
|
|
8
|
+
function normalize(code: string | null | undefined): string | null | undefined {
|
|
9
|
+
if (code == null) return code;
|
|
10
|
+
return code
|
|
11
|
+
.replace(/(\$\.add_locations\(.*), (\[\[[\d, [\]]+]])\)/g, '$1, []')
|
|
12
|
+
.replace(/[?&]t=\d{13}\b/g, '');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function same(previous: string | null | undefined, next: string | null | undefined): boolean {
|
|
16
|
+
return (
|
|
17
|
+
(previous == null && next == null) || (previous != null && next != null && previous === next)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function changed(
|
|
22
|
+
previous: string | null | undefined,
|
|
23
|
+
next: string | null | undefined,
|
|
24
|
+
id: string | null,
|
|
25
|
+
log: Log
|
|
26
|
+
): boolean {
|
|
27
|
+
if (same(previous, next)) return false;
|
|
28
|
+
const loose = same(normalize(previous), normalize(next));
|
|
29
|
+
if (loose) {
|
|
30
|
+
log.debug(
|
|
31
|
+
`ignoring compiler output change for ${id} as it is equal to previous output after normalization`,
|
|
32
|
+
undefined,
|
|
33
|
+
'hmr'
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return !loose;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function watchConfig(
|
|
40
|
+
api: PluginAPI,
|
|
41
|
+
{ name, messages, log }: Identity,
|
|
42
|
+
server: ViteDevServer
|
|
43
|
+
): void {
|
|
44
|
+
const configFile = api.options.configFile;
|
|
45
|
+
if (configFile === false) return;
|
|
46
|
+
const { watcher, ws } = server;
|
|
47
|
+
const { root, server: serverConfig } = server.config;
|
|
48
|
+
const restart = (filename: string) => {
|
|
49
|
+
if (serverConfig.middlewareMode) {
|
|
50
|
+
const message = messages.configChangeDetected;
|
|
51
|
+
log.info(message, filename);
|
|
52
|
+
ws.send({
|
|
53
|
+
type: 'error',
|
|
54
|
+
err: { message, stack: '', plugin: name, id: filename }
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
log.info(messages.configChanged(filename));
|
|
58
|
+
void server.restart();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
if (configFile) {
|
|
62
|
+
const onConfig = (filename: string) => {
|
|
63
|
+
if (filename === configFile) restart(filename);
|
|
64
|
+
};
|
|
65
|
+
watcher.on('change', onConfig);
|
|
66
|
+
watcher.on('unlink', onConfig);
|
|
67
|
+
} else {
|
|
68
|
+
const stems = api.frontEnds.map((frontEnd) => frontEnd.config);
|
|
69
|
+
const candidates = configNames(stems).map((file) => path.join(root, file));
|
|
70
|
+
watcher.on('add', (filename: string) => {
|
|
71
|
+
if (candidates.includes(filename)) restart(filename);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function hotUpdate(api: PluginAPI, identity: Identity): Plugin {
|
|
77
|
+
const { log, virtualStyle } = identity;
|
|
78
|
+
const results = new Map<string | null, string>();
|
|
79
|
+
const plugin: Plugin = {
|
|
80
|
+
name: `${identity.name}:hot-update`,
|
|
81
|
+
enforce: 'post',
|
|
82
|
+
configResolved() {
|
|
83
|
+
Object.assign(plugin.transform as object, {
|
|
84
|
+
filter: {
|
|
85
|
+
id: {
|
|
86
|
+
include: [...api.filter.id.include, virtualStyle],
|
|
87
|
+
exclude: [
|
|
88
|
+
/\/node_modules\//,
|
|
89
|
+
...api.filter.id.exclude.filter((item) => item !== virtualStyle)
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
applyToEnvironment(environment) {
|
|
96
|
+
const enabled = api.options.compilerOptions.hmr && api.options.emitCss;
|
|
97
|
+
return !!enabled && environment.config.consumer === 'client';
|
|
98
|
+
},
|
|
99
|
+
configureServer(server) {
|
|
100
|
+
const client = Object.values(server.environments).find(
|
|
101
|
+
(environment) => environment.config.consumer === 'client'
|
|
102
|
+
);
|
|
103
|
+
if (client) watchConfig(api, identity, server);
|
|
104
|
+
else {
|
|
105
|
+
identity.log.warn(identity.messages.noClientEnvironment);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
buildStart() {
|
|
109
|
+
results.clear();
|
|
110
|
+
},
|
|
111
|
+
transform: {
|
|
112
|
+
order: 'post',
|
|
113
|
+
handler(code, id) {
|
|
114
|
+
results.set(id, code);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
hotUpdate: {
|
|
118
|
+
order: 'post',
|
|
119
|
+
async handler(context) {
|
|
120
|
+
const request = api.idParser(context.file, false, context.timestamp);
|
|
121
|
+
if (!request) return undefined;
|
|
122
|
+
const own: EnvironmentModuleNode[] = [];
|
|
123
|
+
const others: EnvironmentModuleNode[] = [];
|
|
124
|
+
for (const module of context.modules) {
|
|
125
|
+
(results.has(module.id) ? own : others).push(module);
|
|
126
|
+
}
|
|
127
|
+
if (own.length === 0) return undefined;
|
|
128
|
+
const previous = own.map((module) => results.get(module.id));
|
|
129
|
+
const seen = new Set<string>();
|
|
130
|
+
const transform = async (url: string) => {
|
|
131
|
+
if (seen.has(url)) return;
|
|
132
|
+
seen.add(url);
|
|
133
|
+
await this.environment.transformRequest(url);
|
|
134
|
+
};
|
|
135
|
+
await transform(request.filename);
|
|
136
|
+
const affected: EnvironmentModuleNode[] = [];
|
|
137
|
+
for (const [index, module] of own.entries()) {
|
|
138
|
+
await transform(module.url);
|
|
139
|
+
if (changed(previous[index], results.get(module.id), module.id, log))
|
|
140
|
+
affected.push(module);
|
|
141
|
+
else {
|
|
142
|
+
log.debug(
|
|
143
|
+
`skipping hot update for ${module.id} because result is unchanged`,
|
|
144
|
+
undefined,
|
|
145
|
+
'hmr'
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
log.debug(
|
|
150
|
+
`hotUpdate for ${request.id} result: [${affected.map((module) => module.id).join(', ')}]`,
|
|
151
|
+
undefined,
|
|
152
|
+
'hmr'
|
|
153
|
+
);
|
|
154
|
+
return [...affected, ...others];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
return plugin;
|
|
159
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import type { Plugin } from 'vite';
|
|
3
|
+
import type { PluginAPI } from '../api.ts';
|
|
4
|
+
import type { Css } from '../compiler.ts';
|
|
5
|
+
import type { Identity } from '../identity.ts';
|
|
6
|
+
|
|
7
|
+
type CssMeta = Record<string, { css?: Css | null } | undefined>;
|
|
8
|
+
|
|
9
|
+
export function loadCompiledCss(
|
|
10
|
+
api: PluginAPI,
|
|
11
|
+
{ name, log, names, virtualStyle }: Identity
|
|
12
|
+
): Plugin {
|
|
13
|
+
let cached = false;
|
|
14
|
+
const kept = new Map<string, Css>();
|
|
15
|
+
const filter = { id: virtualStyle };
|
|
16
|
+
return {
|
|
17
|
+
name: `${name}:load-compiled-css`,
|
|
18
|
+
configResolved(config) {
|
|
19
|
+
cached = config.command === 'serve' || !!config.build?.watch;
|
|
20
|
+
},
|
|
21
|
+
resolveId: {
|
|
22
|
+
filter,
|
|
23
|
+
handler(id) {
|
|
24
|
+
log.debug(`resolveId resolved virtual css module ${id}`, undefined, 'resolve');
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
load: {
|
|
29
|
+
filter,
|
|
30
|
+
async handler(id) {
|
|
31
|
+
const ssr = this.environment.config.consumer === 'server';
|
|
32
|
+
const request = api.idParser(id, ssr);
|
|
33
|
+
if (!request) return undefined;
|
|
34
|
+
if (this.environment.mode === 'dev')
|
|
35
|
+
await this.environment.transformRequest(request.filename);
|
|
36
|
+
const meta = (moduleId: string) =>
|
|
37
|
+
(this.getModuleInfo(moduleId)?.meta as CssMeta | undefined)?.[names.metaKey]?.css ??
|
|
38
|
+
undefined;
|
|
39
|
+
let css = meta(request.filename);
|
|
40
|
+
if (!css) {
|
|
41
|
+
const resolved = await this.resolve(request.filename);
|
|
42
|
+
if (resolved?.id) css = meta(resolved.id);
|
|
43
|
+
}
|
|
44
|
+
if (cached) {
|
|
45
|
+
if (css) kept.set(request.filename, css);
|
|
46
|
+
else css = kept.get(request.filename);
|
|
47
|
+
}
|
|
48
|
+
if (!css) {
|
|
49
|
+
log.warn(`failed to load virtual css module ${id}`, undefined, 'load');
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const { hasGlobal, code, map } = css;
|
|
53
|
+
return {
|
|
54
|
+
code,
|
|
55
|
+
map: map as never,
|
|
56
|
+
moduleType: 'css',
|
|
57
|
+
meta:
|
|
58
|
+
hasGlobal === false
|
|
59
|
+
? { vite: { cssScopeTo: [request.filename, 'default'] as const } }
|
|
60
|
+
: undefined
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function loadCustom(api: PluginAPI, { name, log }: Identity): Plugin {
|
|
68
|
+
const plugin: Plugin = {
|
|
69
|
+
name: `${name}:load-custom`,
|
|
70
|
+
enforce: 'pre',
|
|
71
|
+
configResolved() {
|
|
72
|
+
Object.assign(plugin.load as object, { filter: api.filter });
|
|
73
|
+
},
|
|
74
|
+
load: {
|
|
75
|
+
async handler(id) {
|
|
76
|
+
const config = this.environment.config;
|
|
77
|
+
const request = api.idParser(id, config.consumer === 'server');
|
|
78
|
+
if (!request || request.query.url || !config.assetsInclude(request.filename)) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
log.debug(
|
|
82
|
+
`loading ${request.filename} to prevent vite asset handling to turn it into a url by default`,
|
|
83
|
+
undefined,
|
|
84
|
+
'load'
|
|
85
|
+
);
|
|
86
|
+
return fs.readFileSync(request.filename, 'utf-8');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
return plugin;
|
|
91
|
+
}
|