@vizejs/vite-plugin 0.100.0 → 0.103.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.d.mts CHANGED
@@ -620,6 +620,13 @@ interface DynamicImportAliasRule {
620
620
  }
621
621
  //#endregion
622
622
  //#region src/transform.d.ts
623
+ /**
624
+ * Rewrite static asset URLs in compiled template output.
625
+ *
626
+ * Transforms property values like `src: "@/assets/logo.svg"` into import
627
+ * statements hoisted to the top of the module, so Vite's module resolution
628
+ * pipeline handles alias expansion and asset hashing in both dev and build.
629
+ */
623
630
  declare function rewriteStaticAssetUrls(code: string, aliasRules: DynamicImportAliasRule[]): string;
624
631
  //#endregion
625
632
  //#region src/plugin/index.d.ts
package/dist/index.mjs CHANGED
@@ -1,20 +1,16 @@
1
1
  import { createRequire } from "node:module";
2
- import fs from "node:fs";
3
2
  import { createHash } from "node:crypto";
4
- import path from "node:path";
5
3
  import * as native from "@vizejs/native";
6
- import { classifyVitePluginRequest } from "@vizejs/native";
4
+ import { applyViteDefineReplacements, chunkVitePrecompileFiles, classifyVitePluginRequest, createViteBareImportBases, createViteBareImportCandidates, createViteVirtualId, detectViteHmrUpdateType, diffVitePrecompileFiles, generateViteHmrCode, hasViteHmrChanges, isViteBareSpecifier, normalizeViteCssModuleFilename, normalizeViteDevMiddlewareUrl, normalizeVitePrecompileBatchSize, normalizeViteRequireBase, normalizeViteResolvedVuePath, resolveViteAliasRequest, resolveViteCssImports, resolveViteRelativeImport, resolveViteVuePath, rewriteViteDynamicTemplateImports, rewriteViteStaticAssetUrls, scopeViteCssForPipeline, shouldApplyViteDefineInVirtualModule, splitViteIdQuery, toViteBrowserImportPrefix } from "@vizejs/native";
7
5
  import { CONFIG_FILE_NAMES, defineConfig, loadConfig } from "vize";
6
+ import fs from "node:fs";
8
7
  import { glob } from "tinyglobby";
8
+ import path from "node:path";
9
9
  import { pathToFileURL } from "node:url";
10
10
  import { transformWithOxc } from "vite";
11
11
  //#region src/hmr.ts
12
- function didHashChange(prevHash, nextHash) {
13
- return prevHash !== nextHash;
14
- }
15
12
  function hasHmrChanges(prev, next) {
16
- if (!prev) return true;
17
- return didHashChange(prev.scriptHash, next.scriptHash) || didHashChange(prev.templateHash, next.templateHash) || didHashChange(prev.styleHash, next.styleHash);
13
+ return hasViteHmrChanges(toHmrHashes(prev), toHmrHashes(next));
18
14
  }
19
15
  /**
20
16
  * Detect the type of HMR update needed based on content hash changes.
@@ -24,362 +20,44 @@ function hasHmrChanges(prev, next) {
24
20
  * @returns The type of HMR update needed
25
21
  */
26
22
  function detectHmrUpdateType(prev, next) {
27
- if (!prev) return "full-reload";
28
- if (didHashChange(prev.scriptHash, next.scriptHash)) return "full-reload";
29
- const templateChanged = didHashChange(prev.templateHash, next.templateHash);
30
- if (didHashChange(prev.styleHash, next.styleHash) && !templateChanged) return "style-only";
31
- if (templateChanged) return "template-only";
32
- return "full-reload";
23
+ return detectViteHmrUpdateType(toHmrHashes(prev), toHmrHashes(next));
33
24
  }
34
25
  /**
35
26
  * Generate HMR-aware code output based on update type.
36
27
  */
37
28
  function generateHmrCode(scopeId, updateType) {
38
- return `
39
- if (import.meta.hot) {
40
- _sfc_main.__hmrId = ${JSON.stringify(scopeId)};
41
- _sfc_main.__hmrUpdateType = ${JSON.stringify(updateType)};
42
-
43
- import.meta.hot.accept((mod) => {
44
- if (!mod) return;
45
- const { default: updated } = mod;
46
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
47
- const updateType = updated.__hmrUpdateType || 'full-reload';
48
- if (updateType === 'template-only') {
49
- __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render);
50
- } else {
51
- __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated);
52
- }
53
- }
54
- });
55
-
56
- import.meta.hot.on('vize:update', (data) => {
57
- if (data.id !== _sfc_main.__hmrId) return;
58
-
59
- if (data.type === 'style-only') {
60
- // Update styles without remounting component
61
- const styleId = 'vize-style-' + _sfc_main.__hmrId;
62
- const styleEl = document.getElementById(styleId);
63
- if (styleEl && data.css) {
64
- styleEl.textContent = data.css;
65
- }
66
- }
67
- });
68
-
69
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
70
- __VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main);
71
- }
72
- }`;
29
+ return generateViteHmrCode(scopeId, updateType);
30
+ }
31
+ function toHmrHashes(module) {
32
+ return module ? {
33
+ scriptHash: module.scriptHash,
34
+ templateHash: module.templateHash,
35
+ styleHash: module.styleHash
36
+ } : void 0;
73
37
  }
74
38
  //#endregion
75
39
  //#region src/utils/css.ts
76
- const deepSelectorPattern = /:deep\(([^()]*(?:\([^()]*\))*[^()]*)\)/;
77
- const globalSelectorPattern = /:global\(([^()]*(?:\([^()]*\))*[^()]*)\)/g;
78
- const recursiveAtRules = new Set([
79
- "@container",
80
- "@layer",
81
- "@media",
82
- "@supports"
83
- ]);
84
40
  function scopeCssForPipeline(css, scopeId) {
85
- return transformCssBlock(css, scopeId);
41
+ return scopeViteCssForPipeline(css, scopeId);
86
42
  }
87
43
  /**
88
44
  * Resolve CSS @import statements by inlining the imported files,
89
45
  * then resolve @custom-media definitions within the combined CSS.
90
- *
91
- * This is necessary because Vize embeds CSS as a JS string via
92
- * document.createElement('style'), bypassing Vite's CSS pipeline.
93
46
  */
