@vizejs/vite-plugin 0.58.0 → 0.59.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1265 @@
1
+ import { createRequire } from "node:module";
2
+ import fs from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ import path from "node:path";
5
+ import { CONFIG_FILE_NAMES, defineConfig, loadConfig } from "vize";
6
+ import { glob } from "tinyglobby";
7
+ import * as native from "@vizejs/native";
8
+ import { pathToFileURL } from "node:url";
9
+ import { transformWithOxc } from "vite";
10
+ //#region src/hmr.ts
11
+ function didHashChange(prevHash, nextHash) {
12
+ return prevHash !== nextHash;
13
+ }
14
+ function hasHmrChanges(prev, next) {
15
+ if (!prev) return true;
16
+ return didHashChange(prev.scriptHash, next.scriptHash) || didHashChange(prev.templateHash, next.templateHash) || didHashChange(prev.styleHash, next.styleHash);
17
+ }
18
+ /**
19
+ * Detect the type of HMR update needed based on content hash changes.
20
+ *
21
+ * @param prev - Previously compiled module (undefined if first compile)
22
+ * @param next - Newly compiled module
23
+ * @returns The type of HMR update needed
24
+ */
25
+ function detectHmrUpdateType(prev, next) {
26
+ if (!prev) return "full-reload";
27
+ if (didHashChange(prev.scriptHash, next.scriptHash)) return "full-reload";
28
+ const templateChanged = didHashChange(prev.templateHash, next.templateHash);
29
+ if (didHashChange(prev.styleHash, next.styleHash) && !templateChanged) return "style-only";
30
+ if (templateChanged) return "template-only";
31
+ return "full-reload";
32
+ }
33
+ /**
34
+ * Generate HMR-aware code output based on update type.
35
+ */
36
+ function generateHmrCode(scopeId, updateType) {
37
+ return `
38
+ if (import.meta.hot) {
39
+ _sfc_main.__hmrId = ${JSON.stringify(scopeId)};
40
+ _sfc_main.__hmrUpdateType = ${JSON.stringify(updateType)};
41
+
42
+ import.meta.hot.accept((mod) => {
43
+ if (!mod) return;
44
+ const { default: updated } = mod;
45
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
46
+ const updateType = updated.__hmrUpdateType || 'full-reload';
47
+ if (updateType === 'template-only') {
48
+ __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render);
49
+ } else {
50
+ __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated);
51
+ }
52
+ }
53
+ });
54
+
55
+ import.meta.hot.on('vize:update', (data) => {
56
+ if (data.id !== _sfc_main.__hmrId) return;
57
+
58
+ if (data.type === 'style-only') {
59
+ // Update styles without remounting component
60
+ const styleId = 'vize-style-' + _sfc_main.__hmrId;
61
+ const styleEl = document.getElementById(styleId);
62
+ if (styleEl && data.css) {
63
+ styleEl.textContent = data.css;
64
+ }
65
+ }
66
+ });
67
+
68
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
69
+ __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
70
+ }
71
+ }`;
72
+ }
73
+ //#endregion
74
+ //#region src/utils/css.ts
75
+ /**
76
+ * Resolve CSS @import statements by inlining the imported files,
77
+ * then resolve @custom-media definitions within the combined CSS.
78
+ *
79
+ * This is necessary because Vize embeds CSS as a JS string via
80
+ * document.createElement('style'), bypassing Vite's CSS pipeline.
81
+ */
82
+ function resolveCssImports(css, importer, aliasRules, isDev, devUrlBase) {
83
+ const customMedia = /* @__PURE__ */ new Map();
84
+ const importRegex = /^@import\s+(?:"([^"]+)"|'([^']+)');?\s*$/gm;
85
+ let result = css;
86
+ result = result.replace(importRegex, (_match, dqPath, sqPath) => {
87
+ const importPath = dqPath || sqPath;
88
+ if (!importPath) return _match;
89
+ const resolved = resolveCssPath(importPath, importer, aliasRules);
90
+ if (!resolved || !fs.existsSync(resolved)) return _match;
91
+ try {
92
+ const content = fs.readFileSync(resolved, "utf-8");
93
+ parseCustomMedia(content, customMedia);
94
+ return content;
95
+ } catch {
96
+ return _match;
97
+ }
98
+ });
99
+ parseCustomMedia(result, customMedia);
100
+ result = result.replace(/^@custom-media\s+[^;]+;\s*$/gm, "");
101
+ if (customMedia.size > 0) for (const [name, query] of customMedia) {
102
+ const escaped = name.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
103
+ result = result.replace(new RegExp(`\\(${escaped}\\)`, "g"), query);
104
+ }
105
+ if (isDev) result = result.replace(/url\(\s*(["']?)([^"')]+)\1\s*\)/g, (_match, quote, urlPath) => {
106
+ const trimmed = urlPath.trim();
107
+ if (trimmed.startsWith("data:") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("/@fs/")) return _match;
108
+ const resolved = resolveCssPath(trimmed, importer, aliasRules);
109
+ if (resolved && fs.existsSync(resolved)) {
110
+ const normalized = resolved.replace(/\\/g, "/");
111
+ const base = devUrlBase ?? "/";
112
+ return `url("${base.endsWith("/") ? base : base + "/"}@fs${normalized}")`;
113
+ }
114
+ return _match;
115
+ });
116
+ result = result.replace(/:deep\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, "$1");
117
+ result = result.replace(/\n{3,}/g, "\n\n");
118
+ return result;
119
+ }
120
+ function parseCustomMedia(css, map) {
121
+ const re = /@custom-media\s+(--[\w-]+)\s+(.+?)\s*;/g;
122
+ let m;
123
+ while ((m = re.exec(css)) !== null) map.set(m[1], m[2]);
124
+ }
125
+ function resolveCssPath(importPath, importer, aliasRules) {
126
+ for (const rule of aliasRules) if (importPath.startsWith(rule.find)) {
127
+ const resolved = importPath.replace(rule.find, rule.replacement);
128
+ return path.resolve(resolved);
129
+ }
130
+ if (importPath.startsWith(".")) {
131
+ const dir = path.dirname(importer);
132
+ return path.resolve(dir, importPath);
133
+ }
134
+ if (path.isAbsolute(importPath)) return importPath;
135
+ return null;
136
+ }
137
+ //#endregion
138
+ //#region src/utils/index.ts
139
+ /** Known CSS preprocessor languages that must be delegated to Vite */
140
+ const PREPROCESSOR_LANGS = new Set([
141
+ "scss",
142
+ "sass",
143
+ "less",
144
+ "stylus",
145
+ "styl"
146
+ ]);
147
+ /** Check if a style block requires Vite's preprocessor pipeline */
148
+ function needsPreprocessor(block) {
149
+ return block.lang !== null && PREPROCESSOR_LANGS.has(block.lang);
150
+ }
151
+ /** Check if a style block uses CSS Modules */
152
+ function isCssModule(block) {
153
+ return block.module !== false;
154
+ }
155
+ /**
156
+ * Check if any style blocks in the compiled module require delegation to
157
+ * Vite's CSS pipeline (preprocessor or CSS Modules).
158
+ */
159
+ function hasDelegatedStyles(compiled) {
160
+ if (!compiled.styles) return false;
161
+ return compiled.styles.some((s) => needsPreprocessor(s) || isCssModule(s));
162
+ }
163
+ function supportsTemplateOnlyHmr(output) {
164
+ return /(?:^|\n)(?:_sfc_main|__sfc__)\.render\s*=\s*render\b/m.test(output);
165
+ }
166
+ function generateScopeId(filename) {
167
+ return createHash("sha256").update(filename).digest("hex").slice(0, 8);
168
+ }
169
+ function createFilter(include, exclude) {
170
+ const includePatterns = include ? Array.isArray(include) ? include : [include] : [/\.vue$/];
171
+ const excludePatterns = exclude ? Array.isArray(exclude) ? exclude : [exclude] : [/node_modules/];
172
+ return (id) => {
173
+ const matchInclude = includePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
174
+ const matchExclude = excludePatterns.some((pattern) => typeof pattern === "string" ? id.includes(pattern) : pattern.test(id));
175
+ return matchInclude && !matchExclude;
176
+ };
177
+ }
178
+ function generateOutput(compiled, options) {
179
+ const { isProduction, isDev, hmrUpdateType, extractCss, filePath } = options;
180
+ let output = compiled.code;
181
+ const exportDefaultRegex = /^export default /m;
182
+ const hasExportDefault = exportDefaultRegex.test(output);
183
+ const hasNamedRenderExport = /^export function render\b/m.test(output);
184
+ const hasNamedSsrRenderExport = /^export function ssrRender\b/m.test(output);
185
+ const hasSfcMainDefined = /\bconst\s+_sfc_main\s*=/.test(output);
186
+ if (hasExportDefault && !hasSfcMainDefined) {
187
+ output = output.replace(exportDefaultRegex, "const _sfc_main = ");
188
+ if (compiled.hasScoped && compiled.scopeId) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
189
+ output += "\nexport default _sfc_main;";
190
+ } else if (hasExportDefault && hasSfcMainDefined) {
191
+ if (compiled.hasScoped && compiled.scopeId) output = output.replace(/^export default _sfc_main/m, `_sfc_main.__scopeId = "data-v-${compiled.scopeId}";\nexport default _sfc_main`);
192
+ } else if (!hasExportDefault && !hasSfcMainDefined && hasNamedRenderExport) {
193
+ output += "\nconst _sfc_main = {};";
194
+ if (compiled.hasScoped && compiled.scopeId) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
195
+ output += "\n_sfc_main.render = render;";
196
+ output += "\nexport default _sfc_main;";
197
+ } else if (!hasExportDefault && !hasSfcMainDefined && hasNamedSsrRenderExport) {
198
+ output += "\nconst _sfc_main = {};";
199
+ if (compiled.hasScoped && compiled.scopeId) output += `\n_sfc_main.__scopeId = "data-v-${compiled.scopeId}";`;
200
+ output += "\n_sfc_main.ssrRender = ssrRender;";
201
+ output += "\nexport default _sfc_main;";
202
+ }
203
+ if (hasDelegatedStyles(compiled) && filePath) {
204
+ const styleImports = [];
205
+ const cssModuleImports = [];
206
+ for (const block of compiled.styles) {
207
+ const lang = block.lang ?? "css";
208
+ const params = new URLSearchParams();
209
+ params.set("vue", "");
210
+ params.set("type", "style");
211
+ params.set("index", String(block.index));
212
+ if (block.scoped) params.set("scoped", `data-v-${compiled.scopeId}`);
213
+ params.set("lang", lang);
214
+ if (isCssModule(block)) {
215
+ const bindingName = typeof block.module === "string" ? block.module : "$style";
216
+ params.set("module", typeof block.module === "string" ? block.module : "");
217
+ const importUrl = `${filePath}?${params.toString()}`;
218
+ cssModuleImports.push(`import ${bindingName} from ${JSON.stringify(importUrl)};`);
219
+ } else {
220
+ const importUrl = `${filePath}?${params.toString()}`;
221
+ styleImports.push(`import ${JSON.stringify(importUrl)};`);
222
+ }
223
+ }
224
+ const allImports = [...styleImports, ...cssModuleImports].join("\n");
225
+ if (allImports) output = allImports + "\n" + output;
226
+ if (cssModuleImports.length > 0) {
227
+ const moduleBindings = [];
228
+ for (const block of compiled.styles) if (isCssModule(block)) {
229
+ const bindingName = typeof block.module === "string" ? block.module : "$style";
230
+ moduleBindings.push({
231
+ name: bindingName,
232
+ bindingName
233
+ });
234
+ }
235
+ const cssModuleSetup = moduleBindings.map((m) => `_sfc_main.__cssModules = _sfc_main.__cssModules || {};\n_sfc_main.__cssModules[${JSON.stringify(m.name)}] = ${m.bindingName};`).join("\n");
236
+ output = output.replace(/^export default _sfc_main;/m, `${cssModuleSetup}\nexport default _sfc_main;`);
237
+ }
238
+ } else if (compiled.css && !(isProduction && extractCss)) output = `
239
+ export const __vize_css__ = ${JSON.stringify(compiled.css)};
240
+ const __vize_css_id__ = ${JSON.stringify(`vize-style-${compiled.scopeId}`)};
241
+ (function() {
242
+ if (typeof document !== 'undefined') {
243
+ let style = document.getElementById(__vize_css_id__);
244
+ if (!style) {
245
+ style = document.createElement('style');
246
+ style.id = __vize_css_id__;
247
+ style.textContent = __vize_css__;
248
+ document.head.appendChild(style);
249
+ } else {
250
+ style.textContent = __vize_css__;
251
+ }
252
+ }
253
+ })();
254
+ ${output}`;
255
+ if (!isProduction && isDev && hasExportDefault) {
256
+ const effectiveHmrUpdateType = hmrUpdateType === "template-only" && !supportsTemplateOnlyHmr(output) ? "full-reload" : hmrUpdateType ?? "full-reload";
257
+ output += generateHmrCode(compiled.scopeId, effectiveHmrUpdateType);
258
+ }
259
+ return output;
260
+ }
261
+ const VIZE_SSR_PREFIX = "\0vize-ssr:";
262
+ const RESOLVED_CSS_MODULE = "\0vize:all-styles.css";
263
+ /** Check if a module ID is a vize-compiled virtual module */
264
+ function isVizeVirtual(id) {
265
+ const pathPart = id.startsWith("\0vize-ssr:") ? id.slice(10) : id.slice(1);
266
+ return id.startsWith("\0") && pathPart.endsWith(".vue.ts");
267
+ }
268
+ function isVizeSsrVirtual(id) {
269
+ return id.startsWith(VIZE_SSR_PREFIX);
270
+ }
271
+ /** Create a virtual module ID from a real .vue file path */
272
+ function toVirtualId(realPath, ssr = false) {
273
+ return ssr ? `${VIZE_SSR_PREFIX}${realPath}.ts` : "\0" + realPath + ".ts";
274
+ }
275
+ /** Extract the real .vue file path from a virtual module ID */
276
+ function fromVirtualId(virtualId) {
277
+ const prefix = isVizeSsrVirtual(virtualId) ? 10 : 1;
278
+ return virtualId.slice(prefix, -3);
279
+ }
280
+ function escapeRegExp(value) {
281
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
282
+ }
283
+ function toBrowserImportPrefix(replacement) {
284
+ const normalized = replacement.replace(/\\/g, "/");
285
+ if (normalized.startsWith("/@fs/")) return normalized;
286
+ if (path.isAbsolute(replacement) && fs.existsSync(replacement)) return `/@fs${normalized}`;
287
+ return normalized;
288
+ }
289
+ function normalizeFsIdForBuild(id) {
290
+ const [pathPart, queryPart] = id.split("?");
291
+ if (!pathPart.startsWith("/@fs/")) return id;
292
+ const normalizedPath = pathPart.slice(4);
293
+ return queryPart ? `${normalizedPath}?${queryPart}` : normalizedPath;
294
+ }
295
+ function rewriteDynamicTemplateImports(code, aliasRules) {
296
+ let rewritten = code;
297
+ for (const rule of aliasRules) {
298
+ const pattern = new RegExp(`\\bimport\\s*\\(\\s*\`${escapeRegExp(rule.fromPrefix)}`, "g");
299
+ rewritten = rewritten.replace(pattern, `import(/* @vite-ignore */ \`${rule.toPrefix}`);
300
+ }
301
+ rewritten = rewritten.replace(/\bimport\s*\(\s*`/g, "import(/* @vite-ignore */ `");
302
+ return rewritten;
303
+ }
304
+ //#endregion
305
+ //#region src/transform.ts
306
+ /**
307
+ * Code transformation utilities for Vize.
308
+ *
309
+ * Handles static asset URL rewriting, Vite define replacements, and
310
+ * provides the debug logger.
311
+ */
312
+ /**
313
+ * Rewrite static asset URLs in compiled template output.
314
+ *
315
+ * Transforms property values like `src: "@/assets/logo.svg"` into import
316
+ * statements hoisted to the top of the module, so Vite's module resolution
317
+ * pipeline handles alias expansion and asset hashing in both dev and build.
318
+ */
319
+ const SCRIPT_EXTENSIONS = /\.(js|mjs|cjs|ts|mts|cts|jsx|tsx)$/i;
320
+ function rewriteStaticAssetUrls(code, aliasRules) {
321
+ let rewritten = code;
322
+ const imports = [];
323
+ let counter = 0;
324
+ for (const rule of aliasRules) {
325
+ const pattern = new RegExp(`("?src"?\\s*:\\s*)(?:"(${escapeRegExp(rule.fromPrefix)}[^"]+)"|'(${escapeRegExp(rule.fromPrefix)}[^']+)')`, "g");
326
+ rewritten = rewritten.replace(pattern, (match, prefix, dqPath, sqPath) => {
327
+ const fullPath = dqPath || sqPath;
328
+ if (fullPath && SCRIPT_EXTENSIONS.test(fullPath)) return match;
329
+ const varName = `__vize_static_${counter++}`;
330
+ imports.push(`import ${varName} from ${JSON.stringify(fullPath)};`);
331
+ return `${prefix}${varName}`;
332
+ });
333
+ }
334
+ if (imports.length > 0) rewritten = imports.join("\n") + "\n" + rewritten;
335
+ return rewritten;
336
+ }
337
+ /**
338
+ * Built-in Vite/Vue/Nuxt define keys that are handled by Vite's own transform pipeline.
339
+ * These must NOT be replaced by the vize plugin because:
340
+ * 1. Nuxt runs both client and server Vite builds, each with different values
341
+ * (e.g., import.meta.server = true on server, false on client).
342
+ * 2. Vite's import.meta transform already handles these correctly per-environment.
343
+ */
344
+ const BUILTIN_DEFINE_PREFIXES = [
345
+ "import.meta.server",
346
+ "import.meta.client",
347
+ "import.meta.dev",
348
+ "import.meta.test",
349
+ "import.meta.prerender",
350
+ "import.meta.env",
351
+ "import.meta.hot",
352
+ "__VUE_",
353
+ "__NUXT_",
354
+ "process.env"
355
+ ];
356
+ function isBuiltinDefine(key) {
357
+ return BUILTIN_DEFINE_PREFIXES.some((prefix) => key === prefix || key.startsWith(prefix + ".") || key.startsWith(prefix + "_"));
358
+ }
359
+ /**
360
+ * Apply Vite define replacements to code.
361
+ * Replaces keys like `import.meta.vfFeatures.photoSection` with their values.
362
+ * Uses word-boundary-aware matching to avoid replacing inside strings or partial matches.
363
+ */
364
+ function applyDefineReplacements(code, defines) {
365
+ const sortedKeys = Object.keys(defines).sort((a, b) => b.length - a.length);
366
+ let result = code;
367
+ for (const key of sortedKeys) {
368
+ if (!result.includes(key)) continue;
369
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
370
+ const re = new RegExp(escaped + "(?![\\w$.])", "g");
371
+ result = result.replace(re, defines[key]);
372
+ }
373
+ return result;
374
+ }
375
+ function createLogger(debug) {
376
+ return {
377
+ log: (...args) => debug && console.log("[vize]", ...args),
378
+ info: (...args) => console.log("[vize]", ...args),
379
+ warn: (...args) => console.warn("[vize]", ...args),
380
+ error: (...args) => console.error("[vize]", ...args)
381
+ };
382
+ }
383
+ [...CONFIG_FILE_NAMES];
384
+ /**
385
+ * Shared config store for inter-plugin communication.
386
+ * Key = project root, Value = resolved VizeConfig.
387
+ * Used by musea() and other plugins to access the unified config.
388
+ */
389
+ const vizeConfigStore = /* @__PURE__ */ new Map();
390
+ //#endregion
391
+ //#region src/compile-options.ts
392
+ function buildCompileFileOptions(filePath, source, options) {
393
+ const scopeId = /<style[^>]*\bscoped\b/.test(source) ? `data-v-${generateScopeId(filePath)}` : void 0;
394
+ return {
395
+ filename: filePath,
396
+ sourceMap: options.sourceMap,
397
+ ssr: options.ssr,
398
+ vapor: options.vapor,
399
+ scopeId
400
+ };
401
+ }
402
+ function buildCompileBatchOptions(options) {
403
+ return {
404
+ ssr: options.ssr,
405
+ vapor: options.vapor
406
+ };
407
+ }
408
+ //#endregion
409
+ //#region src/compiler.ts
410
+ const { compileSfc, compileSfcBatchWithResults } = native;
411
+ /**
412
+ * Extract style block metadata from a Vue SFC source string.
413
+ * Parses `<style>` tags to determine lang, scoped, and module attributes.
414
+ */
415
+ function extractStyleBlocks(source) {
416
+ const blocks = [];
417
+ const styleRegex = /<style([^>]*)>([\s\S]*?)<\/style>/gi;
418
+ let match;
419
+ let index = 0;
420
+ while ((match = styleRegex.exec(source)) !== null) {
421
+ const attrs = match[1];
422
+ const content = match[2];
423
+ const lang = attrs.match(/\blang=["']([^"']+)["']/)?.[1] ?? null;
424
+ const scoped = /\bscoped\b/.test(attrs);
425
+ const moduleMatch = attrs.match(/\bmodule(?:=["']([^"']+)["'])?/);
426
+ const isModule = moduleMatch ? moduleMatch[1] || true : false;
427
+ blocks.push({
428
+ content,
429
+ lang,
430
+ scoped,
431
+ module: isModule,
432
+ index
433
+ });
434
+ index++;
435
+ }
436
+ return blocks;
437
+ }
438
+ function compileFile(filePath, cache, options, source) {
439
+ const content = source ?? fs.readFileSync(filePath, "utf-8");
440
+ const scopeId = generateScopeId(filePath);
441
+ const hasScoped = /<style[^>]*\bscoped\b/.test(content);
442
+ const result = compileSfc(content, buildCompileFileOptions(filePath, content, options));
443
+ if (result.errors.length > 0) {
444
+ const errorMsg = result.errors.join("\n");
445
+ console.error(`[vize] Compilation error in ${filePath}:\n${errorMsg}`);
446
+ }
447
+ if (result.warnings.length > 0) result.warnings.forEach((warning) => {
448
+ console.warn(`[vize] Warning in ${filePath}: ${warning}`);
449
+ });
450
+ const styles = extractStyleBlocks(content);
451
+ const compiled = {
452
+ code: result.code,
453
+ css: result.css,
454
+ scopeId,
455
+ hasScoped,
456
+ templateHash: result.templateHash,
457
+ styleHash: result.styleHash,
458
+ scriptHash: result.scriptHash,
459
+ styles
460
+ };
461
+ cache.set(filePath, compiled);
462
+ return compiled;
463
+ }
464
+ /**
465
+ * Batch compile multiple files in parallel using native Rust multithreading.
466
+ * Returns per-file results with content hashes for HMR.
467
+ */
468
+ function compileBatch(files, cache, options) {
469
+ const result = compileSfcBatchWithResults(files.map((f) => ({
470
+ path: f.path,
471
+ source: f.source
472
+ })), buildCompileBatchOptions(options));
473
+ const sourceMap = /* @__PURE__ */ new Map();
474
+ for (const f of files) sourceMap.set(f.path, f.source);
475
+ for (const fileResult of result.results) {
476
+ if (fileResult.errors.length === 0) {
477
+ const source = sourceMap.get(fileResult.path);
478
+ const styles = source ? extractStyleBlocks(source) : void 0;
479
+ cache.set(fileResult.path, {
480
+ code: fileResult.code,
481
+ css: fileResult.css,
482
+ scopeId: fileResult.scopeId,
483
+ hasScoped: fileResult.hasScoped,
484
+ templateHash: fileResult.templateHash,
485
+ styleHash: fileResult.styleHash,
486
+ scriptHash: fileResult.scriptHash,
487
+ styles
488
+ });
489
+ }
490
+ if (fileResult.errors.length > 0) console.error(`[vize] Compilation error in ${fileResult.path}:\n${fileResult.errors.join("\n")}`);
491
+ if (fileResult.warnings.length > 0) fileResult.warnings.forEach((warning) => {
492
+ console.warn(`[vize] Warning in ${fileResult.path}: ${warning}`);
493
+ });
494
+ }
495
+ return result;
496
+ }
497
+ //#endregion
498
+ //#region src/plugin/state.ts
499
+ function hasFileMetadataChanged(previous, next) {
500
+ return previous === void 0 || previous.mtimeMs !== next.mtimeMs || previous.size !== next.size;
501
+ }
502
+ function diffPrecompileFiles(files, currentMetadata, previousMetadata) {
503
+ const changedFiles = [];
504
+ const seenFiles = new Set(files);
505
+ for (const file of files) {
506
+ const metadata = currentMetadata.get(file);
507
+ if (!metadata || hasFileMetadataChanged(previousMetadata.get(file), metadata)) changedFiles.push(file);
508
+ }
509
+ const deletedFiles = [];
510
+ for (const file of previousMetadata.keys()) if (!seenFiles.has(file)) deletedFiles.push(file);
511
+ return {
512
+ changedFiles,
513
+ deletedFiles
514
+ };
515
+ }
516
+ function getEnvironmentCache(state, ssr) {
517
+ return ssr ? state.ssrCache : state.cache;
518
+ }
519
+ function getCompileOptionsForRequest(state, ssr) {
520
+ return {
521
+ sourceMap: state.mergedOptions?.sourceMap ?? !state.isProduction,
522
+ ssr,
523
+ vapor: !ssr && (state.mergedOptions?.vapor ?? false)
524
+ };
525
+ }
526
+ /**
527
+ * Pre-compile all Vue files matching scan patterns.
528
+ */
529
+ async function compileAll(state) {
530
+ const startTime = performance.now();
531
+ const files = await glob(state.scanPatterns, {
532
+ cwd: state.root,
533
+ ignore: state.ignorePatterns,
534
+ absolute: true
535
+ });
536
+ const currentMetadata = /* @__PURE__ */ new Map();
537
+ for (const file of files) try {
538
+ const stat = fs.statSync(file);
539
+ currentMetadata.set(file, {
540
+ mtimeMs: stat.mtimeMs,
541
+ size: stat.size
542
+ });
543
+ } catch (e) {
544
+ state.logger.error(`Failed to stat ${file}:`, e);
545
+ }
546
+ const { changedFiles, deletedFiles } = diffPrecompileFiles(files, currentMetadata, state.precompileMetadata);
547
+ const cachedFileCount = files.length - changedFiles.length;
548
+ for (const file of deletedFiles) {
549
+ state.cache.delete(file);
550
+ state.ssrCache.delete(file);
551
+ state.collectedCss.delete(file);
552
+ state.precompileMetadata.delete(file);
553
+ state.pendingHmrUpdateTypes.delete(file);
554
+ }
555
+ state.logger.info(`Pre-compiling ${files.length} Vue files... (${changedFiles.length} changed, ${cachedFileCount} cached, ${deletedFiles.length} removed)`);
556
+ if (changedFiles.length === 0) {
557
+ const elapsed = (performance.now() - startTime).toFixed(2);
558
+ state.logger.info(`Pre-compilation complete: cache reused (${elapsed}ms)`);
559
+ return;
560
+ }
561
+ const fileContents = [];
562
+ for (const file of changedFiles) try {
563
+ const source = fs.readFileSync(file, "utf-8");
564
+ fileContents.push({
565
+ path: file,
566
+ source
567
+ });
568
+ } catch (e) {
569
+ state.logger.error(`Failed to read ${file}:`, e);
570
+ }
571
+ const result = compileBatch(fileContents, state.cache, {
572
+ ssr: false,
573
+ vapor: state.mergedOptions.vapor ?? false
574
+ });
575
+ for (const file of changedFiles) {
576
+ state.collectedCss.delete(file);
577
+ state.pendingHmrUpdateTypes.delete(file);
578
+ }
579
+ for (const fileResult of result.results) {
580
+ const metadata = currentMetadata.get(fileResult.path);
581
+ if (fileResult.errors.length > 0) {
582
+ state.cache.delete(fileResult.path);
583
+ state.collectedCss.delete(fileResult.path);
584
+ state.precompileMetadata.delete(fileResult.path);
585
+ continue;
586
+ }
587
+ if (metadata) state.precompileMetadata.set(fileResult.path, metadata);
588
+ if (state.isProduction && fileResult.css) {
589
+ const cached = state.cache.get(fileResult.path);
590
+ if (cached && !hasDelegatedStyles(cached)) state.collectedCss.set(fileResult.path, resolveCssImports(fileResult.css, fileResult.path, state.cssAliasRules, false));
591
+ }
592
+ }
593
+ const elapsed = (performance.now() - startTime).toFixed(2);
594
+ state.logger.info(`Pre-compilation complete: ${result.successCount} recompiled, ${cachedFileCount} reused, ${result.failedCount} failed (${elapsed}ms, native batch: ${result.timeMs.toFixed(2)}ms)`);
595
+ }
596
+ //#endregion
597
+ //#region src/plugin/resolve.ts
598
+ function resolveVuePath(state, id, importer) {
599
+ let resolved;
600
+ if (id.startsWith("/@fs/")) resolved = id.slice(4);
601
+ else if (id.startsWith("/") && !fs.existsSync(id)) resolved = path.resolve(state.root, id.slice(1));
602
+ else if (path.isAbsolute(id)) resolved = id;
603
+ else if (importer) {
604
+ const realImporter = isVizeVirtual(importer) ? fromVirtualId(importer) : importer;
605
+ resolved = path.resolve(path.dirname(realImporter), id);
606
+ } else resolved = path.resolve(state.root, id);
607
+ if (!path.isAbsolute(resolved)) resolved = path.resolve(state.root, resolved);
608
+ return path.normalize(resolved);
609
+ }
610
+ function normalizeRequireBase(importer) {
611
+ if (!importer) return null;
612
+ let normalized = importer;
613
+ if (isVizeVirtual(normalized)) normalized = fromVirtualId(normalized);
614
+ else if (normalized.startsWith("\0") && normalized.endsWith("?macro=true")) normalized = normalized.slice(1).replace("?macro=true", "");
615
+ return normalized.split("?")[0] ?? null;
616
+ }
617
+ function resolveBareImportWithNode(state, id, importer) {
618
+ const [request, queryPart] = id.split("?");
619
+ const querySuffix = queryPart ? `?${queryPart}` : "";
620
+ const candidates = [normalizeRequireBase(importer), path.join(state.root, "package.json")].filter((candidate) => candidate != null);
621
+ const seen = /* @__PURE__ */ new Set();
622
+ for (const candidate of candidates) {
623
+ if (seen.has(candidate)) continue;
624
+ seen.add(candidate);
625
+ try {
626
+ return `${createRequire(candidate).resolve(request)}${querySuffix}`;
627
+ } catch {}
628
+ }
629
+ return null;
630
+ }
631
+ async function resolveIdHook(ctx, state, id, importer, options) {
632
+ const isBuild = state.server === null;
633
+ const isSsrRequest = !!options?.ssr || (importer ? isVizeSsrVirtual(importer) : false);
634
+ if (id.startsWith("\0")) {
635
+ if (isVizeVirtual(id)) {
636
+ if (isSsrRequest && !isVizeSsrVirtual(id)) return toVirtualId(fromVirtualId(id), true);
637
+ return null;
638
+ }
639
+ if (id.startsWith("\0vize:")) {
640
+ const rawPath = id.slice(6);
641
+ const cleanPath = rawPath.endsWith(".ts") ? rawPath.slice(0, -3) : rawPath;
642
+ if (!cleanPath.endsWith(".vue")) {
643
+ state.logger.log(`resolveId: redirecting legacy virtual ID to ${cleanPath}`);
644
+ return cleanPath;
645
+ }
646
+ }
647
+ const cleanPath = id.slice(1);
648
+ if (cleanPath.startsWith("/") && !cleanPath.endsWith(".vue.ts")) {
649
+ const [pathPart, queryPart] = cleanPath.split("?");
650
+ const querySuffix = queryPart ? `?${queryPart}` : "";
651
+ state.logger.log(`resolveId: redirecting \0-prefixed non-vue ID to ${pathPart}${querySuffix}`);
652
+ const redirected = pathPart + querySuffix;
653
+ return isBuild ? normalizeFsIdForBuild(redirected) : redirected;
654
+ }
655
+ return null;
656
+ }
657
+ if (id.startsWith("vize:")) {
658
+ let realPath = id.slice(5);
659
+ if (realPath.endsWith(".ts")) realPath = realPath.slice(0, -3);
660
+ state.logger.log(`resolveId: redirecting stale vize: ID to ${realPath}`);
661
+ const resolved = await ctx.resolve(realPath, importer, { skipSelf: true });
662
+ if (resolved && isBuild && resolved.id.startsWith("/@fs/")) return {
663
+ ...resolved,
664
+ id: normalizeFsIdForBuild(resolved.id)
665
+ };
666
+ return resolved;
667
+ }
668
+ if (id === "virtual:vize-styles") return RESOLVED_CSS_MODULE;
669
+ if (isBuild && id.startsWith("/@fs/")) return normalizeFsIdForBuild(id);
670
+ if (id.includes("?macro=true")) {
671
+ const filePath = id.split("?")[0];
672
+ const resolved = resolveVuePath(state, filePath, importer);
673
+ if (resolved && fs.existsSync(resolved)) return `\0${resolved}?macro=true`;
674
+ }
675
+ if (id.includes("?vue&type=style") || id.includes("?vue=&type=style")) {
676
+ const params = new URLSearchParams(id.split("?")[1]);
677
+ const lang = params.get("lang") || "css";
678
+ if (params.has("module")) return `\0${id}.module.${lang}`;
679
+ return `\0${id}.${lang}`;
680
+ }
681
+ const isMacroImporter = importer?.startsWith("\0") && importer?.endsWith("?macro=true");
682
+ if (importer && (isVizeVirtual(importer) || isMacroImporter)) {
683
+ const cleanImporter = isMacroImporter ? importer.slice(1).replace("?macro=true", "") : fromVirtualId(importer);
684
+ state.logger.log(`resolveId from virtual: id=${id}, cleanImporter=${cleanImporter}`);
685
+ if (id.startsWith("#")) try {
686
+ return await ctx.resolve(id, cleanImporter, { skipSelf: true });
687
+ } catch {
688
+ return null;
689
+ }
690
+ if (!id.endsWith(".vue")) {
691
+ if (!id.startsWith("./") && !id.startsWith("../") && !id.startsWith("/")) {
692
+ if (!state.cssAliasRules.some((rule) => id === rule.find || id.startsWith(rule.find + "/"))) {
693
+ try {
694
+ const resolved = await ctx.resolve(id, cleanImporter, { skipSelf: true });
695
+ if (resolved) {
696
+ state.logger.log(`resolveId: resolved bare ${id} to ${resolved.id} via Vite resolver`);
697
+ if (isBuild && resolved.id.startsWith("/@fs/")) return {
698
+ ...resolved,
699
+ id: normalizeFsIdForBuild(resolved.id)
700
+ };
701
+ return resolved;
702
+ }
703
+ } catch {}
704
+ const nodeResolved = resolveBareImportWithNode(state, id, cleanImporter);
705
+ if (nodeResolved) {
706
+ state.logger.log(`resolveId: resolved bare ${id} to ${nodeResolved} via Node fallback`);
707
+ return nodeResolved;
708
+ }
709
+ }
710
+ return null;
711
+ }
712
+ try {
713
+ const resolved = await ctx.resolve(id, cleanImporter, { skipSelf: true });
714
+ if (resolved) {
715
+ state.logger.log(`resolveId: resolved ${id} to ${resolved.id} via Vite resolver`);
716
+ if (isBuild && resolved.id.startsWith("/@fs/")) return {
717
+ ...resolved,
718
+ id: normalizeFsIdForBuild(resolved.id)
719
+ };
720
+ return resolved;
721
+ }
722
+ } catch {}
723
+ if (id.startsWith("./") || id.startsWith("../")) {
724
+ const [pathPart, queryPart] = id.split("?");
725
+ const querySuffix = queryPart ? `?${queryPart}` : "";
726
+ const resolved = path.resolve(path.dirname(cleanImporter), pathPart);
727
+ for (const ext of [
728
+ "",
729
+ ".ts",
730
+ ".tsx",
731
+ ".js",
732
+ ".jsx",
733
+ ".json"
734
+ ]) {
735
+ const candidate = resolved + ext;
736
+ if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
737
+ const finalPath = candidate + querySuffix;
738
+ state.logger.log(`resolveId: resolved relative ${id} to ${finalPath}`);
739
+ return finalPath;
740
+ }
741
+ }
742
+ if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) for (const indexFile of [
743
+ "/index.ts",
744
+ "/index.tsx",
745
+ "/index.js",
746
+ "/index.jsx"
747
+ ]) {
748
+ const candidate = resolved + indexFile;
749
+ if (fs.existsSync(candidate)) {
750
+ const finalPath = candidate + querySuffix;
751
+ state.logger.log(`resolveId: resolved directory ${id} to ${finalPath}`);
752
+ return finalPath;
753
+ }
754
+ }
755
+ }
756
+ return null;
757
+ }
758
+ }
759
+ if (id.endsWith(".vue")) {
760
+ const handleNodeModules = state.initialized ? state.mergedOptions.handleNodeModulesVue ?? true : true;
761
+ if (!handleNodeModules && id.includes("node_modules")) {
762
+ state.logger.log(`resolveId: skipping node_modules import ${id}`);
763
+ return null;
764
+ }
765
+ const resolved = resolveVuePath(state, id, importer);
766
+ const isNodeModulesPath = resolved.includes("node_modules");
767
+ if (!handleNodeModules && isNodeModulesPath) {
768
+ state.logger.log(`resolveId: skipping node_modules path ${resolved}`);
769
+ return null;
770
+ }
771
+ if (state.filter && !isNodeModulesPath && !state.filter(resolved)) {
772
+ state.logger.log(`resolveId: skipping filtered path ${resolved}`);
773
+ return null;
774
+ }
775
+ const hasCache = state.cache.has(resolved);
776
+ const fileExists = fs.existsSync(resolved);
777
+ state.logger.log(`resolveId: id=${id}, resolved=${resolved}, hasCache=${hasCache}, fileExists=${fileExists}, importer=${importer ?? "none"}`);
778
+ if (hasCache || fileExists) return toVirtualId(resolved, isSsrRequest);
779
+ if (!fileExists && !path.isAbsolute(id)) {
780
+ const viteResolved = await ctx.resolve(id, importer, { skipSelf: true });
781
+ if (viteResolved && viteResolved.id.endsWith(".vue")) {
782
+ const realPath = viteResolved.id;
783
+ if ((realPath.includes("node_modules") ? handleNodeModules : state.filter(realPath)) && (state.cache.has(realPath) || fs.existsSync(realPath))) {
784
+ state.logger.log(`resolveId: resolved via Vite fallback ${id} to ${realPath}`);
785
+ return toVirtualId(realPath, isSsrRequest);
786
+ }
787
+ }
788
+ }
789
+ }
790
+ return null;
791
+ }
792
+ //#endregion
793
+ //#region src/plugin/load.ts
794
+ const SERVER_PLACEHOLDER_CODE = `import { createElementBlock, defineComponent } from "vue";
795
+ export default defineComponent({
796
+ name: "ServerPlaceholder",
797
+ render() {
798
+ return createElementBlock("div");
799
+ }
800
+ });
801
+ `;
802
+ function getBoundaryPlaceholderCode(realPath, ssr) {
803
+ if (ssr && realPath.endsWith(".client.vue")) return SERVER_PLACEHOLDER_CODE;
804
+ if (!ssr && realPath.endsWith(".server.vue")) return SERVER_PLACEHOLDER_CODE;
805
+ return null;
806
+ }
807
+ function getOxcDumpPath(root, realPath) {
808
+ const dumpDir = path.resolve(root || process.cwd(), "__agent_only", "oxc-dumps");
809
+ fs.mkdirSync(dumpDir, { recursive: true });
810
+ return path.join(dumpDir, `vize-oxc-error-${path.basename(realPath)}.ts`);
811
+ }
812
+ function loadHook(state, id, loadOptions) {
813
+ const currentBase = loadOptions?.ssr ? state.serverViteBase : state.clientViteBase;
814
+ if (id === "\0vize:all-styles.css") return Array.from(state.collectedCss.values()).join("\n\n");
815
+ let styleId = id;
816
+ if (id.startsWith("\0") && id.includes("?vue")) styleId = id.slice(1).replace(/\.module\.\w+$/, "").replace(/\.\w+$/, "");
817
+ if (styleId.includes("?vue&type=style") || styleId.includes("?vue=&type=style")) {
818
+ const [filename, queryString] = styleId.split("?");
819
+ const realPath = isVizeVirtual(filename) ? fromVirtualId(filename) : filename;
820
+ const params = new URLSearchParams(queryString);
821
+ const indexStr = params.get("index");
822
+ const lang = params.get("lang");
823
+ params.has("module");
824
+ const scoped = params.get("scoped");
825
+ const fallbackCompiled = state.cache.get(realPath) ?? state.ssrCache.get(realPath);
826
+ const blockIndex = indexStr !== null ? parseInt(indexStr, 10) : -1;
827
+ if (fallbackCompiled?.styles && blockIndex >= 0 && blockIndex < fallbackCompiled.styles.length) {
828
+ const block = fallbackCompiled.styles[blockIndex];
829
+ let styleContent = block.content;
830
+ if (scoped && block.scoped && lang && lang !== "css") {
831
+ const lines = styleContent.split("\n");
832
+ const hoisted = [];
833
+ const body = [];
834
+ for (const line of lines) {
835
+ const trimmed = line.trimStart();
836
+ if (trimmed.startsWith("@use ") || trimmed.startsWith("@forward ") || trimmed.startsWith("@import ")) hoisted.push(line);
837
+ else body.push(line);
838
+ }
839
+ const bodyContent = body.join("\n");
840
+ styleContent = `${hoisted.length > 0 ? hoisted.join("\n") + "\n\n" : ""}[${scoped}] {\n${bodyContent}\n}`;
841
+ }
842
+ return {
843
+ code: styleContent,
844
+ map: null
845
+ };
846
+ }
847
+ if (fallbackCompiled?.css) return resolveCssImports(fallbackCompiled.css, realPath, state.cssAliasRules, state.server !== null, currentBase);
848
+ return "";
849
+ }
850
+ if (id.startsWith("\0") && id.endsWith("?macro=true")) {
851
+ const realPath = id.slice(1).replace("?macro=true", "");
852
+ if (fs.existsSync(realPath)) {
853
+ const setupMatch = fs.readFileSync(realPath, "utf-8").match(/<script\s+setup[^>]*>([\s\S]*?)<\/script>/);
854
+ if (setupMatch) return {
855
+ code: `${setupMatch[1]}\nexport default {}`,
856
+ map: null
857
+ };
858
+ }
859
+ return {
860
+ code: "export default {}",
861
+ map: null
862
+ };
863
+ }
864
+ if (isVizeVirtual(id)) {
865
+ const realPath = fromVirtualId(id);
866
+ const isSsr = isVizeSsrVirtual(id) || !!loadOptions?.ssr;
867
+ if (!realPath.endsWith(".vue")) {
868
+ state.logger.log(`load: skipping non-vue virtual module ${realPath}`);
869
+ return null;
870
+ }
871
+ const placeholderCode = getBoundaryPlaceholderCode(realPath, !!loadOptions?.ssr);
872
+ if (placeholderCode) {
873
+ state.logger.log(`load: using boundary placeholder for ${realPath}`);
874
+ return {
875
+ code: placeholderCode,
876
+ map: null
877
+ };
878
+ }
879
+ const cache = getEnvironmentCache(state, isSsr);
880
+ let compiled = cache.get(realPath);
881
+ if (!compiled && fs.existsSync(realPath)) {
882
+ state.logger.log(`load: on-demand compiling ${realPath}`);
883
+ compiled = compileFile(realPath, cache, getCompileOptionsForRequest(state, isSsr));
884
+ }
885
+ if (compiled) {
886
+ const hasDelegated = hasDelegatedStyles(compiled);
887
+ const pendingHmrUpdateType = loadOptions?.ssr ? void 0 : state.pendingHmrUpdateTypes.get(realPath);
888
+ if (compiled.css && !hasDelegated) compiled = {
889
+ ...compiled,
890
+ css: resolveCssImports(compiled.css, realPath, state.cssAliasRules, state.server !== null, currentBase)
891
+ };
892
+ const output = rewriteStaticAssetUrls(rewriteDynamicTemplateImports(generateOutput(compiled, {
893
+ isProduction: state.isProduction,
894
+ isDev: state.server !== null && !isSsr,
895
+ hmrUpdateType: pendingHmrUpdateType,
896
+ extractCss: state.extractCss,
897
+ filePath: realPath
898
+ }), state.dynamicImportAliasRules), state.dynamicImportAliasRules);
899
+ if (!loadOptions?.ssr) state.pendingHmrUpdateTypes.delete(realPath);
900
+ return {
901
+ code: output,
902
+ map: null
903
+ };
904
+ }
905
+ }
906
+ if (id.startsWith("\0")) {
907
+ const afterPrefix = id.startsWith("\0vize:") ? id.slice(6) : id.slice(1);
908
+ if (afterPrefix.includes("?commonjs-")) return null;
909
+ const [pathPart, queryPart] = afterPrefix.split("?");
910
+ const querySuffix = queryPart ? `?${queryPart}` : "";
911
+ const fsPath = pathPart.startsWith("/@fs/") ? pathPart.slice(4) : pathPart;
912
+ if (fsPath.startsWith("/") && fs.existsSync(fsPath) && fs.statSync(fsPath).isFile()) {
913
+ const importPath = state.server === null ? `${pathToFileURL(fsPath).href}${querySuffix}` : "/@fs" + fsPath + querySuffix;
914
+ state.logger.log(`load: proxying \0-prefixed file ${id} -> re-export from ${importPath}`);
915
+ return `export { default } from ${JSON.stringify(importPath)};\nexport * from ${JSON.stringify(importPath)};`;
916
+ }
917
+ }
918
+ return null;
919
+ }
920
+ async function transformHook(state, code, id, options) {
921
+ const isMacro = id.startsWith("\0") && id.endsWith("?macro=true");
922
+ if (isVizeVirtual(id) || isMacro) {
923
+ const realPath = isMacro ? id.slice(1).replace("?macro=true", "") : fromVirtualId(id);
924
+ try {
925
+ const result = await transformWithOxc(code, realPath, { lang: "ts" });
926
+ const defines = options?.ssr ? state.serverViteDefine : state.clientViteDefine;
927
+ let transformed = result.code;
928
+ if (Object.keys(defines).length > 0) transformed = applyDefineReplacements(transformed, defines);
929
+ return {
930
+ code: transformed,
931
+ map: result.map
932
+ };
933
+ } catch (e) {
934
+ state.logger.error(`transformWithOxc failed for ${realPath}:`, e);
935
+ const dumpPath = getOxcDumpPath(state.root, realPath);
936
+ fs.writeFileSync(dumpPath, code, "utf-8");
937
+ state.logger.error(`Dumped failing code to ${dumpPath}`);
938
+ return {
939
+ code: "export default {}",
940
+ map: null
941
+ };
942
+ }
943
+ }
944
+ return null;
945
+ }
946
+ //#endregion
947
+ //#region src/plugin/hmr.ts
948
+ async function handleHotUpdateHook(state, ctx) {
949
+ const { file, server, read } = ctx;
950
+ if (file.endsWith(".vue") && state.filter(file)) try {
951
+ const source = await read();
952
+ const prevCompiled = state.cache.get(file);
953
+ compileFile(file, state.cache, getCompileOptionsForRequest(state, false), source);
954
+ state.ssrCache.delete(file);
955
+ const newCompiled = state.cache.get(file);
956
+ try {
957
+ const stat = fs.statSync(file);
958
+ state.precompileMetadata.set(file, {
959
+ mtimeMs: stat.mtimeMs,
960
+ size: stat.size
961
+ });
962
+ } catch {
963
+ state.precompileMetadata.delete(file);
964
+ }
965
+ if (!hasHmrChanges(prevCompiled, newCompiled)) {
966
+ state.pendingHmrUpdateTypes.delete(file);
967
+ state.logger.log(`Re-compiled: ${path.relative(state.root, file)} (no-op)`);
968
+ return [];
969
+ }
970
+ const updateType = detectHmrUpdateType(prevCompiled, newCompiled);
971
+ state.logger.log(`Re-compiled: ${path.relative(state.root, file)} (${updateType})`);
972
+ const virtualId = toVirtualId(file);
973
+ const modules = server.moduleGraph.getModulesByFile(virtualId) ?? server.moduleGraph.getModulesByFile(file);
974
+ const hasDelegated = hasDelegatedStyles(newCompiled);
975
+ if (hasDelegated && updateType === "style-only") {
976
+ const affectedModules = /* @__PURE__ */ new Set();
977
+ for (const block of newCompiled.styles ?? []) {
978
+ const params = new URLSearchParams();
979
+ params.set("vue", "");
980
+ params.set("type", "style");
981
+ params.set("index", String(block.index));
982
+ if (block.scoped) params.set("scoped", `data-v-${newCompiled.scopeId}`);
983
+ params.set("lang", block.lang ?? "css");
984
+ if (block.module !== false) params.set("module", typeof block.module === "string" ? block.module : "");
985
+ const styleId = `${file}?${params.toString()}`;
986
+ const styleMods = server.moduleGraph.getModulesByFile(styleId);
987
+ if (styleMods) for (const mod of styleMods) affectedModules.add(mod);
988
+ }
989
+ if (affectedModules.size > 0) return [...affectedModules];
990
+ if (modules) return [...modules];
991
+ return [];
992
+ }
993
+ if (updateType === "style-only" && newCompiled.css && !hasDelegated) {
994
+ state.pendingHmrUpdateTypes.delete(file);
995
+ server.ws.send({
996
+ type: "custom",
997
+ event: "vize:update",
998
+ data: {
999
+ id: newCompiled.scopeId,
1000
+ type: "style-only",
1001
+ css: resolveCssImports(newCompiled.css, file, state.cssAliasRules, true, state.clientViteBase)
1002
+ }
1003
+ });
1004
+ return [];
1005
+ }
1006
+ if (modules) {
1007
+ state.pendingHmrUpdateTypes.set(file, updateType);
1008
+ return [...modules];
1009
+ }
1010
+ state.pendingHmrUpdateTypes.delete(file);
1011
+ } catch (e) {
1012
+ state.logger.error(`Re-compilation failed for ${file}:`, e);
1013
+ }
1014
+ }
1015
+ function handleGenerateBundleHook(state, emitFile) {
1016
+ if (!state.extractCss || state.collectedCss.size === 0) return;
1017
+ const allCss = Array.from(state.collectedCss.values()).join("\n\n");
1018
+ if (allCss.trim()) {
1019
+ emitFile({
1020
+ type: "asset",
1021
+ fileName: "assets/vize-components.css",
1022
+ source: allCss
1023
+ });
1024
+ state.logger.log(`Extracted CSS to assets/vize-components.css (${state.collectedCss.size} components)`);
1025
+ }
1026
+ }
1027
+ //#endregion
1028
+ //#region src/plugin/compat.ts
1029
+ function createVueCompatPlugin(state) {
1030
+ let compilerSfc = null;
1031
+ const loadCompilerSfc = () => {
1032
+ if (!compilerSfc) try {
1033
+ compilerSfc = createRequire(import.meta.url)("@vue/compiler-sfc");
1034
+ } catch {
1035
+ compilerSfc = { parse: () => ({
1036
+ descriptor: {},
1037
+ errors: []
1038
+ }) };
1039
+ }
1040
+ return compilerSfc;
1041
+ };
1042
+ return {
1043
+ name: "vite:vue",
1044
+ api: { get options() {
1045
+ return {
1046
+ compiler: loadCompilerSfc(),
1047
+ isProduction: state.isProduction ?? false,
1048
+ root: state.root ?? process.cwd(),
1049
+ template: {}
1050
+ };
1051
+ } }
1052
+ };
1053
+ }
1054
+ function createPostTransformPlugin(state) {
1055
+ return {
1056
+ name: "vize:post-transform",
1057
+ enforce: "post",
1058
+ async transform(code, id, transformOptions) {
1059
+ if (!id.endsWith(".vue") && !id.endsWith(".vue.ts") && !id.includes("node_modules") && id.endsWith(".setup.ts") && /<script\s+setup[\s>]/.test(code)) {
1060
+ state.logger.log(`post-transform: compiling virtual SFC content from ${id}`);
1061
+ try {
1062
+ const isSsr = !!transformOptions?.ssr;
1063
+ const result = await transformWithOxc(generateOutput(compileFile(id, getEnvironmentCache(state, isSsr), getCompileOptionsForRequest(state, isSsr), code), {
1064
+ isProduction: state.isProduction,
1065
+ isDev: state.server !== null,
1066
+ extractCss: state.extractCss,
1067
+ filePath: id
1068
+ }), id, { lang: "ts" });
1069
+ const defines = transformOptions?.ssr ? state.serverViteDefine : state.clientViteDefine;
1070
+ let transformed = result.code;
1071
+ if (Object.keys(defines).length > 0) transformed = applyDefineReplacements(transformed, defines);
1072
+ return {
1073
+ code: transformed,
1074
+ map: result.map
1075
+ };
1076
+ } catch (e) {
1077
+ state.logger.error(`Virtual SFC compilation failed for ${id}:`, e);
1078
+ }
1079
+ }
1080
+ return null;
1081
+ }
1082
+ };
1083
+ }
1084
+ //#endregion
1085
+ //#region src/plugin/index.ts
1086
+ function vize(options = {}) {
1087
+ const state = {
1088
+ cache: /* @__PURE__ */ new Map(),
1089
+ ssrCache: /* @__PURE__ */ new Map(),
1090
+ collectedCss: /* @__PURE__ */ new Map(),
1091
+ precompileMetadata: /* @__PURE__ */ new Map(),
1092
+ pendingHmrUpdateTypes: /* @__PURE__ */ new Map(),
1093
+ isProduction: false,
1094
+ root: "",
1095
+ clientViteBase: "/",
1096
+ serverViteBase: "/",
1097
+ server: null,
1098
+ filter: () => true,
1099
+ scanPatterns: null,
1100
+ ignorePatterns: [],
1101
+ mergedOptions: options,
1102
+ initialized: false,
1103
+ dynamicImportAliasRules: [],
1104
+ cssAliasRules: [],
1105
+ extractCss: false,
1106
+ clientViteDefine: {},
1107
+ serverViteDefine: {},
1108
+ logger: createLogger(options.debug ?? false)
1109
+ };
1110
+ return [
1111
+ createVueCompatPlugin(state),
1112
+ {
1113
+ name: "vite-plugin-vize",
1114
+ enforce: "pre",
1115
+ config(userConfig, env) {
1116
+ const cssModules = userConfig.css?.modules;
1117
+ if (cssModules && typeof cssModules.generateScopedName === "function") {
1118
+ const origFn = cssModules.generateScopedName;
1119
+ cssModules.generateScopedName = function(name, filename, css) {
1120
+ let clean = filename;
1121
+ const nulIdx = clean.indexOf("\0");
1122
+ if (nulIdx >= 0) clean = clean.slice(nulIdx + 1);
1123
+ clean = clean.replace(/\.module\.\w+$/, "").replace(/\.\w+$/, "");
1124
+ if (clean.includes("?")) clean = clean.split("?")[0];
1125
+ return origFn.call(this, name, clean, css);
1126
+ };
1127
+ }
1128
+ return {
1129
+ define: {
1130
+ __VUE_OPTIONS_API__: true,
1131
+ __VUE_PROD_DEVTOOLS__: env.command === "serve",
1132
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false
1133
+ },
1134
+ optimizeDeps: { exclude: ["virtual:vize-styles"] }
1135
+ };
1136
+ },
1137
+ async configResolved(resolvedConfig) {
1138
+ state.root = options.root ?? resolvedConfig.root;
1139
+ state.isProduction = options.isProduction ?? resolvedConfig.isProduction;
1140
+ const isSsrBuild = !!resolvedConfig.build?.ssr;
1141
+ const currentBase = resolvedConfig.command === "serve" ? options.devUrlBase ?? resolvedConfig.base ?? "/" : resolvedConfig.base ?? "/";
1142
+ if (isSsrBuild) state.serverViteBase = currentBase;
1143
+ else state.clientViteBase = currentBase;
1144
+ state.extractCss = state.isProduction;
1145
+ const isSsr = !!resolvedConfig.build?.ssr;
1146
+ const envDefine = {};
1147
+ if (resolvedConfig.define) for (const [key, value] of Object.entries(resolvedConfig.define)) {
1148
+ if (isBuiltinDefine(key)) continue;
1149
+ if (typeof value === "string") envDefine[key] = value;
1150
+ else envDefine[key] = JSON.stringify(value);
1151
+ }
1152
+ if (isSsr) state.serverViteDefine = envDefine;
1153
+ else state.clientViteDefine = envDefine;
1154
+ const configEnv = {
1155
+ mode: resolvedConfig.mode,
1156
+ command: resolvedConfig.command === "build" ? "build" : "serve",
1157
+ isSsrBuild: !!resolvedConfig.build?.ssr
1158
+ };
1159
+ let fileConfig = null;
1160
+ if (options.configMode !== false) try {
1161
+ fileConfig = await loadConfig(state.root, {
1162
+ mode: options.configMode ?? "root",
1163
+ configFile: options.configFile,
1164
+ env: configEnv
1165
+ });
1166
+ if (fileConfig) {
1167
+ state.logger.log("Loaded config from vize.config file");
1168
+ vizeConfigStore.set(state.root, fileConfig);
1169
+ }
1170
+ } catch (error) {
1171
+ state.logger.warn(`Failed to load vize config from ${options.configFile ?? state.root}:`, error);
1172
+ }
1173
+ const viteConfig = fileConfig?.vite ?? {};
1174
+ const compilerConfig = fileConfig?.compiler ?? {};
1175
+ state.mergedOptions = {
1176
+ ...options,
1177
+ ssr: options.ssr ?? compilerConfig.ssr ?? false,
1178
+ sourceMap: options.sourceMap ?? compilerConfig.sourceMap,
1179
+ vapor: options.vapor ?? compilerConfig.vapor ?? false,
1180
+ include: options.include ?? viteConfig.include,
1181
+ exclude: options.exclude ?? viteConfig.exclude,
1182
+ scanPatterns: options.scanPatterns ?? viteConfig.scanPatterns,
1183
+ ignorePatterns: options.ignorePatterns ?? viteConfig.ignorePatterns
1184
+ };
1185
+ state.dynamicImportAliasRules = [];
1186
+ for (const alias of resolvedConfig.resolve.alias) {
1187
+ if (typeof alias.find !== "string" || typeof alias.replacement !== "string") continue;
1188
+ const fromPrefix = alias.find.endsWith("/") ? alias.find : `${alias.find}/`;
1189
+ const replacement = toBrowserImportPrefix(alias.replacement);
1190
+ const toPrefix = replacement.endsWith("/") ? replacement : `${replacement}/`;
1191
+ state.dynamicImportAliasRules.push({
1192
+ fromPrefix,
1193
+ toPrefix
1194
+ });
1195
+ }
1196
+ state.dynamicImportAliasRules.sort((a, b) => b.fromPrefix.length - a.fromPrefix.length);
1197
+ state.cssAliasRules = [];
1198
+ for (const alias of resolvedConfig.resolve.alias) {
1199
+ if (typeof alias.find !== "string" || typeof alias.replacement !== "string") continue;
1200
+ state.cssAliasRules.push({
1201
+ find: alias.find,
1202
+ replacement: alias.replacement
1203
+ });
1204
+ }
1205
+ state.cssAliasRules.sort((a, b) => b.find.length - a.find.length);
1206
+ state.filter = createFilter(state.mergedOptions.include, state.mergedOptions.exclude);
1207
+ state.scanPatterns = state.mergedOptions.scanPatterns ?? ["**/*.vue"];
1208
+ state.ignorePatterns = state.mergedOptions.ignorePatterns ?? [
1209
+ "node_modules/**",
1210
+ "dist/**",
1211
+ ".git/**"
1212
+ ];
1213
+ state.initialized = true;
1214
+ },
1215
+ configureServer(devServer) {
1216
+ state.server = devServer;
1217
+ devServer.middlewares.use((req, _res, next) => {
1218
+ if (req.url && req.url.includes("__x00__")) {
1219
+ const [urlPath, queryPart] = req.url.split("?");
1220
+ let cleanedPath = urlPath.replace(/__x00__/g, "");
1221
+ cleanedPath = cleanedPath.replace(/^\/@id\/\//, "/@fs/");
1222
+ if (cleanedPath.startsWith("/@fs/")) {
1223
+ const fsPath = cleanedPath.slice(4);
1224
+ if (fsPath.startsWith("/") && fs.existsSync(fsPath) && fs.statSync(fsPath).isFile() && !fsPath.endsWith(".vue.ts")) {
1225
+ const cleaned = queryPart ? `${cleanedPath}?${queryPart}` : cleanedPath;
1226
+ if (cleaned !== req.url) {
1227
+ state.logger.log(`middleware: rewriting ${req.url} -> ${cleaned}`);
1228
+ req.url = cleaned;
1229
+ }
1230
+ }
1231
+ }
1232
+ }
1233
+ next();
1234
+ });
1235
+ },
1236
+ async buildStart() {
1237
+ if (!state.scanPatterns) return;
1238
+ await compileAll(state);
1239
+ state.logger.log("Cache keys:", [...state.cache.keys()].slice(0, 3));
1240
+ },
1241
+ resolveId(id, importer, options) {
1242
+ return resolveIdHook(this, state, id, importer, options);
1243
+ },
1244
+ load(id, loadOptions) {
1245
+ return loadHook(state, id, loadOptions);
1246
+ },
1247
+ async transform(code, id, transformOptions) {
1248
+ return transformHook(state, code, id, transformOptions);
1249
+ },
1250
+ async handleHotUpdate(ctx) {
1251
+ return handleHotUpdateHook(state, ctx);
1252
+ },
1253
+ generateBundle() {
1254
+ handleGenerateBundleHook(state, this.emitFile.bind(this));
1255
+ }
1256
+ },
1257
+ createPostTransformPlugin(state)
1258
+ ];
1259
+ }
1260
+ //#endregion
1261
+ //#region src/index.ts
1262
+ const __internal = { rewriteStaticAssetUrls };
1263
+ var src_default = vize;
1264
+ //#endregion
1265
+ export { __internal, rewriteStaticAssetUrls as __internal_rewriteStaticAssetUrls, src_default as default, defineConfig, loadConfig, vize, vizeConfigStore };