@vizejs/vite-plugin 0.0.1-alpha.102 → 0.0.1-alpha.104

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.
Files changed (2) hide show
  1. package/dist/index.js +141 -15
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -118,6 +118,69 @@ ${output}`;
118
118
  if (!isProduction && isDev && hasExportDefault) output += generateHmrCode(compiled.scopeId, hmrUpdateType ?? "full-reload");
119
119
  return output;
120
120
  }
121
+ /**
122
+ * Resolve CSS @import statements by inlining the imported files,
123
+ * then resolve @custom-media definitions within the combined CSS.
124
+ *
125
+ * This is necessary because Vize embeds CSS as a JS string via
126
+ * document.createElement('style'), bypassing Vite's CSS pipeline.
127
+ */
128
+ function resolveCssImports(css, importer, aliasRules, isDev, devUrlBase) {
129
+ const customMedia = new Map();
130
+ const importRegex = /^@import\s+(?:"([^"]+)"|'([^']+)');?\s*$/gm;
131
+ let result = css;
132
+ result = result.replace(importRegex, (_match, dqPath, sqPath) => {
133
+ const importPath = dqPath || sqPath;
134
+ if (!importPath) return _match;
135
+ const resolved = resolveCssPath(importPath, importer, aliasRules);
136
+ if (!resolved || !fs.existsSync(resolved)) return _match;
137
+ try {
138
+ const content = fs.readFileSync(resolved, "utf-8");
139
+ parseCustomMedia(content, customMedia);
140
+ return content;
141
+ } catch {
142
+ return _match;
143
+ }
144
+ });
145
+ parseCustomMedia(result, customMedia);
146
+ result = result.replace(/^@custom-media\s+[^;]+;\s*$/gm, "");
147
+ if (customMedia.size > 0) for (const [name, query] of customMedia) {
148
+ const escaped = name.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
149
+ result = result.replace(new RegExp(`\\(${escaped}\\)`, "g"), query);
150
+ }
151
+ if (isDev) result = result.replace(/url\(\s*(["']?)([^"')]+)\1\s*\)/g, (_match, quote, urlPath) => {
152
+ const trimmed = urlPath.trim();
153
+ if (trimmed.startsWith("data:") || trimmed.startsWith("http://") || trimmed.startsWith("https://") || trimmed.startsWith("/@fs/")) return _match;
154
+ const resolved = resolveCssPath(trimmed, importer, aliasRules);
155
+ if (resolved && fs.existsSync(resolved)) {
156
+ const normalized = resolved.replace(/\\/g, "/");
157
+ const base = devUrlBase ?? "/";
158
+ const prefix = base.endsWith("/") ? base : base + "/";
159
+ return `url("${prefix}@fs${normalized}")`;
160
+ }
161
+ return _match;
162
+ });
163
+ result = result.replace(/:deep\(([^()]*(?:\([^()]*\))*[^()]*)\)/g, "$1");
164
+ result = result.replace(/\n{3,}/g, "\n\n");
165
+ return result;
166
+ }
167
+ function parseCustomMedia(css, map) {
168
+ const re = /@custom-media\s+(--[\w-]+)\s+(.+?)\s*;/g;
169
+ let m;
170
+ while ((m = re.exec(css)) !== null) map.set(m[1], m[2]);
171
+ }
172
+ function resolveCssPath(importPath, importer, aliasRules) {
173
+ for (const rule of aliasRules) if (importPath.startsWith(rule.find)) {
174
+ const resolved = importPath.replace(rule.find, rule.replacement);
175
+ return path.resolve(resolved);
176
+ }
177
+ if (importPath.startsWith(".")) {
178
+ const dir = path.dirname(importer);
179
+ return path.resolve(dir, importPath);
180
+ }
181
+ if (path.isAbsolute(importPath)) return importPath;
182
+ return null;
183
+ }
121
184
 
122
185
  //#endregion
123
186
  //#region src/compiler.ts
@@ -323,18 +386,61 @@ function createLogger(debug) {
323
386
  error: (...args) => console.error("[vize]", ...args)
324
387
  };
325
388
  }
389
+ /**
390
+ * Built-in Vite/Vue/Nuxt define keys that are handled by Vite's own transform pipeline.
391
+ * These must NOT be replaced by the vize plugin because:
392
+ * 1. Nuxt runs both client and server Vite builds, each with different values
393
+ * (e.g., import.meta.server = true on server, false on client).
394
+ * 2. Vite's import.meta transform already handles these correctly per-environment.
395
+ */
396
+ const BUILTIN_DEFINE_PREFIXES = [
397
+ "import.meta.server",
398
+ "import.meta.client",
399
+ "import.meta.dev",
400
+ "import.meta.test",
401
+ "import.meta.prerender",
402
+ "import.meta.env",
403
+ "import.meta.hot",
404
+ "__VUE_",
405
+ "__NUXT_",
406
+ "process.env"
407
+ ];
408
+ function isBuiltinDefine(key) {
409
+ return BUILTIN_DEFINE_PREFIXES.some((prefix) => key === prefix || key.startsWith(prefix + ".") || key.startsWith(prefix + "_"));
410
+ }
411
+ /**
412
+ * Apply Vite define replacements to code.
413
+ * Replaces keys like `import.meta.vfFeatures.photoSection` with their values.
414
+ * Uses word-boundary-aware matching to avoid replacing inside strings or partial matches.
415
+ */
416
+ function applyDefineReplacements(code, defines) {
417
+ const sortedKeys = Object.keys(defines).sort((a, b) => b.length - a.length);
418
+ let result = code;
419
+ for (const key of sortedKeys) {
420
+ if (!result.includes(key)) continue;
421
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
422
+ const re = new RegExp(escaped + "(?![\\w$.])", "g");
423
+ result = result.replace(re, defines[key]);
424
+ }
425
+ return result;
426
+ }
326
427
  function vize(options = {}) {
327
428
  const cache = new Map();
328
429
  const collectedCss = new Map();
329
430
  let isProduction;
330
431
  let root;
432
+ let clientViteBase = "/";
433
+ let serverViteBase = "/";
331
434
  let server = null;
332
435
  let filter;
333
436
  let scanPatterns;
334
437
  let ignorePatterns;
335
438
  let mergedOptions;
336
439
  let dynamicImportAliasRules = [];
440
+ let cssAliasRules = [];
337
441
  let extractCss = false;
442
+ let clientViteDefine = {};
443
+ let serverViteDefine = {};
338
444
  const logger = createLogger(options.debug ?? false);
339
445
  async function compileAll() {
340
446
  const startTime = performance.now();
@@ -356,7 +462,7 @@ function vize(options = {}) {
356
462
  }
357
463
  const result = compileBatch(fileContents, cache, { ssr: mergedOptions.ssr ?? false });
358
464
  if (isProduction) {
359
- for (const fileResult of result.results) if (fileResult.css) collectedCss.set(fileResult.path, fileResult.css);
465
+ for (const fileResult of result.results) if (fileResult.css) collectedCss.set(fileResult.path, resolveCssImports(fileResult.css, fileResult.path, cssAliasRules, false));
360
466
  }
361
467
  const elapsed = (performance.now() - startTime).toFixed(2);
362
468
  logger.info(`Pre-compilation complete: ${result.successCount} succeeded, ${result.failedCount} failed (${elapsed}ms, native batch: ${result.timeMs.toFixed(2)}ms)`);
@@ -386,15 +492,6 @@ function vize(options = {}) {
386
492
  optimizeDeps: {
387
493
  include: ["vue"],
388
494
  exclude: ["virtual:vize-styles"],
389
- esbuildOptions: { plugins: [{
390
- name: "vize-externalize-vue",
391
- setup(build) {
392
- build.onResolve({ filter: /\.vue$/ }, (args) => ({
393
- path: args.path,
394
- external: true
395
- }));
396
- }
397
- }] },
398
495
  rolldownOptions: { external: [/\.vue$/] }
399
496
  }
400
497
  };
@@ -402,7 +499,19 @@ function vize(options = {}) {
402
499
  async configResolved(resolvedConfig) {
403
500
  root = options.root ?? resolvedConfig.root;
404
501
  isProduction = options.isProduction ?? resolvedConfig.isProduction;
502
+ const isSsrBuild = !!resolvedConfig.build?.ssr;
503
+ if (isSsrBuild) serverViteBase = resolvedConfig.base ?? "/";
504
+ else clientViteBase = resolvedConfig.base ?? "/";
405
505
  extractCss = isProduction;
506
+ const isSsr = !!resolvedConfig.build?.ssr;
507
+ const envDefine = {};
508
+ if (resolvedConfig.define) for (const [key, value] of Object.entries(resolvedConfig.define)) {
509
+ if (isBuiltinDefine(key)) continue;
510
+ if (typeof value === "string") envDefine[key] = value;
511
+ else envDefine[key] = JSON.stringify(value);
512
+ }
513
+ if (isSsr) serverViteDefine = envDefine;
514
+ else clientViteDefine = envDefine;
406
515
  const configEnv = {
407
516
  mode: resolvedConfig.mode,
408
517
  command: resolvedConfig.command === "build" ? "build" : "serve",
@@ -444,6 +553,15 @@ function vize(options = {}) {
444
553
  });
445
554
  }
446
555
  dynamicImportAliasRules.sort((a, b) => b.fromPrefix.length - a.fromPrefix.length);
556
+ cssAliasRules = [];
557
+ for (const alias of resolvedConfig.resolve.alias) {
558
+ if (typeof alias.find !== "string" || typeof alias.replacement !== "string") continue;
559
+ cssAliasRules.push({
560
+ find: alias.find,
561
+ replacement: alias.replacement
562
+ });
563
+ }
564
+ cssAliasRules.sort((a, b) => b.find.length - a.find.length);
447
565
  filter = createFilter(mergedOptions.include, mergedOptions.exclude);
448
566
  scanPatterns = mergedOptions.scanPatterns ?? ["**/*.vue"];
449
567
  ignorePatterns = mergedOptions.ignorePatterns ?? [
@@ -604,7 +722,8 @@ function vize(options = {}) {
604
722
  }
605
723
  return null;
606
724
  },
607
- load(id) {
725
+ load(id, loadOptions) {
726
+ const currentBase = loadOptions?.ssr ? serverViteBase : clientViteBase;
608
727
  if (id === RESOLVED_CSS_MODULE) {
609
728
  const allCss = Array.from(collectedCss.values()).join("\n\n");
610
729
  return allCss;
@@ -613,7 +732,7 @@ function vize(options = {}) {
613
732
  const [filename] = id.split("?");
614
733
  const realPath = isVizeVirtual(filename) ? fromVirtualId(filename) : filename;
615
734
  const compiled = cache.get(realPath);
616
- if (compiled?.css) return compiled.css;
735
+ if (compiled?.css) return resolveCssImports(compiled.css, realPath, cssAliasRules, server !== null, currentBase);
617
736
  return "";
618
737
  }
619
738
  if (isVizeVirtual(id)) {
@@ -631,6 +750,10 @@ function vize(options = {}) {
631
750
  });
632
751
  }
633
752
  if (compiled) {
753
+ if (compiled.css) compiled = {
754
+ ...compiled,
755
+ css: resolveCssImports(compiled.css, realPath, cssAliasRules, server !== null, currentBase)
756
+ };
634
757
  const output = rewriteStaticAssetUrls(rewriteDynamicTemplateImports(generateOutput(compiled, {
635
758
  isProduction,
636
759
  isDev: server !== null,
@@ -656,13 +779,16 @@ function vize(options = {}) {
656
779
  }
657
780
  return null;
658
781
  },
659
- async transform(code, id) {
782
+ async transform(code, id, options$1) {
660
783
  if (isVizeVirtual(id)) {
661
784
  const realPath = fromVirtualId(id);
662
785
  try {
663
786
  const result = await transformWithOxc(code, realPath, { lang: "ts" });
787
+ const defines = options$1?.ssr ? serverViteDefine : clientViteDefine;
788
+ let transformed = result.code;
789
+ if (Object.keys(defines).length > 0) transformed = applyDefineReplacements(transformed, defines);
664
790
  return {
665
- code: result.code,
791
+ code: transformed,
666
792
  map: result.map
667
793
  };
668
794
  } catch (e) {
@@ -699,7 +825,7 @@ function vize(options = {}) {
699
825
  data: {
700
826
  id: newCompiled.scopeId,
701
827
  type: "style-only",
702
- css: newCompiled.css
828
+ css: resolveCssImports(newCompiled.css, file, cssAliasRules, true, clientViteBase)
703
829
  }
704
830
  });
705
831
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/vite-plugin",
3
- "version": "0.0.1-alpha.102",
3
+ "version": "0.0.1-alpha.104",
4
4
  "description": "High-performance native Vite plugin for Vue SFC compilation powered by Vize",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "tinyglobby": "^0.2.0",
46
- "@vizejs/native": "0.0.1-alpha.102"
46
+ "@vizejs/native": "0.0.1-alpha.104"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "tsdown",