@vizejs/vite-plugin 0.100.0 → 0.101.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
2
  import fs from "node:fs";
3
3
  import { createHash } from "node:crypto";
4
- import path from "node:path";
5
4
  import * as native from "@vizejs/native";
6
- import { classifyVitePluginRequest } from "@vizejs/native";
5
+ import { applyViteDefineReplacements, classifyVitePluginRequest, createViteBareImportBases, createViteBareImportCandidates, createViteVirtualId, detectViteHmrUpdateType, generateViteHmrCode, hasViteHmrChanges, isViteBareSpecifier, normalizeViteRequireBase, normalizeViteResolvedVuePath, resolveViteAliasRequest, resolveViteCssImports, resolveViteRelativeImport, resolveViteVuePath, rewriteViteDynamicTemplateImports, rewriteViteStaticAssetUrls, scopeViteCssForPipeline, shouldApplyViteDefineInVirtualModule, splitViteIdQuery, toViteBrowserImportPrefix } from "@vizejs/native";
7
6
  import { CONFIG_FILE_NAMES, defineConfig, loadConfig } from "vize";
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 {
@@ -859,104 +477,35 @@ async function compileAll(state) {
859
477
  //#endregion
860
478
  //#region src/plugin/resolve.ts
861
479
  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(":");
480
+ return resolveViteVuePath(state.root, id, importer);
890
481
  }
482
+ const EMPTY_NATIVE_ALIAS_RULES = [];
891
483
  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
- }
484
+ return resolveViteAliasRequest(id, nativeCssAliasRules(state));
921
485
  }
922
486
  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
- }
487
+ const { request, querySuffix } = splitViteIdQuery(id);
488
+ for (const candidate of createViteBareImportBases(state.root, importer)) try {
489
+ return `${createRequire(candidate).resolve(request)}${querySuffix}`;
490
+ } catch {}
935
491
  return null;
936
492
  }
937
493
  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);
494
+ for (const candidate of createViteBareImportCandidates(id, nativeCssAliasRules(state), resolvedId)) {
947
495
  const resolved = resolveBareImportWithNode(state, candidate, importer);
948
496
  if (resolved) return resolved;
949
497
  }
950
498
  return null;
951
499
  }
952
500
  function normalizeResolvedVuePath(id) {
953
- const [pathPart] = splitIdQuery(id);
954
- if (!pathPart?.endsWith(".vue")) return null;
955
- return pathPart.startsWith("/@fs/") ? pathPart.slice(4) : pathPart;
501
+ return normalizeViteResolvedVuePath(id);
502
+ }
503
+ function nativeCssAliasRules(state) {
504
+ return state.cssAliasRules.length === 0 ? EMPTY_NATIVE_ALIAS_RULES : state.cssAliasRules.map(toNativeCssAliasRule);
956
505
  }
957
506
  async function resolveAliasedVueImport(ctx, state, id, importer, isSsrRequest, handleNodeModules) {
958
507
  if (path.isAbsolute(id)) return null;
959
- const viteImporter = normalizeRequireBase(importer) ?? importer;
508
+ const viteImporter = normalizeViteRequireBase(importer) ?? importer;
960
509
  const viteResolved = await ctx.resolve(id, viteImporter, { skipSelf: true });
961
510
  const realPath = viteResolved ? normalizeResolvedVuePath(viteResolved.id) : null;
962
511
  if (!realPath) return null;
@@ -995,8 +544,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
995
544
  }
996
545
  const cleanPath = id.slice(1);
997
546
  if (cleanPath.startsWith("/") && !cleanPath.endsWith(".vue.ts")) {
998
- const [pathPart, queryPart] = cleanPath.split("?");
999
- const querySuffix = queryPart ? `?${queryPart}` : "";
547
+ const { request: pathPart, querySuffix } = splitViteIdQuery(cleanPath);
1000
548
  state.logger.log(`resolveId: redirecting \0-prefixed non-vue ID to ${pathPart}${querySuffix}`);
1001
549
  const redirected = pathPart + querySuffix;
1002
550
  return isBuild ? classifyVitePluginRequest(redirected).normalizedFsId ?? redirected : redirected;
@@ -1035,7 +583,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1035
583
  if (!id.endsWith(".vue")) {
1036
584
  if (!id.startsWith("./") && !id.startsWith("../") && !id.startsWith("/")) {
1037
585
  const aliasRequest = resolveAliasRequest(state, id);
1038
- if (aliasRequest && isBareSpecifier(aliasRequest)) {
586
+ if (aliasRequest && isViteBareSpecifier(aliasRequest)) {
1039
587
  const nodeResolved = resolveBareImportCandidatesWithNode(state, id, cleanImporter);
1040
588
  if (nodeResolved) {
1041
589
  state.logger.log(`resolveId: resolved aliased bare ${id} to ${nodeResolved} via Node fallback`);
@@ -1056,7 +604,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1056
604
  state.logger.log(`resolveId: normalized bare ${id} to ${nodeResolved} via Node fallback`);
1057
605
  return nodeResolved;
1058
606
  }
1059
- if (isBareSpecifier(resolved.id)) return null;
607
+ if (isViteBareSpecifier(resolved.id)) return null;
1060
608
  return resolved;
1061
609
  }
1062
610
  } catch {}
@@ -1065,7 +613,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1065
613
  state.logger.log(`resolveId: resolved bare ${id} to ${nodeResolved} via Node fallback`);
1066
614
  return nodeResolved;
1067
615
  }
1068
- if (aliasRequest && aliasRequest !== id && !isBareSpecifier(aliasRequest)) {
616
+ if (aliasRequest && aliasRequest !== id && !isViteBareSpecifier(aliasRequest)) {
1069
617
  try {
1070
618
  const resolved = await ctx.resolve(aliasRequest, cleanImporter, { skipSelf: true });
1071
619
  if (resolved) {
@@ -1080,7 +628,7 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1080
628
  state.logger.log(`resolveId: normalized aliased bare ${id} to ${nodeResolved} via Node fallback`);
1081
629
  return nodeResolved;
1082
630
  }
1083
- if (isBareSpecifier(resolved.id)) return null;
631
+ if (isViteBareSpecifier(resolved.id)) return null;
1084
632
  return resolved;
1085
633
  }
1086
634
  } catch {}
@@ -1105,36 +653,10 @@ async function resolveIdHook(ctx, state, id, importer, options) {
1105
653
  }
1106
654
  } catch {}
1107
655
  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
- }
656
+ const resolved = resolveViteRelativeImport(id, cleanImporter);
657
+ if (resolved) {
658
+ state.logger.log(`resolveId: resolved relative ${id} to ${resolved}`);
659
+ return resolved;
1138
660
  }
1139
661
  }
1140
662
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/vite-plugin",
3
- "version": "0.100.0",
3
+ "version": "0.101.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.101.0",
37
37
  "tinyglobby": "0.2.16",
38
- "vize": "0.100.0"
38
+ "vize": "0.101.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "25.7.0",