94
47
  function resolveCssImports(css, importer, aliasRules, isDev, devUrlBase) {
95
- const customMedia = /* @__PURE__ */ new Map();
96
- const importRegex = /^@import\s+(?:"([^"]+)"|'([^']+)');?\s*$/gm;
97
- let result = css;
98
- result = result.replace(importRegex, (_match, dqPath, sqPath) => {
99
- const importPath = dqPath || sqPath;
100
- if (!importPath) return _match;
101
- const resolved = resolveCssPath(importPath, importer, aliasRules);
102
- if (!resolved || !fs.existsSync(resolved)) return _match;
103
- try {
104
- const content = fs.readFileSync(resolved, "utf-8");
105
- parseCustomMedia(content, customMedia);
106
- return content;
107
- } catch {
108
- return _match;
109
- }
110
- });
111
- parseCustomMedia(result, customMedia);
112
- result = result.replace(/^@custom-media\s+[^;]+;\s*$/gm, "");
113
- if (customMedia.size > 0) for (const [name, query] of customMedia) {
114
- const escaped = name.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
115
- result = result.replace(new RegExp(`\\(${escaped}\\)`, "g"), query);
116
- }
117
- if (isDev) result = result.replace(/url\(\s*(["']?)([^"')]+)\1\s*\)/g, (_match, quote, urlPath) => {
118
- const trimmed = urlPath.trim();
119
- if (trimmed.startsWith("data:") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("/@fs/")) return _match;
120
- const resolved = resolveCssPath(trimmed, importer, aliasRules);
121
- if (resolved && fs.existsSync(resolved)) {
122
- const normalized = resolved.replace(/\\/g, "/");
123
- const base = devUrlBase ?? "/";
124
- return `url("${base.endsWith("/") ? base : base + "/"}@fs${normalized}")`;
125
- }
126
- return _match;
127
- });
128
- result = result.replace(new RegExp(deepSelectorPattern.source, "g"), "$1");
129
- result = result.replace(/\n{3,}/g, "\n\n");
130
- return result;
131
- }
132
- function transformCssBlock(css, scopeId) {
133
- let output = "";
134
- let cursor = 0;
135
- while (cursor < css.length) {
136
- const brace = findNextTopLevelBrace(css, cursor);
137
- if (brace === -1) {
138
- output += css.slice(cursor);
139
- break;
140
- }
141
- const end = findMatchingBrace(css, brace);
142
- if (end === -1) {
143
- output += css.slice(cursor);
144
- break;
145
- }
146
- const header = css.slice(cursor, brace);
147
- const body = css.slice(brace + 1, end);
148
- const leadingLength = header.search(/\S/);
149
- const leading = leadingLength === -1 ? header : header.slice(0, leadingLength);
150
- const statement = leadingLength === -1 ? "" : header.slice(leadingLength);
151
- output += leading;
152
- if (statement.trimStart().startsWith("@")) {
153
- output += statement;
154
- output += "{";
155
- output += shouldRecurseAtRule(statement) ? transformCssBlock(body, scopeId) : body;
156
- output += "}";
157
- } else {
158
- output += scopeSelectorList(statement, scopeId);
159
- output += "{";
160
- output += body;
161
- output += "}";
162
- }
163
- cursor = end + 1;
164
- }
165
- return output;
166
- }
167
- function shouldRecurseAtRule(statement) {
168
- const name = statement.trimStart().split(/\s+/, 1)[0];
169
- return name !== void 0 && recursiveAtRules.has(name);
170
- }
171
- function findNextTopLevelBrace(css, start) {
172
- let parenDepth = 0;
173
- let bracketDepth = 0;
174
- let quote = null;
175
- let inComment = false;
176
- for (let index = start; index < css.length; index += 1) {
177
- const char = css[index];
178
- const next = css[index + 1];
179
- if (inComment) {
180
- if (char === "*" && next === "/") {
181
- inComment = false;
182
- index += 1;
183
- }
184
- continue;
185
- }
186
- if (quote !== null) {
187
- if (char === "\\") index += 1;
188
- else if (char === quote) quote = null;
189
- continue;
190
- }
191
- if (char === "/" && next === "*") {
192
- inComment = true;
193
- index += 1;
194
- continue;
195
- }
196
- if (char === "'" || char === "\"") {
197
- quote = char;
198
- continue;
199
- }
200
- if (char === "(") parenDepth += 1;
201
- else if (char === ")" && parenDepth > 0) parenDepth -= 1;
202
- else if (char === "[") bracketDepth += 1;
203
- else if (char === "]" && bracketDepth > 0) bracketDepth -= 1;
204
- else if (char === "{" && parenDepth === 0 && bracketDepth === 0) return index;
205
- }
206
- return -1;
207
- }
208
- function findMatchingBrace(css, start) {
209
- let depth = 0;
210
- let quote = null;
211
- let inComment = false;
212
- for (let index = start; index < css.length; index += 1) {
213
- const char = css[index];
214
- const next = css[index + 1];
215
- if (inComment) {
216
- if (char === "*" && next === "/") {
217
- inComment = false;
218
- index += 1;
219
- }
220
- continue;
221
- }
222
- if (quote !== null) {
223
- if (char === "\\") index += 1;
224
- else if (char === quote) quote = null;
225
- continue;
226
- }
227
- if (char === "/" && next === "*") {
228
- inComment = true;
229
- index += 1;
230
- continue;
231
- }
232
- if (char === "'" || char === "\"") {
233
- quote = char;
234
- continue;
235
- }
236
- if (char === "{") depth += 1;
237
- else if (char === "}") {
238
- depth -= 1;
239
- if (depth === 0) return index;
240
- }
241
- }
242
- return -1;
243
- }
244
- function scopeSelectorList(selectorList, scopeId) {
245
- return splitSelectorList(selectorList).map((selector) => scopeSelector(selector, scopeId)).join(",");
246
- }
247
- function splitSelectorList(selectorList) {
248
- const selectors = [];
249
- let start = 0;
250
- let parenDepth = 0;
251
- let bracketDepth = 0;
252
- let quote = null;
253
- for (let index = 0; index < selectorList.length; index += 1) {
254
- const char = selectorList[index];
255
- if (quote !== null) {
256
- if (char === "\\") index += 1;
257
- else if (char === quote) quote = null;
258
- continue;
259
- }
260
- if (char === "'" || char === "\"") {
261
- quote = char;
262
- continue;
263
- }
264
- if (char === "(") parenDepth += 1;
265
- else if (char === ")" && parenDepth > 0) parenDepth -= 1;
266
- else if (char === "[") bracketDepth += 1;
267
- else if (char === "]" && bracketDepth > 0) bracketDepth -= 1;
268
- else if (char === "," && parenDepth === 0 && bracketDepth === 0) {
269
- selectors.push(selectorList.slice(start, index));
270
- start = index + 1;
271
- }
272
- }
273
- selectors.push(selectorList.slice(start));
274
- return selectors;
275
- }
276
- function scopeSelector(selector, scopeId) {
277
- const leadingLength = selector.search(/\S/);
278
- if (leadingLength === -1) return selector;
279
- const leading = selector.slice(0, leadingLength);
280
- const trailingLength = selector.match(/\s*$/)?.[0].length ?? 0;
281
- const bodyEnd = trailingLength === 0 ? selector.length : selector.length - trailingLength;
282
- const trailing = selector.slice(bodyEnd);
283
- let body = selector.slice(leadingLength, bodyEnd).replace(globalSelectorPattern, "$1");
284
- const deep = body.match(deepSelectorPattern);
285
- if (deep?.index !== void 0) {
286
- const before = body.slice(0, deep.index).trimEnd();
287
- const inner = deep[1] ?? "";
288
- const after = body.slice(deep.index + deep[0].length);
289
- body = `${before.length === 0 ? `[${scopeId}]` : addScopeToSelectorEnd(before, scopeId)} ${inner}${after}`;
290
- } else body = addScopeToSelectorEnd(body, scopeId);
291
- return leading + body + trailing;
292
- }
293
- function addScopeToSelectorEnd(selector, scopeId) {
294
- const targetStart = findLastCompoundStart(selector);
295
- const beforeTarget = selector.slice(0, targetStart);
296
- const target = selector.slice(targetStart);
297
- const insertAt = findScopeInsertPosition(target);
298
- return `${beforeTarget}${target.slice(0, insertAt)}[${scopeId}]${target.slice(insertAt)}`;
299
- }
300
- function findLastCompoundStart(selector) {
301
- let parenDepth = 0;
302
- let bracketDepth = 0;
303
- let quote = null;
304
- for (let index = selector.length - 1; index >= 0; index -= 1) {
305
- const char = selector[index];
306
- if (quote !== null) {
307
- if (char === quote) quote = null;
308
- continue;
309
- }
310
- if (char === "'" || char === "\"") {
311
- quote = char;
312
- continue;
313
- }
314
- if (char === ")") parenDepth += 1;
315
- else if (char === "(" && parenDepth > 0) parenDepth -= 1;
316
- else if (char === "]") bracketDepth += 1;
317
- else if (char === "[" && bracketDepth > 0) bracketDepth -= 1;
318
- else if (parenDepth === 0 && bracketDepth === 0 && (char === ">" || char === "+" || char === "~")) return index + 1;
319
- else if (parenDepth === 0 && bracketDepth === 0 && /\s/.test(char)) {
320
- while (index > 0 && /\s/.test(selector[index - 1])) index -= 1;
321
- return index + 1;
322
- }
323
- }
324
- return 0;
325
- }
326
- function findScopeInsertPosition(target) {
327
- let parenDepth = 0;
328
- let bracketDepth = 0;
329
- let quote = null;
330
- for (let index = 0; index < target.length; index += 1) {
331
- const char = target[index];
332
- if (quote !== null) {
333
- if (char === "\\") index += 1;
334
- else if (char === quote) quote = null;
335
- continue;
336
- }
337
- if (char === "'" || char === "\"") {
338
- quote = char;
339
- continue;
340
- }
341
- if (char === "(") parenDepth += 1;
342
- else if (char === ")" && parenDepth > 0) parenDepth -= 1;
343
- else if (char === "[") bracketDepth += 1;
344
- else if (char === "]" && bracketDepth > 0) bracketDepth -= 1;
345
- else if (char === ":" && parenDepth === 0 && bracketDepth === 0) return index;
346
- }
347
- return target.length;
348
- }
349
- function parseCustomMedia(css, map) {
350
- const re = /@custom-media\s+(--[\w-]+)\s+(.+?)\s*;/g;
351
- let m;
352
- while ((m = re.exec(css)) !== null) map.set(m[1], m[2]);
353
- }
354
- function resolveCssPath(importPath, importer, aliasRules) {
355
- for (const rule of aliasRules) {
356
- const resolved = resolveAliasPath(importPath, rule);
357
- if (resolved !== null) return path.resolve(resolved);
358
- }
359
- if (importPath.startsWith(".")) {
360
- const dir = path.dirname(importer);
361
- return path.resolve(dir, importPath);
362
- }
363
- if (path.isAbsolute(importPath)) return importPath;
364
- return null;
365
- }
366
- function resolveAliasPath(importPath, rule) {
367
- if (typeof rule.find !== "string") {
368
- const pattern = stableAliasPattern$1(rule.find);
369
- return pattern.test(importPath) ? importPath.replace(pattern, rule.replacement) : null;
370
- }
371
- const suffix = matchedAliasSuffix(importPath, rule.find);
372
- if (suffix !== null) return path.join(rule.replacement, suffix);
373
- return null;
374
- }
375
- function stableAliasPattern$1(pattern) {
376
- return new RegExp(pattern.source, pattern.flags.replace(/[gy]/g, ""));
377
- }
378
- function matchedAliasSuffix(importPath, find) {
379
- if (importPath === find) return "";
380
- const prefix = find.endsWith("/") ? find : `${find}/`;
381
- if (!importPath.startsWith(prefix)) return null;
382
- return importPath.slice(prefix.length);
48
+ return resolveViteCssImports(css, importer, aliasRules.map(toNativeCssAliasRule), isDev, devUrlBase);
49
+ }
50
+ function toNativeCssAliasRule(rule) {
51
+ return typeof rule.find === "string" ? {
52
+ find: rule.find,
53
+ replacement: rule.replacement,
54
+ isRegex: false
55
+ } : {
56
+ find: rule.find.source,
57
+ replacement: rule.replacement,
58
+ isRegex: true,
59
+ flags: rule.find.flags.replace(/[gy]/g, "")
60
+ };
383
61
  }
384
62
  //#endregion
385
63
  //#region src/utils/index.ts
@@ -508,29 +186,16 @@ ${output}`;
508
186
  }
509
187
  return output;
510
188
  }
511
- const VIZE_SSR_PREFIX$1 = "\0vize-ssr:";
512
189
  const RESOLVED_CSS_MODULE = "\0vize:all-styles.css";
513
190
  /** Create a virtual module ID from a real .vue file path */
514
191
  function toVirtualId(realPath, ssr = false) {
515
- return ssr ? `${VIZE_SSR_PREFIX$1}${realPath}.ts` : "\0" + realPath + ".ts";
516
- }
517
- function escapeRegExp(value) {
518
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
192
+ return createViteVirtualId(realPath, ssr);
519
193
  }
520
194
  function toBrowserImportPrefix(replacement) {
521
- const normalized = replacement.replace(/\\/g, "/");
522
- if (normalized.startsWith("/@fs/")) return normalized;
523
- if (path.isAbsolute(replacement) && fs.existsSync(replacement)) return `/@fs${normalized}`;
524
- return normalized;
195
+ return toViteBrowserImportPrefix(replacement);
525
196
  }
526
197
  function rewriteDynamicTemplateImports(code, aliasRules) {
527
- let rewritten = code;
528
- for (const rule of aliasRules) {
529
- const pattern = new RegExp(`\\bimport\\s*\\(\\s*\`${escapeRegExp(rule.fromPrefix)}`, "g");
530
- rewritten = rewritten.replace(pattern, `import(/* @vite-ignore */ \`${rule.toPrefix}`);
531
- }
532
- rewritten = rewritten.replace(/\bimport\s*\(\s*`/g, "import(/* @vite-ignore */ `");
533
- return rewritten;
198
+ return rewriteViteDynamicTemplateImports(code, aliasRules);
534
199
  }
535
200
  //#endregion
536
201
  //#region src/transform.ts
@@ -547,53 +212,11 @@ function rewriteDynamicTemplateImports(code, aliasRules) {
547
212
  * statements hoisted to the top of the module, so Vite's module resolution
548
213
  * pipeline handles alias expansion and asset hashing in both dev and build.
549
214
  */
550
- const SCRIPT_EXTENSIONS = /\.(js|mjs|cjs|ts|mts|cts|jsx|tsx)$/i;
551
215
  function rewriteStaticAssetUrls(code, aliasRules) {
552
- let rewritten = code;
553
- const imports = [];
554
- let counter = 0;
555
- for (const rule of aliasRules) {
556
- const pattern = new RegExp(`("?src"?\\s*:\\s*)(?:"(${escapeRegExp(rule.fromPrefix)}[^"]+)"|'(${escapeRegExp(rule.fromPrefix)}[^']+)')`, "g");
557
- rewritten = rewritten.replace(pattern, (match, prefix, dqPath, sqPath) => {
558
- const fullPath = dqPath || sqPath;
559
- if (fullPath && SCRIPT_EXTENSIONS.test(fullPath)) return match;
560
- const varName = `__vize_static_${counter++}`;
561
- imports.push(`import ${varName} from ${JSON.stringify(fullPath)};`);
562
- return `${prefix}${varName}`;
563
- });
564
- }
565
- if (imports.length > 0) rewritten = imports.join("\n") + "\n" + rewritten;
566
- return rewritten;
567
- }
568
- /**
569
- * Built-in Vite/Vue/Nuxt define keys that are normally handled by Vite's own
570
- * transform pipeline.
571
- */
572
- const BUILTIN_DEFINE_PREFIXES = [
573
- "import.meta.server",
574
- "import.meta.client",
575
- "import.meta.dev",
576
- "import.meta.test",
577
- "import.meta.prerender",
578
- "import.meta.env",
579
- "import.meta.hot",
580
- "__VUE_",
581
- "__NUXT_",
582
- "process.env"
583
- ];
584
- const VIRTUAL_MODULE_DEFINE_KEYS = new Set([
585
- "import.meta.server",
586
- "import.meta.client",
587
- "import.meta.dev",
588
- "import.meta.test",
589
- "import.meta.prerender"
590
- ]);
591
- function isBuiltinDefine(key) {
592
- return BUILTIN_DEFINE_PREFIXES.some((prefix) => key === prefix || key.startsWith(prefix + ".") || key.startsWith(prefix + "_"));
216
+ return rewriteViteStaticAssetUrls(code, aliasRules);
593
217
  }
594
218
  function shouldApplyDefineInVirtualModule(key) {
595
- if (VIRTUAL_MODULE_DEFINE_KEYS.has(key)) return true;
596
- return !isBuiltinDefine(key);
219
+ return shouldApplyViteDefineInVirtualModule(key);
597
220
  }
598
221
  /**
599
222
  * Apply Vite define replacements to code.
@@ -601,15 +224,10 @@ function shouldApplyDefineInVirtualModule(key) {
601
224
  * Uses word-boundary-aware matching to avoid replacing inside strings or partial matches.
602
225
  */
603
226
  function applyDefineReplacements(code, defines) {
604
- const sortedKeys = Object.keys(defines).sort((a, b) => b.length - a.length);
605
- let result = code;
606
- for (const key of sortedKeys) {
607
- if (!result.includes(key)) continue;
608
- const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
609
- const re = new RegExp(escaped + "(?![\\w$.])", "g");
610
- result = result.replace(re, defines[key]);
611
- }
612
- return result;
227
+ return applyViteDefineReplacements(code, Object.entries(defines).map(([key, value]) => ({
228
+ key,
229
+ value
230
+ })));
613
231
  }
614
232
  function createLogger(debug) {
615
233
  return {
@@ -648,6 +266,19 @@ function buildCompileBatchOptions(options) {
648
266
  //#endregion
649
267
  //#region src/compiler.ts
650
268
  const { compileSfc, compileSfcBatchWithResults } = native;
269
+ var VizeSfcCompileError = class extends Error {
270
+ filePath;
271
+ diagnostics;
272
+ constructor(filePath, diagnostics) {
273
+ super(formatCompileErrorMessage(filePath, diagnostics));
274
+ this.name = "VizeSfcCompileError";
275
+ this.filePath = filePath;
276
+ this.diagnostics = diagnostics;
277
+ }
278
+ };
279
+ function formatCompileErrorMessage(filePath, diagnostics) {
280
+ return `[vize] Compilation failed in ${filePath}:\n${diagnostics.map((diagnostic) => ` - ${diagnostic}`).join("\n")}`;
281
+ }
651
282
  function normalizeStyleBlocks(styles) {
652
283
  if (!styles) return [];
653
284
  return styles.map((block) => ({
@@ -662,10 +293,7 @@ function compileFile(filePath, cache, options, source) {
662
293
  const content = source ?? fs.readFileSync(filePath, "utf-8");
663
294
  const scopeId = generateScopeId(filePath);
664
295
  const result = compileSfc(content, buildCompileFileOptions(filePath, options));
665
- if (result.errors.length > 0) {
666
- const errorMsg = result.errors.join("\n");
667
- console.error(`[vize] Compilation error in ${filePath}:\n${errorMsg}`);
668
- }
296
+ if (result.errors.length > 0) throw new VizeSfcCompileError(filePath, result.errors);
669
297
  if (result.warnings.length > 0) result.warnings.forEach((warning) => {
670
298
  console.warn(`[vize] Warning in ${filePath}: ${warning}`);
671
299
  });
@@ -701,13 +329,15 @@ function compileBatch(files, cache, options) {
701
329
  macroArtifacts: fileResult.macroArtifacts ?? [],
702
330
  styles: normalizeStyleBlocks(fileResult.styles)
703
331
  });
704
- if (fileResult.errors.length > 0) console.error(`[vize] Compilation error in ${fileResult.path}:\n${fileResult.errors.join("\n")}`);
332
+ if (fileResult.errors.length > 0) console.error(formatCompileErrorMessage(fileResult.path, fileResult.errors));
705
333
  if (fileResult.warnings.length > 0) fileResult.warnings.forEach((warning) => {
706
334
  console.warn(`[vize] Warning in ${fileResult.path}: ${warning}`);
707
335
  });
708
336
  }
709
337
  return result;
710
338
  }
339
+ //#endregion
340
+ //#region src/plugin/precompile.ts
711
341
  const DEFAULT_PRECOMPILE_IGNORE_PATTERNS = [
712
342
  "node_modules/**",
713
343
  "dist/**",
@@ -717,46 +347,29 @@ const DEFAULT_PRECOMPILE_IGNORE_PATTERNS = [
717
347
  ".nitro/**",
718
348
  "coverage/**"
719
349
  ];
720
- function hasFileMetadataChanged(previous, next) {
721
- return previous === void 0 || previous.mtimeMs !== next.mtimeMs || previous.size !== next.size;
722
- }
723
350
  function diffPrecompileFiles(files, currentMetadata, previousMetadata) {
724
- const changedFiles = [];
725
- const seenFiles = new Set(files);
726
- for (const file of files) {
727
- const metadata = currentMetadata.get(file);
728
- if (!metadata || hasFileMetadataChanged(previousMetadata.get(file), metadata)) changedFiles.push(file);
729
- }
730
- const deletedFiles = [];
731
- for (const file of previousMetadata.keys()) if (!seenFiles.has(file)) deletedFiles.push(file);
732
- return {
733
- changedFiles,
734
- deletedFiles
735
- };
351
+ return diffVitePrecompileFiles([...files], toNativePrecompileMetadataEntries(currentMetadata), toNativePrecompileMetadataEntries(previousMetadata));
736
352
  }
737
353
  function normalizePrecompileBatchSize(value) {
738
- if (value === void 0 || !Number.isFinite(value) || value <= 0) return 128;
739
- return Math.max(1, Math.floor(value));
354
+ return normalizeVitePrecompileBatchSize(value);
740
355
  }
741
356
  function chunkPrecompileFiles(files, batchSize, options = {}) {
742
- const normalizedBatchSize = normalizePrecompileBatchSize(batchSize);
743
- const maxBytes = Math.max(1, Math.floor(options.maxBytes ?? 33554432));
744
- const chunks = [];
745
- let current = [];
746
- let currentBytes = 0;
747
- for (const file of files) {
748
- const fileBytes = Math.max(0, options.metadata?.get(file)?.size ?? 0);
749
- if (current.length > 0 && (current.length >= normalizedBatchSize || currentBytes + fileBytes > maxBytes)) {
750
- chunks.push(current);
751
- current = [];
752
- currentBytes = 0;
753
- }
754
- current.push(file);
755
- currentBytes += fileBytes;
756
- }
757
- if (current.length > 0) chunks.push(current);
758
- return chunks;
357
+ return chunkVitePrecompileFiles([...files], batchSize, {
358
+ maxBytes: options.maxBytes,
359
+ metadata: options.metadata ? toNativePrecompileMetadataEntries(options.metadata) : void 0
360
+ });
759
361
  }
362
+ function toNativePrecompileMetadataEntries(metadata) {
363
+ const entries = [];
364
+ for (const [path, value] of metadata) entries.push({
365
+ path,
366
+ mtimeMs: value.mtimeMs,
367
+ size: value.size
368
+ });
369
+ return entries;
370
+ }
371
+ //#endregion
372
+ //#region src/plugin/state.ts
760
373
  function getEnvironmentCache(state, ssr) {
761
374
  return ssr ? state.ssrCache : state.cache;
762
375
  }
@@ -815,6 +428,7 @@ async function compileAll(state) {
815
428
  let successCount = 0;
816
429
  let failedCount = 0;
817
430
  let nativeTimeMs = 0;
431
+ const precompileFailures = [];
818
432
  const chunks = chunkPrecompileFiles(changedFiles, state.precompileBatchSize, { metadata: currentMetadata });
819
433
  for (const chunk of chunks) {
820
434
  const fileContents = [];
@@ -829,6 +443,7 @@ async function compileAll(state) {
829
443
  state.cache.delete(file);
830
444
  state.collectedCss.delete(file);
831
445
  state.precompileMetadata.delete(file);
446
+ precompileFailures.push(`[vize] Failed to read ${file}: ${formatUnknownError$1(e)}`);
832
447
  state.logger.error(`Failed to read ${file}:`, e);
833
448
  }
834
449
  if (fileContents.length === 0) continue;
@@ -837,8 +452,9 @@ async function compileAll(state) {
837
452
  vapor: state.mergedOptions.vapor ?? false,
838
453
  customRenderer: state.mergedOptions.customRenderer ?? false
839
454
  });
840
- successCount += result.successCount;
841
- failedCount += result.failedCount;
455
+ const chunkFailedCount = result.results.filter((fileResult) => fileResult.errors.length > 0).length;
456
+ failedCount += chunkFailedCount;
457
+ successCount += result.results.length - chunkFailedCount;
842
458
  nativeTimeMs += result.timeMs;
843
459
  for (const fileResult of result.results) {
844
460
  const metadata = currentMetadata.get(fileResult.path);
@@ -846,6 +462,7 @@ async function compileAll(state) {
846
462
  state.cache.delete(fileResult.path);
847
463
  state.collectedCss.delete(fileResult.path);
848
464
  state.precompileMetadata.delete(fileResult.path);
465
+ precompileFailures.push(formatCompileErrorMessage(fileResult.path, fileResult.errors));
849
466
  continue;
850
467
  }
851
468
  if (metadata) state.precompileMetadata.set(fileResult.path, metadata);
@@ -855,108 +472,52 @@ async function compileAll(state) {
855
472
  const elapsed = (performance.now() - startTime).toFixed(2);
856
473
  const batchLabel = chunks.length === 1 ? "batch" : "batches";
857
474
  state.logger.info(`Pre-compilation complete: ${successCount} recompiled, ${cachedFileCount} reused, ${failedCount} failed (${elapsed}ms, native ${batchLabel}: ${nativeTimeMs.toFixed(2)}ms)`);
475
+ if (failedCount > 0) {
476
+ const details = precompileFailures.length > 0 ? `\n\n${precompileFailures.join("\n\n")}` : "";
477
+ throw new Error(`[vize] Pre-compilation failed for ${failedCount} file(s).${details}`);
478
+ }
479
+ }
480
+ function formatUnknownError$1(error) {
481
+ return error instanceof Error ? error.message : String(error);
858
482
  }
859
483
  //#endregion
860
484
  //#region src/plugin/resolve.ts
861
485
  function resolveVuePath(state, id, importer) {
862
- let resolved;
863
- if (id.startsWith("/@fs/")) resolved = id.slice(4);
864
- else if (id.startsWith("/") && !fs.existsSync(id)) resolved = path.resolve(state.root, id.slice(1));
865
- else if (path.isAbsolute(id)) resolved = id;
866
- else if (importer) {
867
- const importerRequest = classifyVitePluginRequest(importer);
868
- const realImporter = importerRequest.vizeVirtualPath ?? importerRequest.strippedVirtualPath ?? importer;
869
- resolved = path.resolve(path.dirname(realImporter), id);
870
- } else resolved = path.resolve(state.root, id);
871
- if (!path.isAbsolute(resolved)) resolved = path.resolve(state.root, resolved);
872
- return path.normalize(resolved);
873
- }
874
- function normalizeRequireBase(importer) {
875
- if (!importer) return null;
876
- let normalized = importer;
877
- const request = classifyVitePluginRequest(normalized);
878
- if (request.vizeVirtualPath) normalized = request.vizeVirtualPath;
879
- else if (request.isMacroVirtualId) normalized = request.strippedVirtualPath ?? "";
880
- return normalized.split("?")[0] ?? null;
881
- }
882
- function splitIdQuery(id) {
883
- const queryStart = id.indexOf("?");
884
- if (queryStart === -1) return [id, ""];
885
- return [id.slice(0, queryStart), id.slice(queryStart)];
886
- }
887
- function isBareSpecifier(id) {
888
- const [request] = splitIdQuery(id);
889
- return request !== "" && !request.startsWith("./") && !request.startsWith("../") && !request.startsWith("/") && !request.startsWith("\0") && !request.includes(":");
486
+ return resolveViteVuePath(state.root, id, importer);
890
487
  }
488
+ const EMPTY_NATIVE_ALIAS_RULES = [];
891
489
  function resolveAliasRequest(state, id) {
892
- const [request, querySuffix] = splitIdQuery(id);
893
- for (const rule of state.cssAliasRules) {
894
- if (rule.find instanceof RegExp) {
895
- const pattern = stableAliasPattern(rule.find);
896
- if (pattern.test(request)) return request.replace(pattern, rule.replacement) + querySuffix;
897
- continue;
898
- }
899
- if (request === rule.find) return rule.replacement + querySuffix;
900
- const findPrefix = rule.find.endsWith("/") ? rule.find : rule.find + "/";
901
- if (request.startsWith(findPrefix)) return (rule.replacement.endsWith("/") ? rule.replacement : rule.replacement + "/") + request.slice(findPrefix.length) + querySuffix;
902
- }
903
- return null;
904
- }
905
- function stableAliasPattern(pattern) {
906
- return new RegExp(pattern.source, pattern.flags.replace(/[gy]/g, ""));
907
- }
908
- function pushPnpmHoistBases(candidates, start, isDirectory) {
909
- if (!start) return;
910
- let dir = isDirectory ? start : path.dirname(start);
911
- for (;;) {
912
- const pnpmHoist = path.join(dir, "node_modules", ".pnpm", "node_modules");
913
- if (fs.existsSync(pnpmHoist)) {
914
- candidates.push(path.join(pnpmHoist, "package.json"));
915
- break;
916
- }
917
- const parent = path.dirname(dir);
918
- if (parent === dir) break;
919
- dir = parent;
920
- }
490
+ return resolveViteAliasRequest(id, nativeCssAliasRules(state));
921
491
  }
922
492
  function resolveBareImportWithNode(state, id, importer) {
923
- const [request, querySuffix] = splitIdQuery(id);
924
- const candidates = [normalizeRequireBase(importer), path.join(state.root, "package.json")].filter((candidate) => candidate != null);
925
- pushPnpmHoistBases(candidates, importer ?? null, false);
926
- pushPnpmHoistBases(candidates, state.root, true);
927
- const seen = /* @__PURE__ */ new Set();
928
- for (const candidate of candidates) {
929
- if (seen.has(candidate)) continue;
930
- seen.add(candidate);
931
- try {
932
- return `${createRequire(candidate).resolve(request)}${querySuffix}`;
933
- } catch {}
934
- }
493
+ const { request, querySuffix } = splitViteIdQuery(id);
494
+ for (const candidate of createViteBareImportBases(state.root, importer)) try {
495
+ return `${createRequire(candidate).resolve(request)}${querySuffix}`;
496
+ } catch {}
935
497
  return null;
936
498
  }
937
499
  function resolveBareImportCandidatesWithNode(state, id, importer, resolvedId) {
938
- const candidates = [
939
- resolvedId,
940
- resolveAliasRequest(state, id),
941
- id
942
- ].filter((candidate) => candidate != null && isBareSpecifier(candidate));
943
- const seen = /* @__PURE__ */ new Set();
944
- for (const candidate of candidates) {
945
- if (seen.has(candidate)) continue;
946
- seen.add(candidate);
500
+ for (const candidate of createViteBareImportCandidates(id, nativeCssAliasRules(state), resolvedId)) {
947
501
  const resolved = resolveBareImportWithNode(state, candidate, importer);
948
502
  if (resolved) return resolved;
949
503
  }
950
504
  return null;
951
505
  }
952
506
  function normalizeResolvedVuePath(id) {
953
- const [pathPart] = splitIdQuery(id);
954
- if (!pathPart?.endsWith(".vue")) return null;
955
- return pathPart.startsWith("/@fs/") ? pathPart.slice(4) : pathPart;
507
+ return normalizeViteResolvedVuePath(id);
508
+ }
509
+ function nativeCssAliasRules(state) {
510
+ return state.cssAliasRules.length === 0 ? EMPTY_NATIVE_ALIAS_RULES : state.cssAliasRules.map(toNativeCssAliasRule);
511
+ }
512
+ function isPotentialVizeResolveId(id) {
513
+ return id.startsWith("\0") || id.startsWith("vize:") || id.startsWith("/@fs") || id === "virtual:vize-styles" || id.endsWith(".vue") || id.includes(".vue?") || id.includes("?macro=true") || id.includes("?definePage");
514
+ }
515
+ function isPotentialVizeImporter(importer) {
516
+ return importer !== void 0 && (importer.startsWith("\0") || importer.startsWith("vize:"));
956
517
  }
957
518
  async function resolveAliasedVueImport(ctx, state, id, importer, isSsrRequest, handleNodeModules) {
958
519
  if (path.isAbsolute(id)) return null;
959
- const viteImporter = normalizeRequireBase(importer) ?? importer;
520
+ const viteImporter = normalizeViteRequireBase(importer) ?? importer;
960
521
  const viteResolved = await ctx.resolve(id, viteImporter, { skipSelf: true });
961
522
  const realPath = viteResolved ? normalizeResolvedVuePath(viteResolved.id) : null;
962
523
  if (!realPath) return null;
@@ -976,6 +537,7 @@ async function resolveAliasedVueImport(ctx, state, id, importer, isSsrRequest, h
976
537
  return null;
977
538
  }
978
539
  async function resolveIdHook(ctx, state, id, importer, options) {
540
+ if (!isPotentialVizeResolveId(id) && !isPotentialVizeImporter(importer)) return null;
979
541
  const isBuild = state.server === null;
980
542
  const importerRequest = importer ? classifyVitePluginRequest(importer) : null;
981
543
  const isSsrRequest = !!options?.ssr || (importerRequest?.isVizeSsrVirtual ?? false);
@@ -995,8 +557,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
995
557
  }
996
558
  const cleanPath = id.slice(1);
997
559
  if (cleanPath.startsWith("/") && !cleanPath.endsWith(".vue.ts")) {
998
- const [pathPart, queryPart] = cleanPath.split("?");
999
- const querySuffix = queryPart ? `?${queryPart}` : "";
560
+ const { request: pathPart, querySuffix } = splitViteIdQuery(cleanPath);
1000
561
  state.logger.log(`resolveId: redirecting \0-prefixed non-vue ID to ${pathPart}${querySuffix}`);
1001
562
  const redirected = pathPart + querySuffix;
1002
563
  return isBuild ? classifyVitePluginRequest(redirected).normalizedFsId ?? redirected : redirected;
@@ -1035,7 +596,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1035
596
  if (!id.endsWith(".vue")) {
1036
597
  if (!id.startsWith("./") && !id.startsWith("../") && !id.startsWith("/")) {
1037
598
  const aliasRequest = resolveAliasRequest(state, id);
1038
- if (aliasRequest && isBareSpecifier(aliasRequest)) {
599
+ if (aliasRequest && isViteBareSpecifier(aliasRequest)) {
1039
600
  const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter);
1040
601
  if (nodeResolved) {
1041
602
  state.logger.log(`resolveId: resolved aliased bare ${id} to ${nodeResolved} via Node fallback`);
@@ -1051,12 +612,14 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1051
612
  ...resolved,
1052
613
  id: normalizedFsId
1053
614
  };
1054
- const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter, resolved.id);
1055
- if (nodeResolved) {
1056
- state.logger.log(`resolveId: normalized bare ${id} to ${nodeResolved} via Node fallback`);
1057
- return nodeResolved;
615
+ if (isViteBareSpecifier(resolved.id)) {
616
+ const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter, resolved.id);
617
+ if (nodeResolved) {
618
+ state.logger.log(`resolveId: normalized bare ${id} to ${nodeResolved} via Node fallback`);
619
+ return nodeResolved;
620
+ }
621
+ return null;
1058
622
  }
1059
- if (isBareSpecifier(resolved.id)) return null;
1060
623
  return resolved;
1061
624
  }
1062
625
  } catch {}
@@ -1065,7 +628,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1065
628
  state.logger.log(`resolveId: resolved bare ${id} to ${nodeResolved} via Node fallback`);
1066
629
  return nodeResolved;
1067
630
  }
1068
- if (aliasRequest && aliasRequest !== id && !isBareSpecifier(aliasRequest)) {
631
+ if (aliasRequest && aliasRequest !== id && !isViteBareSpecifier(aliasRequest)) {
1069
632
  try {
1070
633
  const resolved = await ctx.resolve(aliasRequest, cleanImporter, { skipSelf: true });
1071
634
  if (resolved) {
@@ -1075,12 +638,14 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1075
638
  ...resolved,
1076
639
  id: normalizedFsId
1077
640
  };
1078
- const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter, resolved.id);
1079
- if (nodeResolved) {
1080
- state.logger.log(`resolveId: normalized aliased bare ${id} to ${nodeResolved} via Node fallback`);
1081
- return nodeResolved;
641
+ if (isViteBareSpecifier(resolved.id)) {
642
+ const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter, resolved.id);
643
+ if (nodeResolved) {
644
+ state.logger.log(`resolveId: normalized aliased bare ${id} to ${nodeResolved} via Node fallback`);
645
+ return nodeResolved;
646
+ }
647
+ return null;
1082
648
  }
1083
- if (isBareSpecifier(resolved.id)) return null;
1084
649
  return resolved;
1085
650
  }
1086
651
  } catch {}
@@ -1105,36 +670,10 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1105
670
  }
1106
671
  } catch {}
1107
672
  if (id.startsWith("./") || id.startsWith("../")) {
1108
- const [pathPart, queryPart] = id.split("?");
1109
- const querySuffix = queryPart ? `?${queryPart}` : "";
1110
- const resolved = path.resolve(path.dirname(cleanImporter), pathPart);
1111
- for (const ext of [
1112
- "",
1113
- ".ts",
1114
- ".tsx",
1115
- ".js",
1116
- ".jsx",
1117
- ".json"
1118
- ]) {
1119
- const candidate = resolved + ext;
1120
- if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
1121
- const finalPath = candidate + querySuffix;
1122
- state.logger.log(`resolveId: resolved relative ${id} to ${finalPath}`);
1123
- return finalPath;
1124
- }
1125
- }
1126
- if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) for (const indexFile of [
1127
- "/index.ts",
1128
- "/index.tsx",
1129
- "/index.js",
1130
- "/index.jsx"
1131
- ]) {
1132
- const candidate = resolved + indexFile;
1133
- if (fs.existsSync(candidate)) {
1134
- const finalPath = candidate + querySuffix;
1135
- state.logger.log(`resolveId: resolved directory ${id} to ${finalPath}`);
1136
- return finalPath;
1137
- }
673
+ const resolved = resolveViteRelativeImport(id, cleanImporter);
674
+ if (resolved) {
675
+ state.logger.log(`resolveId: resolved relative ${id} to ${resolved}`);
676
+ return resolved;
1138
677
  }
1139
678
  }
1140
679
  return null;
@@ -1223,6 +762,7 @@ function loadDefinePageMetaArtifact(state, realPath, ssr) {
1223
762
  } : null;
1224
763
  }
1225
764
  function loadHook(state, id, loadOptions) {
765
+ if (id !== "\0vize:all-styles.css" && !id.startsWith("\0")) return null;
1226
766
  const currentBase = loadOptions?.ssr ? state.serverViteBase : state.clientViteBase;
1227
767
  const request = classifyVitePluginRequest(id);
1228
768
  if (id === "\0vize:all-styles.css") {
@@ -1344,6 +884,7 @@ function loadHook(state, id, loadOptions) {
1344
884
  return null;
1345
885
  }
1346
886
  async function transformHook(state, code, id, options) {
887
+ if (!id.startsWith("\0")) return null;
1347
888
  const request = classifyVitePluginRequest(id);
1348
889
  if (request.isVizeVirtual || request.isMacroVirtualId) {
1349
890
  const realPath = request.isMacroVirtualId ? request.strippedVirtualPath ?? "" : request.vizeVirtualPath ?? "";
@@ -1361,17 +902,23 @@ async function transformHook(state, code, id, options) {
1361
902
  };
1362
903
  } catch (e) {
1363
904
  state.logger.error(`transformWithOxc failed for ${realPath}:`, e);
1364
- const dumpPath = getOxcDumpPath(state.root, realPath);
1365
- fs.writeFileSync(dumpPath, code, "utf-8");
1366
- state.logger.error(`Dumped failing code to ${dumpPath}`);
1367
- return {
1368
- code: "export default {}",
1369
- map: null
1370
- };
905
+ let dumpPath = null;
906
+ try {
907
+ dumpPath = getOxcDumpPath(state.root, realPath);
908
+ fs.writeFileSync(dumpPath, code, "utf-8");
909
+ state.logger.error(`Dumped failing code to ${dumpPath}`);
910
+ } catch (dumpError) {
911
+ state.logger.error(`Failed to dump failing virtual module for ${realPath}:`, dumpError);
912
+ }
913
+ const message = [`[vize] Virtual module transform failed for ${realPath}: ${formatUnknownError(e)}`, dumpPath ? `Dumped failing code to ${dumpPath}` : null].filter(Boolean).join("\n");
914
+ throw new Error(message);
1371
915
  }
1372
916
  }
1373
917
  return null;
1374
918
  }
919
+ function formatUnknownError(error) {
920
+ return error instanceof Error ? error.message : String(error);
921
+ }
1375
922
  //#endregion
1376
923
  //#region src/plugin/hmr.ts
1377
924
  async function handleHotUpdateHook(state, ctx) {
@@ -1564,6 +1111,28 @@ function patchUnoCssBridge(plugins) {
1564
1111
  }
1565
1112
  }
1566
1113
  //#endregion
1114
+ //#region src/plugin/css-modules.ts
1115
+ function patchCssModuleGenerateScopedName(userConfig) {
1116
+ const cssModules = userConfig.css?.modules;
1117
+ if (!cssModules || typeof cssModules.generateScopedName !== "function") return;
1118
+ const origFn = cssModules.generateScopedName;
1119
+ cssModules.generateScopedName = function(name, filename, css) {
1120
+ return origFn.call(this, name, normalizeViteCssModuleFilename(filename), css);
1121
+ };
1122
+ }
1123
+ //#endregion
1124
+ //#region src/plugin/dev-middleware.ts
1125
+ function installVirtualAssetMiddleware(devServer, state) {
1126
+ devServer.middlewares.use((req, _res, next) => {
1127
+ const rewrite = req.url ? normalizeViteDevMiddlewareUrl(req.url) : null;
1128
+ if (rewrite && fs.existsSync(rewrite.fsPath) && fs.statSync(rewrite.fsPath).isFile()) {
1129
+ state.logger.log(`middleware: rewriting ${req.url} -> ${rewrite.cleanedUrl}`);
1130
+ req.url = rewrite.cleanedUrl;
1131
+ }
1132
+ next();
1133
+ });
1134
+ }
1135
+ //#endregion
1567
1136
  //#region src/plugin/index.ts
1568
1137
  function aliasSortKey(find) {
1569
1138
  return typeof find === "string" ? find.length : find.source.length;
@@ -1599,18 +1168,7 @@ function vize(options = {}) {
1599
1168
  name: "vite-plugin-vize",
1600
1169
  enforce: "pre",
1601
1170
  config(userConfig, env) {
1602
- const cssModules = userConfig.css?.modules;
1603
- if (cssModules && typeof cssModules.generateScopedName === "function") {
1604
- const origFn = cssModules.generateScopedName;
1605
- cssModules.generateScopedName = function(name, filename, css) {
1606
- let clean = filename;
1607
- const nulIdx = clean.indexOf("\0");
1608
- if (nulIdx >= 0) clean = clean.slice(nulIdx + 1);
1609
- clean = clean.replace(/\.module\.\w+$/, "").replace(/\.\w+$/, "");
1610
- if (clean.includes("?")) clean = clean.split("?")[0];
1611
- return origFn.call(this, name, clean, css);
1612
- };
1613
- }
1171
+ patchCssModuleGenerateScopedName(userConfig);
1614
1172
  return {
1615
1173
  // @vitejs/plugin-vue normally provides them; vize must do so as its replacement.
1616
1174
  define: {
@@ -1701,24 +1259,7 @@ function vize(options = {}) {
1701
1259
  },
1702
1260
  configureServer(devServer) {
1703
1261
  state.server = devServer;
1704
- devServer.middlewares.use((req, _res, next) => {
1705
- if (req.url && req.url.includes("__x00__")) {
1706
- const [urlPath, queryPart] = req.url.split("?");
1707
- let cleanedPath = urlPath.replace(/__x00__/g, "");
1708
- cleanedPath = cleanedPath.replace(/^\/@id\/\//, "/@fs/");
1709
- if (cleanedPath.startsWith("/@fs/")) {
1710
- const fsPath = cleanedPath.slice(4);
1711
- if (fsPath.startsWith("/") && fs.existsSync(fsPath) && fs.statSync(fsPath).isFile() && !fsPath.endsWith(".vue.ts")) {
1712
- const cleaned = queryPart ? `${cleanedPath}?${queryPart}` : cleanedPath;
1713
- if (cleaned !== req.url) {
1714
- state.logger.log(`middleware: rewriting ${req.url} -> ${cleaned}`);
1715
- req.url = cleaned;
1716
- }
1717
- }
1718
- }
1719
- }
1720
- next();
1721
- });
1262
+ installVirtualAssetMiddleware(devServer, state);
1722
1263
  },
1723
1264
  async buildStart() {
1724
1265
  if (!state.scanPatterns || state.scanPatterns.length === 0) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/vite-plugin",
3
- "version": "0.100.0",
3
+ "version": "0.103.0",
4
4
  "description": "High-performance native Vite plugin for Vue SFC compilation powered by Vize",
5
5
  "keywords": [
6
6
  "compiler",
@@ -33,9 +33,9 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@vizejs/native": "0.100.0",
36
+ "@vizejs/native": "0.103.0",
37
37
  "tinyglobby": "0.2.16",
38
- "vize": "0.100.0"
38
+ "vize": "0.103.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "25.7.0",
@@ -46,6 +46,9 @@
46
46
  "peerDependencies": {
47
47
  "vite": "^8.0.0"
48
48
  },
49
+ "engines": {
50
+ "node": ">=22"
51
+ },
49
52
  "scripts": {
50
53
  "build": "vp pack",
51
54
  "dev": "vp pack --watch",