@nasti-toolchain/nasti 2.4.0 → 2.4.2

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/cli.js CHANGED
@@ -189,7 +189,10 @@ var init_defaults = __esm({
189
189
  target: "es2022",
190
190
  rolldownOptions: {},
191
191
  emptyOutDir: true,
192
- css: {},
192
+ css: {
193
+ inject: true,
194
+ emit: true
195
+ },
193
196
  reportCompressedSize: true,
194
197
  chunkSizeWarningLimit: 500,
195
198
  cssCodeSplit: true,
@@ -428,7 +431,11 @@ async function resolveConfig(inlineConfig = {}, command) {
428
431
  allowClearScreen: clearScreen2,
429
432
  customLogger: merged.customLogger
430
433
  });
431
- const mergedBuild = { ...defaults.build, ...merged.build };
434
+ const mergedBuild = {
435
+ ...defaults.build,
436
+ ...merged.build,
437
+ css: { ...defaults.build.css, ...merged.build?.css }
438
+ };
432
439
  if (merged.build?.cssMinify === void 0) {
433
440
  mergedBuild.cssMinify = !!mergedBuild.minify;
434
441
  }
@@ -459,11 +466,17 @@ async function resolveConfig(inlineConfig = {}, command) {
459
466
  bundledDev: merged.experimental?.bundledDev ?? defaults.experimental.bundledDev
460
467
  }
461
468
  };
462
- const userEnvironments = {
469
+ const rawUserEnvironments = {
463
470
  client: {},
464
471
  ssr: {},
465
472
  ...merged.environments ?? {}
466
473
  };
474
+ const userEnvironments = Object.fromEntries(
475
+ Object.entries(rawUserEnvironments).map(([name, options]) => [
476
+ name,
477
+ deepMerge({}, options)
478
+ ])
479
+ );
467
480
  for (const [name, envOptions] of Object.entries(userEnvironments)) {
468
481
  for (const plugin of rawPlugins) {
469
482
  if (plugin.configEnvironment) {
@@ -474,6 +487,7 @@ async function resolveConfig(inlineConfig = {}, command) {
474
487
  }
475
488
  for (const [name, envOptions] of Object.entries(userEnvironments)) {
476
489
  const consumer = envOptions.consumer ?? (name === "client" ? "client" : "server");
490
+ const vueOptions = deepMerge({}, envOptions.vue ?? {});
477
491
  if (name === "client") {
478
492
  if (envOptions.resolve) {
479
493
  Object.assign(resolved.resolve, {
@@ -481,7 +495,11 @@ async function resolveConfig(inlineConfig = {}, command) {
481
495
  alias: { ...resolved.resolve.alias, ...envOptions.resolve.alias }
482
496
  });
483
497
  }
484
- if (envOptions.build) Object.assign(resolved.build, envOptions.build);
498
+ if (envOptions.build) {
499
+ const { css, ...environmentBuild } = envOptions.build;
500
+ Object.assign(resolved.build, environmentBuild);
501
+ if (css) resolved.build.css = { ...resolved.build.css, ...css };
502
+ }
485
503
  resolved.environments.client = {
486
504
  consumer,
487
505
  buildEnabled: envOptions.buildEnabled ?? true,
@@ -493,7 +511,8 @@ async function resolveConfig(inlineConfig = {}, command) {
493
511
  driver: envOptions.driver,
494
512
  // 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
495
513
  resolve: resolved.resolve,
496
- build: resolved.build
514
+ build: resolved.build,
515
+ vue: vueOptions
497
516
  };
498
517
  continue;
499
518
  }
@@ -503,6 +522,7 @@ async function resolveConfig(inlineConfig = {}, command) {
503
522
  entry: normalizeEnvironmentEntries(envOptions.entry, root),
504
523
  html: envOptions.consumer === "client" && envOptions.html ? path.resolve(root, envOptions.html) : void 0,
505
524
  driver: envOptions.driver,
525
+ vue: vueOptions,
506
526
  resolve: {
507
527
  alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
508
528
  extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
@@ -513,6 +533,7 @@ async function resolveConfig(inlineConfig = {}, command) {
513
533
  build: {
514
534
  ...resolved.build,
515
535
  ...envOptions.build,
536
+ css: { ...resolved.build.css, ...envOptions.build?.css },
516
537
  // 非 client 环境默认产出到 <outDir>/<envName>(如 dist/ssr),可显式覆盖
517
538
  outDir: envOptions.build?.outDir ?? path.join(resolved.build.outDir, name),
518
539
  // server 产物默认不压缩(可调试性优先,与 Vite SSR 默认一致),可显式覆盖
@@ -756,17 +777,23 @@ var init_plugin_container = __esm({
756
777
  }
757
778
  async transform(code, id) {
758
779
  let currentCode = code;
780
+ let lastResult;
759
781
  for (const plugin of this.plugins) {
760
782
  if (!plugin.transform) continue;
761
783
  const result = await plugin.transform.call(this.ctx, currentCode, id);
762
784
  if (result == null) continue;
763
785
  if (typeof result === "string") {
764
786
  currentCode = result;
787
+ lastResult = void 0;
765
788
  } else {
766
789
  currentCode = result.code;
790
+ lastResult = result;
767
791
  }
768
792
  }
769
- return currentCode === code ? null : { code: currentCode };
793
+ return currentCode === code ? null : {
794
+ ...lastResult,
795
+ code: currentCode
796
+ };
770
797
  }
771
798
  /** 完整的模块处理管道: resolveId → load → transform */
772
799
  async processModule(source, importer) {
@@ -813,9 +840,13 @@ var init_module_graph = __esm({
813
840
  "use strict";
814
841
  init_url();
815
842
  ModuleGraph = class {
843
+ environmentName;
816
844
  urlToModuleMap = /* @__PURE__ */ new Map();
817
845
  idToModuleMap = /* @__PURE__ */ new Map();
818
846
  fileToModulesMap = /* @__PURE__ */ new Map();
847
+ constructor(environmentName = "client") {
848
+ this.environmentName = environmentName;
849
+ }
819
850
  getModuleByUrl(url) {
820
851
  return this.urlToModuleMap.get(removeTimestampQuery(url));
821
852
  }
@@ -845,7 +876,8 @@ var init_module_graph = __esm({
845
876
  transformResult: null,
846
877
  lastHMRTimestamp: 0,
847
878
  invalidationVersion: 0,
848
- isSelfAccepting: false
879
+ isSelfAccepting: false,
880
+ environment: this.environmentName
849
881
  };
850
882
  this.idToModuleMap.set(mod.id, mod);
851
883
  return mod;
@@ -1003,12 +1035,12 @@ function createNoopHotChannel() {
1003
1035
  }
1004
1036
  };
1005
1037
  }
1006
- function createWsHotChannel(ws) {
1038
+ function createWsHotChannel(ws, environmentName = "client") {
1007
1039
  const listeners = /* @__PURE__ */ new Map();
1008
1040
  let invokeHandlers;
1009
1041
  return {
1010
1042
  send(payload) {
1011
- ws.send(payload);
1043
+ ws.send({ ...payload, environment: payload.environment ?? environmentName });
1012
1044
  },
1013
1045
  on(event, listener) {
1014
1046
  let set = listeners.get(event);
@@ -1020,8 +1052,8 @@ function createWsHotChannel(ws) {
1020
1052
  },
1021
1053
  listen() {
1022
1054
  },
1055
+ // 多个 environment 共享底层 WebSocket server;它由 DevServer.close() 统一关闭。
1023
1056
  close() {
1024
- ws.close();
1025
1057
  },
1026
1058
  setInvokeHandler(handlers) {
1027
1059
  invokeHandlers = handlers;
@@ -1120,6 +1152,9 @@ var init_environment = __esm({
1120
1152
  candidatePlugins;
1121
1153
  pluginApi;
1122
1154
  buildMetadata = {};
1155
+ cssModules = /* @__PURE__ */ new Map();
1156
+ assetModules = /* @__PURE__ */ new Map();
1157
+ transformRequestHandler;
1123
1158
  initialized = false;
1124
1159
  constructor(name, config, init = {}) {
1125
1160
  const options = config.environments[name];
@@ -1134,7 +1169,7 @@ var init_environment = __esm({
1134
1169
  this.config = config;
1135
1170
  this.options = options;
1136
1171
  this.hot = init.hot ?? createNoopHotChannel();
1137
- this.moduleGraph = new ModuleGraph();
1172
+ this.moduleGraph = new ModuleGraph(name);
1138
1173
  this.candidatePlugins = init.plugins ?? config.plugins;
1139
1174
  this.pluginApi = init.pluginApi ?? getPluginApi(config);
1140
1175
  }
@@ -1176,6 +1211,37 @@ var init_environment = __esm({
1176
1211
  logger: this.config.logger
1177
1212
  };
1178
1213
  }
1214
+ configureDevPipeline(transformRequest2) {
1215
+ this.transformRequestHandler = transformRequest2;
1216
+ }
1217
+ async transformRequest(url) {
1218
+ if (!this.transformRequestHandler) {
1219
+ throw new Error(
1220
+ `[nasti] environment "${this.name}" does not have an initialized dev transform pipeline`
1221
+ );
1222
+ }
1223
+ return this.transformRequestHandler(url);
1224
+ }
1225
+ setCssModule(module) {
1226
+ this.cssModules.set(module.id, { ...module });
1227
+ }
1228
+ getCssModule(id) {
1229
+ const module = this.cssModules.get(id);
1230
+ return module ? { ...module } : void 0;
1231
+ }
1232
+ getCssModules() {
1233
+ return Object.freeze(
1234
+ Object.fromEntries(
1235
+ [...this.cssModules].map(([id, module]) => [id, { ...module }])
1236
+ )
1237
+ );
1238
+ }
1239
+ setAssetModule(id, fileName) {
1240
+ this.assetModules.set(id, fileName);
1241
+ }
1242
+ getAssetModules() {
1243
+ return Object.freeze(Object.fromEntries(this.assetModules));
1244
+ }
1179
1245
  setBuildMetadata(metadata) {
1180
1246
  const { entries: currentEntries, ...currentMetadata } = this.buildMetadata;
1181
1247
  const { entries, ...nextMetadata } = metadata;
@@ -1432,16 +1498,97 @@ var init_env = __esm({
1432
1498
  }
1433
1499
  });
1434
1500
 
1435
- // src/server/middleware.ts
1436
- var middleware_exports = {};
1437
- __export(middleware_exports, {
1438
- REACT_REFRESH_GLOBAL_PREAMBLE: () => REACT_REFRESH_GLOBAL_PREAMBLE,
1439
- getReactRefreshRuntimeEsm: () => getReactRefreshRuntimeEsm,
1440
- transformMiddleware: () => transformMiddleware,
1441
- transformRequest: () => transformRequest
1442
- });
1501
+ // src/plugins/assets.ts
1443
1502
  import path4 from "path";
1444
1503
  import fs4 from "fs";
1504
+ import crypto from "crypto";
1505
+ function assetsPlugin(config) {
1506
+ const emittedAssets = /* @__PURE__ */ new Set();
1507
+ return {
1508
+ name: "nasti:assets",
1509
+ resolveId(source) {
1510
+ if (source.endsWith("?url") || source.endsWith("?raw")) {
1511
+ return source;
1512
+ }
1513
+ return null;
1514
+ },
1515
+ load(id) {
1516
+ const ext = path4.extname(id.replace(/\?.*$/, ""));
1517
+ if (id.endsWith("?raw")) {
1518
+ const file = id.slice(0, -4);
1519
+ if (fs4.existsSync(file)) {
1520
+ const content = fs4.readFileSync(file, "utf-8");
1521
+ return `export default ${JSON.stringify(content)}`;
1522
+ }
1523
+ }
1524
+ if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
1525
+ const file = id.replace(/\?.*$/, "");
1526
+ if (!fs4.existsSync(file)) return null;
1527
+ if (config.command === "serve") {
1528
+ const url = "/" + path4.relative(config.root, file);
1529
+ return `export default ${JSON.stringify(url)}`;
1530
+ }
1531
+ const content = fs4.readFileSync(file);
1532
+ const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
1533
+ const basename = path4.basename(file, ext);
1534
+ const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
1535
+ const environment = this.environment;
1536
+ if (!environment) {
1537
+ throw new Error("[nasti:assets] build environment is not initialized");
1538
+ }
1539
+ if (!emittedAssets.has(hashedName)) {
1540
+ this.emitFile({
1541
+ type: "asset",
1542
+ fileName: hashedName,
1543
+ source: content
1544
+ });
1545
+ emittedAssets.add(hashedName);
1546
+ }
1547
+ environment.setAssetModule(file, hashedName);
1548
+ return `export default ${JSON.stringify(config.base + hashedName)}`;
1549
+ }
1550
+ return null;
1551
+ }
1552
+ };
1553
+ }
1554
+ function isAssetFile(id) {
1555
+ const ext = path4.extname(id.replace(/\?.*$/, ""));
1556
+ return ASSET_EXTENSIONS.has(ext);
1557
+ }
1558
+ var ASSET_EXTENSIONS;
1559
+ var init_assets = __esm({
1560
+ "src/plugins/assets.ts"() {
1561
+ "use strict";
1562
+ ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
1563
+ ".png",
1564
+ ".jpg",
1565
+ ".jpeg",
1566
+ ".gif",
1567
+ ".svg",
1568
+ ".ico",
1569
+ ".webp",
1570
+ ".avif",
1571
+ ".mp4",
1572
+ ".webm",
1573
+ ".ogg",
1574
+ ".mp3",
1575
+ ".wav",
1576
+ ".flac",
1577
+ ".aac",
1578
+ ".woff",
1579
+ ".woff2",
1580
+ ".eot",
1581
+ ".ttf",
1582
+ ".otf",
1583
+ ".pdf",
1584
+ ".txt"
1585
+ ]);
1586
+ }
1587
+ });
1588
+
1589
+ // src/server/middleware.ts
1590
+ import path5 from "path";
1591
+ import fs5 from "fs";
1445
1592
  import { createRequire } from "module";
1446
1593
  import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
1447
1594
  import pc3 from "picocolors";
@@ -1452,10 +1599,10 @@ function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
1452
1599
  let cjsPath;
1453
1600
  try {
1454
1601
  const pkgPath = __require2.resolve("react-refresh/package.json");
1455
- cjsPath = path4.join(path4.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
1602
+ cjsPath = path5.join(path5.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
1456
1603
  } catch (err) {
1457
- cjsPath = path4.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
1458
- if (!fs4.existsSync(cjsPath)) {
1604
+ cjsPath = path5.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
1605
+ if (!fs5.existsSync(cjsPath)) {
1459
1606
  const origMsg = err instanceof Error ? err.message : String(err);
1460
1607
  throw new Error(
1461
1608
  `[nasti] Missing dependency "react-refresh". Install it with: npm install react-refresh
@@ -1463,7 +1610,7 @@ Original resolve error: ${origMsg}`
1463
1610
  );
1464
1611
  }
1465
1612
  }
1466
- const cjsSource = fs4.readFileSync(cjsPath, "utf-8");
1613
+ const cjsSource = fs5.readFileSync(cjsPath, "utf-8");
1467
1614
  __refreshRuntimeCache = `// Wrapped react-refresh runtime -> ESM
1468
1615
  const exports = {};
1469
1616
  const module = { exports };
@@ -1547,7 +1694,8 @@ const __nasti_hot__ = __nasti_createHotContext__(${urlLit});
1547
1694
  function transformMiddleware(ctx) {
1548
1695
  ctx.envDefine = buildEnvDefine(
1549
1696
  loadEnv(ctx.config.mode, ctx.config.root, ctx.config.envPrefix),
1550
- ctx.config.mode
1697
+ ctx.config.mode,
1698
+ ssrDefineOverrides(ctx.environment?.consumer ?? "client")
1551
1699
  );
1552
1700
  return async (req, res, next) => {
1553
1701
  const url = req.url ?? "/";
@@ -1592,7 +1740,7 @@ function transformMiddleware(ctx) {
1592
1740
  return;
1593
1741
  }
1594
1742
  }
1595
- if (isModuleRequest(url)) {
1743
+ if (isModuleRequest(url, req.headers["sec-fetch-dest"])) {
1596
1744
  try {
1597
1745
  const result = await transformRequest(url, ctx);
1598
1746
  if (result) {
@@ -1633,8 +1781,8 @@ async function transformRequest(url, ctx) {
1633
1781
  let realIdValid = false;
1634
1782
  try {
1635
1783
  if (idParam) {
1636
- realId = fs4.realpathSync(idParam);
1637
- realIdValid = fs4.statSync(realId).isFile() && (realId.includes(`${path4.sep}node_modules${path4.sep}`) || isUnderRoot(realId, config.root));
1784
+ realId = fs5.realpathSync(idParam);
1785
+ realIdValid = fs5.statSync(realId).isFile() && (realId.includes(`${path5.sep}node_modules${path5.sep}`) || isUnderRoot(realId, config.root));
1638
1786
  }
1639
1787
  } catch {
1640
1788
  realId = null;
@@ -1663,12 +1811,16 @@ async function transformRequest(url, ctx) {
1663
1811
  if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
1664
1812
  const mod2 = await moduleGraph.ensureEntryFromUrl(url);
1665
1813
  const transformVersion2 = mod2.invalidationVersion;
1666
- const loaded = await pluginContainer.load(url);
1667
- if (loaded != null) {
1668
- let code2 = typeof loaded === "string" ? loaded : loaded.code;
1814
+ const loaded2 = await pluginContainer.load(url);
1815
+ if (loaded2 != null) {
1816
+ let code2 = typeof loaded2 === "string" ? loaded2 : loaded2.code;
1817
+ let map2 = typeof loaded2 === "string" ? void 0 : loaded2.map;
1669
1818
  const transformed = await pluginContainer.transform(code2, url);
1670
1819
  if (transformed != null) {
1671
1820
  code2 = typeof transformed === "string" ? transformed : transformed.code;
1821
+ if (typeof transformed !== "string" && transformed.map != null) {
1822
+ map2 = transformed.map;
1823
+ }
1672
1824
  }
1673
1825
  const parentFile = resolveUrlToFile(cleanReqUrl, config.root) ?? cleanReqUrl;
1674
1826
  moduleGraph.registerModule(mod2, parentFile);
@@ -1676,7 +1828,8 @@ async function transformRequest(url, ctx) {
1676
1828
  code2 = injectImportMetaHot(hotInfo2.code, url);
1677
1829
  code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
1678
1830
  loadEnv(config.mode, config.root, config.envPrefix),
1679
- config.mode
1831
+ config.mode,
1832
+ ssrDefineOverrides(ctx.environment?.consumer ?? "client")
1680
1833
  ));
1681
1834
  const importedUrls2 = /* @__PURE__ */ new Set();
1682
1835
  code2 = rewriteImports(code2, config, parentFile, importedUrls2, moduleGraph);
@@ -1687,7 +1840,7 @@ async function transformRequest(url, ctx) {
1687
1840
  hotInfo2.isSelfAccepting,
1688
1841
  transformVersion2
1689
1842
  );
1690
- const transformResult2 = { code: code2 };
1843
+ const transformResult2 = { code: code2, map: map2 };
1691
1844
  if (pruned2) {
1692
1845
  if (pruned2.size > 0) ctx.onPrune?.([...pruned2].map((item) => item.url));
1693
1846
  mod2.transformResult = transformResult2;
@@ -1696,7 +1849,7 @@ async function transformRequest(url, ctx) {
1696
1849
  }
1697
1850
  }
1698
1851
  const filePath = resolveUrlToFile(url, config.root);
1699
- if (!filePath || !fs4.existsSync(filePath)) return null;
1852
+ if (!filePath || !fs5.existsSync(filePath)) return null;
1700
1853
  const mod = await moduleGraph.ensureEntryFromUrl(url);
1701
1854
  moduleGraph.registerModule(mod, filePath);
1702
1855
  const transformVersion = mod.invalidationVersion;
@@ -1706,10 +1859,13 @@ async function transformRequest(url, ctx) {
1706
1859
  mod.transformResult = transformResult2;
1707
1860
  return transformResult2;
1708
1861
  }
1709
- let code = fs4.readFileSync(filePath, "utf-8");
1862
+ const loaded = await pluginContainer.load(filePath);
1863
+ let code = loaded == null ? fs5.readFileSync(filePath, "utf-8") : typeof loaded === "string" ? loaded : loaded.code;
1864
+ let map = loaded && typeof loaded !== "string" ? loaded.map : void 0;
1710
1865
  const pluginResult = await pluginContainer.transform(code, filePath);
1711
1866
  if (pluginResult) {
1712
1867
  code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
1868
+ if (typeof pluginResult !== "string") map = pluginResult.map;
1713
1869
  }
1714
1870
  const stableUrl = cleanReqUrl;
1715
1871
  let wrappedWithRefresh = false;
@@ -1720,9 +1876,11 @@ async function transformRequest(url, ctx) {
1720
1876
  sourcemap: true,
1721
1877
  jsxRuntime: "automatic",
1722
1878
  jsxImportSource: config.framework === "vue" ? "vue" : "react",
1723
- reactRefresh: useRefresh
1879
+ reactRefresh: useRefresh,
1880
+ target: ctx.environment?.options.build.target ?? config.build.target
1724
1881
  });
1725
1882
  code = result.code;
1883
+ if (result.map) map = JSON.parse(result.map);
1726
1884
  if (useRefresh) {
1727
1885
  code = buildReactRefreshWrapper(stableUrl, code);
1728
1886
  wrappedWithRefresh = true;
@@ -1735,7 +1893,8 @@ async function transformRequest(url, ctx) {
1735
1893
  }
1736
1894
  const envDefine = ctx.envDefine ?? buildEnvDefine(
1737
1895
  loadEnv(config.mode, config.root, config.envPrefix),
1738
- config.mode
1896
+ config.mode,
1897
+ ssrDefineOverrides(ctx.environment?.consumer ?? "client")
1739
1898
  );
1740
1899
  code = replaceEnvInCode(code, envDefine);
1741
1900
  const importedUrls = /* @__PURE__ */ new Set();
@@ -1747,7 +1906,7 @@ async function transformRequest(url, ctx) {
1747
1906
  wrappedWithRefresh || hotInfo.isSelfAccepting,
1748
1907
  transformVersion
1749
1908
  );
1750
- const transformResult = { code };
1909
+ const transformResult = { code, map };
1751
1910
  if (pruned) {
1752
1911
  if (pruned.size > 0) ctx.onPrune?.([...pruned].map((item) => item.url));
1753
1912
  mod.transformResult = transformResult;
@@ -1759,7 +1918,7 @@ async function loadVirtualModule(spec, ctx) {
1759
1918
  const resolved = await pluginContainer.resolveId(spec);
1760
1919
  if (resolved == null) return null;
1761
1920
  const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
1762
- const looksVirtual = resolvedId.startsWith("\0") || !fs4.existsSync(resolvedId);
1921
+ const looksVirtual = resolvedId.startsWith("\0") || !fs5.existsSync(resolvedId);
1763
1922
  if (!looksVirtual) return null;
1764
1923
  const loadResult = await pluginContainer.load(resolvedId);
1765
1924
  if (loadResult == null) return null;
@@ -1770,9 +1929,10 @@ async function loadVirtualModule(spec, ctx) {
1770
1929
  }
1771
1930
  code = replaceEnvInCode(code, ctx.envDefine ?? buildEnvDefine(
1772
1931
  loadEnv(config.mode, config.root, config.envPrefix),
1773
- config.mode
1932
+ config.mode,
1933
+ ssrDefineOverrides(ctx.environment?.consumer ?? "client")
1774
1934
  ));
1775
- const anchor = path4.join(config.root, "__nasti_virtual__.ts");
1935
+ const anchor = path5.join(config.root, "__nasti_virtual__.ts");
1776
1936
  code = rewriteImports(code, config, anchor);
1777
1937
  return { id: resolvedId, result: { code } };
1778
1938
  }
@@ -1798,7 +1958,7 @@ async function doBundlePackage(entryFile, root) {
1798
1958
  await bundle2.close();
1799
1959
  let code = result.output[0].code;
1800
1960
  code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
1801
- const externalBaseDir = path4.dirname(entryFile);
1961
+ const externalBaseDir = path5.dirname(entryFile);
1802
1962
  code = code.replace(
1803
1963
  /^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
1804
1964
  (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir, root)}${q}`
@@ -1816,16 +1976,16 @@ async function doBundlePackage(entryFile, root) {
1816
1976
  return code;
1817
1977
  }
1818
1978
  async function tryGenerateSubpathShim(entryFile, root) {
1819
- const NM = `${path4.sep}node_modules${path4.sep}`;
1979
+ const NM = `${path5.sep}node_modules${path5.sep}`;
1820
1980
  if (!entryFile.includes(NM)) return null;
1821
1981
  let pkgDir = null;
1822
1982
  let pkgName = null;
1823
- let dir = path4.dirname(entryFile);
1983
+ let dir = path5.dirname(entryFile);
1824
1984
  while (true) {
1825
- const pkgJsonPath = path4.join(dir, "package.json");
1826
- if (fs4.existsSync(pkgJsonPath)) {
1985
+ const pkgJsonPath = path5.join(dir, "package.json");
1986
+ if (fs5.existsSync(pkgJsonPath)) {
1827
1987
  try {
1828
- const pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
1988
+ const pkg = JSON.parse(fs5.readFileSync(pkgJsonPath, "utf-8"));
1829
1989
  if (typeof pkg?.name === "string" && pkg.name) {
1830
1990
  pkgDir = dir;
1831
1991
  pkgName = pkg.name;
@@ -1834,16 +1994,16 @@ async function tryGenerateSubpathShim(entryFile, root) {
1834
1994
  } catch {
1835
1995
  }
1836
1996
  }
1837
- const parent = path4.dirname(dir);
1997
+ const parent = path5.dirname(dir);
1838
1998
  if (parent === dir) return null;
1839
1999
  dir = parent;
1840
2000
  if (!dir.includes(NM)) return null;
1841
2001
  }
1842
2002
  if (!pkgDir || !pkgName) return null;
1843
- const entryExt = path4.extname(entryFile);
2003
+ const entryExt = path5.extname(entryFile);
1844
2004
  const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
1845
2005
  if (!mainEntry) return null;
1846
- if (path4.resolve(mainEntry) === path4.resolve(entryFile)) return null;
2006
+ if (path5.resolve(mainEntry) === path5.resolve(entryFile)) return null;
1847
2007
  let mainNs;
1848
2008
  let subNs;
1849
2009
  try {
@@ -1867,7 +2027,7 @@ async function tryGenerateSubpathShim(entryFile, root) {
1867
2027
  if (mainNs["default"] !== subNs["default"]) return null;
1868
2028
  }
1869
2029
  const rootMain = resolveNodeModule(root, pkgName);
1870
- const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + path4.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
2030
+ const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + path5.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
1871
2031
  const lines = [
1872
2032
  `// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
1873
2033
  `import * as __pkg from "${mainEntryUrl}";`
@@ -1881,10 +2041,10 @@ async function tryGenerateSubpathShim(entryFile, root) {
1881
2041
  return lines.join("\n") + "\n";
1882
2042
  }
1883
2043
  function pickMainEntryByExtension(pkgDir, preferredExt) {
1884
- const pkgJsonPath = path4.join(pkgDir, "package.json");
2044
+ const pkgJsonPath = path5.join(pkgDir, "package.json");
1885
2045
  let pkg;
1886
2046
  try {
1887
- pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
2047
+ pkg = JSON.parse(fs5.readFileSync(pkgJsonPath, "utf-8"));
1888
2048
  } catch {
1889
2049
  return null;
1890
2050
  }
@@ -1903,14 +2063,14 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
1903
2063
  if (typeof pkg.module === "string") candidates.push(pkg.module);
1904
2064
  if (typeof pkg.main === "string") candidates.push(pkg.main);
1905
2065
  for (const cand of candidates) {
1906
- if (path4.extname(cand) === preferredExt) {
1907
- const full = path4.resolve(pkgDir, cand);
1908
- if (fs4.existsSync(full)) return full;
2066
+ if (path5.extname(cand) === preferredExt) {
2067
+ const full = path5.resolve(pkgDir, cand);
2068
+ if (fs5.existsSync(full)) return full;
1909
2069
  }
1910
2070
  }
1911
2071
  for (const cand of candidates) {
1912
- const full = path4.resolve(pkgDir, cand);
1913
- if (fs4.existsSync(full)) return full;
2072
+ const full = path5.resolve(pkgDir, cand);
2073
+ if (fs5.existsSync(full)) return full;
1914
2074
  }
1915
2075
  return null;
1916
2076
  }
@@ -1977,11 +2137,11 @@ function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
1977
2137
  }
1978
2138
  function createModuleSpecifierResolver(config, filePath) {
1979
2139
  const root = config.root;
1980
- const fileDir = path4.dirname(filePath);
2140
+ const fileDir = path5.dirname(filePath);
1981
2141
  const aliasEntries = Object.entries(config.resolve.alias).sort(
1982
2142
  ([a], [b]) => b.length - a.length
1983
2143
  );
1984
- const toRootUrl = (abs) => "/" + path4.relative(root, abs).replace(/\\/g, "/");
2144
+ const toRootUrl = (abs) => "/" + path5.relative(root, abs).replace(/\\/g, "/");
1985
2145
  return (specifier) => {
1986
2146
  const suffixMatch = specifier.match(/[?#].*$/);
1987
2147
  const suffix = suffixMatch ? suffixMatch[0] : "";
@@ -1990,17 +2150,17 @@ function createModuleSpecifierResolver(config, filePath) {
1990
2150
  if (baseSpec === key || baseSpec.startsWith(key + "/")) {
1991
2151
  const aliasBase = resolveAliasTarget(value, root);
1992
2152
  const sub = baseSpec.slice(key.length).replace(/^\//, "");
1993
- const target = sub ? path4.join(aliasBase, sub) : aliasBase;
2153
+ const target = sub ? path5.join(aliasBase, sub) : aliasBase;
1994
2154
  const resolved = tryResolveDiskPath(target);
1995
2155
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
1996
2156
  }
1997
2157
  }
1998
2158
  if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
1999
- const resolved = tryResolveDiskPath(path4.resolve(fileDir, baseSpec));
2159
+ const resolved = tryResolveDiskPath(path5.resolve(fileDir, baseSpec));
2000
2160
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
2001
2161
  }
2002
2162
  if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
2003
- const resolved = tryResolveDiskPath(path4.join(root, baseSpec.replace(/^\//, "")));
2163
+ const resolved = tryResolveDiskPath(path5.join(root, baseSpec.replace(/^\//, "")));
2004
2164
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
2005
2165
  }
2006
2166
  if (baseSpec.startsWith("/")) return specifier;
@@ -2154,27 +2314,27 @@ function maskStringsAndComments(code) {
2154
2314
  return masked.join("");
2155
2315
  }
2156
2316
  function resolveAliasTarget(value, root) {
2157
- if (path4.isAbsolute(value) && fs4.existsSync(value)) return value;
2158
- if (value.startsWith("/")) return path4.join(root, value.slice(1));
2159
- return path4.resolve(root, value);
2317
+ if (path5.isAbsolute(value) && fs5.existsSync(value)) return value;
2318
+ if (value.startsWith("/")) return path5.join(root, value.slice(1));
2319
+ return path5.resolve(root, value);
2160
2320
  }
2161
2321
  function tryResolveDiskPath(target) {
2162
- if (fs4.existsSync(target) && fs4.statSync(target).isFile()) return target;
2322
+ if (fs5.existsSync(target) && fs5.statSync(target).isFile()) return target;
2163
2323
  for (const ext of RESOLVE_EXTENSIONS) {
2164
2324
  const withExt = target + ext;
2165
- if (fs4.existsSync(withExt) && fs4.statSync(withExt).isFile()) return withExt;
2325
+ if (fs5.existsSync(withExt) && fs5.statSync(withExt).isFile()) return withExt;
2166
2326
  }
2167
- if (fs4.existsSync(target) && fs4.statSync(target).isDirectory()) {
2327
+ if (fs5.existsSync(target) && fs5.statSync(target).isDirectory()) {
2168
2328
  for (const ext of RESOLVE_EXTENSIONS) {
2169
- const idx = path4.join(target, "index" + ext);
2170
- if (fs4.existsSync(idx) && fs4.statSync(idx).isFile()) return idx;
2329
+ const idx = path5.join(target, "index" + ext);
2330
+ if (fs5.existsSync(idx) && fs5.statSync(idx).isFile()) return idx;
2171
2331
  }
2172
2332
  }
2173
2333
  return null;
2174
2334
  }
2175
2335
  function isUnderRoot(abs, root) {
2176
- const rel = path4.relative(root, abs);
2177
- return !!rel && !rel.startsWith("..") && !path4.isAbsolute(rel);
2336
+ const rel = path5.relative(root, abs);
2337
+ return !!rel && !rel.startsWith("..") && !path5.isAbsolute(rel);
2178
2338
  }
2179
2339
  function appendTimestampQuery(url, timestamp) {
2180
2340
  const hashIndex = url.indexOf("#");
@@ -2193,7 +2353,7 @@ function resolveNodeModule(baseDir, moduleName) {
2193
2353
  const resolved = resolveNodeModuleEntry(baseDir, moduleName);
2194
2354
  if (!resolved) return null;
2195
2355
  try {
2196
- return fs4.realpathSync(resolved);
2356
+ return fs5.realpathSync(resolved);
2197
2357
  } catch {
2198
2358
  return resolved;
2199
2359
  }
@@ -2213,21 +2373,21 @@ function resolveNodeModuleEntry(root, moduleName) {
2213
2373
  let pkgDir = null;
2214
2374
  let dir = root;
2215
2375
  for (; ; ) {
2216
- const candidate = path4.join(dir, "node_modules", pkgName);
2217
- if (fs4.existsSync(candidate)) {
2376
+ const candidate = path5.join(dir, "node_modules", pkgName);
2377
+ if (fs5.existsSync(candidate)) {
2218
2378
  pkgDir = candidate;
2219
2379
  break;
2220
2380
  }
2221
- const parent = path4.dirname(dir);
2381
+ const parent = path5.dirname(dir);
2222
2382
  if (parent === dir) break;
2223
2383
  dir = parent;
2224
2384
  }
2225
2385
  if (!pkgDir) return null;
2226
- const pkgJsonPath = path4.join(pkgDir, "package.json");
2227
- if (!fs4.existsSync(pkgJsonPath)) return null;
2386
+ const pkgJsonPath = path5.join(pkgDir, "package.json");
2387
+ if (!fs5.existsSync(pkgJsonPath)) return null;
2228
2388
  let pkg;
2229
2389
  try {
2230
- pkg = JSON.parse(fs4.readFileSync(pkgJsonPath, "utf-8"));
2390
+ pkg = JSON.parse(fs5.readFileSync(pkgJsonPath, "utf-8"));
2231
2391
  } catch {
2232
2392
  return null;
2233
2393
  }
@@ -2240,32 +2400,32 @@ function resolveNodeModuleEntry(root, moduleName) {
2240
2400
  const subDirs = [""];
2241
2401
  for (const field of ["module", "main"]) {
2242
2402
  if (typeof pkg[field] === "string") {
2243
- const dir2 = path4.dirname(pkg[field]);
2403
+ const dir2 = path5.dirname(pkg[field]);
2244
2404
  if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
2245
2405
  }
2246
2406
  }
2247
2407
  for (const dir2 of subDirs) {
2248
- const direct = path4.join(pkgDir, dir2, subpath);
2249
- if (fs4.existsSync(direct) && fs4.statSync(direct).isFile()) return direct;
2408
+ const direct = path5.join(pkgDir, dir2, subpath);
2409
+ if (fs5.existsSync(direct) && fs5.statSync(direct).isFile()) return direct;
2250
2410
  for (const ext of RESOLVE_EXTENSIONS) {
2251
- if (fs4.existsSync(direct + ext)) return direct + ext;
2411
+ if (fs5.existsSync(direct + ext)) return direct + ext;
2252
2412
  }
2253
2413
  }
2254
2414
  return null;
2255
2415
  }
2256
2416
  for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
2257
2417
  if (typeof pkg[field] === "string") {
2258
- const entry = path4.join(pkgDir, pkg[field]);
2259
- if (fs4.existsSync(entry)) return entry;
2418
+ const entry = path5.join(pkgDir, pkg[field]);
2419
+ if (fs5.existsSync(entry)) return entry;
2260
2420
  }
2261
2421
  }
2262
- const indexFallback = path4.join(pkgDir, "index.js");
2263
- if (fs4.existsSync(indexFallback)) return indexFallback;
2422
+ const indexFallback = path5.join(pkgDir, "index.js");
2423
+ if (fs5.existsSync(indexFallback)) return indexFallback;
2264
2424
  return null;
2265
2425
  }
2266
2426
  function resolvePackageExports(exports, key, pkgDir) {
2267
2427
  if (typeof exports === "string") {
2268
- return key === "." ? path4.join(pkgDir, exports) : null;
2428
+ return key === "." ? path5.join(pkgDir, exports) : null;
2269
2429
  }
2270
2430
  const entry = exports[key];
2271
2431
  if (entry === void 0) {
@@ -2277,7 +2437,7 @@ function resolvePackageExports(exports, key, pkgDir) {
2277
2437
  return resolveExportValue(entry, pkgDir);
2278
2438
  }
2279
2439
  function resolveExportValue(value, pkgDir) {
2280
- if (typeof value === "string") return path4.join(pkgDir, value);
2440
+ if (typeof value === "string") return path5.join(pkgDir, value);
2281
2441
  if (Array.isArray(value)) {
2282
2442
  for (const item of value) {
2283
2443
  const r = resolveExportValue(item, pkgDir);
@@ -2301,25 +2461,30 @@ function resolveUrlToFile(url, root) {
2301
2461
  const moduleName = cleanUrl.slice("/@modules/".length);
2302
2462
  return resolveNodeModule(root, moduleName);
2303
2463
  }
2304
- const filePath = path4.resolve(root, cleanUrl.replace(/^\//, ""));
2305
- if (fs4.existsSync(filePath) && fs4.statSync(filePath).isFile()) {
2464
+ const filePath = path5.resolve(root, cleanUrl.replace(/^\//, ""));
2465
+ if (fs5.existsSync(filePath) && fs5.statSync(filePath).isFile()) {
2306
2466
  return filePath;
2307
2467
  }
2308
2468
  for (const ext of RESOLVE_EXTENSIONS) {
2309
2469
  const withExt = filePath + ext;
2310
- if (fs4.existsSync(withExt)) return withExt;
2470
+ if (fs5.existsSync(withExt)) return withExt;
2311
2471
  }
2312
2472
  for (const ext of RESOLVE_EXTENSIONS) {
2313
- const indexFile = path4.join(filePath, "index" + ext);
2314
- if (fs4.existsSync(indexFile)) return indexFile;
2473
+ const indexFile = path5.join(filePath, "index" + ext);
2474
+ if (fs5.existsSync(indexFile)) return indexFile;
2315
2475
  }
2316
2476
  return null;
2317
2477
  }
2318
- function isModuleRequest(url) {
2478
+ function isModuleRequest(url, destination) {
2319
2479
  const cleanUrl = url.split("?")[0];
2320
2480
  if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
2321
2481
  if (cleanUrl.startsWith("/@modules/")) return true;
2322
- if (!path4.extname(cleanUrl)) return true;
2482
+ if (isAssetFile(cleanUrl)) {
2483
+ const query = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
2484
+ const isExplicitAssetModule = /(?:^|&)(?:url|raw)(?:&|$)/.test(query);
2485
+ return isExplicitAssetModule || destination === "script";
2486
+ }
2487
+ if (!path5.extname(cleanUrl)) return true;
2323
2488
  return false;
2324
2489
  }
2325
2490
  function getHmrClientCode() {
@@ -2331,11 +2496,15 @@ const hotModulesMap = new Map();
2331
2496
  const disposeMap = new Map();
2332
2497
  const pruneMap = new Map();
2333
2498
  const dataMap = new Map();
2499
+ const customListenersMap = new Map();
2334
2500
  let updateQueue = [];
2335
2501
  let pendingUpdateQueue = false;
2336
2502
 
2337
2503
  socket.addEventListener('message', async ({ data }) => {
2338
2504
  const payload = JSON.parse(data);
2505
+ // \u9ED8\u8BA4\u6D4F\u89C8\u5668 client \u53EA\u6D88\u8D39\u81EA\u5DF1\u7684 HMR \u6D88\u606F\uFF1Bnative/worker \u73AF\u5883\u901A\u8FC7\u5404\u81EA\u7684
2506
+ // HotChannel \u6216 app-level HMR \u534F\u8C03\u5668\u5904\u7406\u540C\u4E00 transport \u4E0A\u7684\u547D\u540D\u6D88\u606F\u3002
2507
+ if (payload.environment && payload.environment !== 'client') return;
2339
2508
  switch (payload.type) {
2340
2509
  case 'connected':
2341
2510
  console.debug('[nasti] connected.');
@@ -2368,8 +2537,24 @@ socket.addEventListener('message', async ({ data }) => {
2368
2537
  disposeMap.delete(path);
2369
2538
  pruneMap.delete(path);
2370
2539
  dataMap.delete(path);
2540
+ clearCustomListeners(path);
2371
2541
  }));
2372
2542
  break;
2543
+ case 'custom': {
2544
+ const listenersByOwner = customListenersMap.get(payload.event);
2545
+ if (!listenersByOwner) break;
2546
+ const results = await Promise.allSettled(
2547
+ [...listenersByOwner.values()]
2548
+ .flatMap((listeners) => [...listeners])
2549
+ .map((listener) => Promise.resolve().then(() => listener(payload.data)))
2550
+ );
2551
+ for (const result of results) {
2552
+ if (result.status === 'rejected') {
2553
+ console.error('[nasti] custom HMR event listener failed:', result.reason);
2554
+ }
2555
+ }
2556
+ break;
2557
+ }
2373
2558
  case 'error':
2374
2559
  console.error('[nasti] error:', payload.err.message);
2375
2560
  showErrorOverlay(payload.err);
@@ -2468,6 +2653,7 @@ export function createHotContext(ownerPath) {
2468
2653
  // \u6A21\u5757\u91CD\u65B0\u6267\u884C\u65F6\u4E22\u5F03\u65E7 accept \u56DE\u8C03\uFF0C\u4F46\u4FDD\u7559\u540C\u4E00\u4E2A hot.data \u5BF9\u8C61\u3002
2469
2654
  const existing = hotModulesMap.get(ownerPath);
2470
2655
  if (existing) existing.callbacks = [];
2656
+ clearCustomListeners(ownerPath);
2471
2657
 
2472
2658
  const acceptDeps = (deps, callback = () => {}) => {
2473
2659
  const mod = hotModulesMap.get(ownerPath) || { id: ownerPath, callbacks: [] };
@@ -2493,12 +2679,39 @@ export function createHotContext(ownerPath) {
2493
2679
  dispose(callback) {
2494
2680
  disposeMap.set(ownerPath, callback);
2495
2681
  },
2682
+ on(event, callback) {
2683
+ let listenersByOwner = customListenersMap.get(event);
2684
+ if (!listenersByOwner) {
2685
+ listenersByOwner = new Map();
2686
+ customListenersMap.set(event, listenersByOwner);
2687
+ }
2688
+ let listeners = listenersByOwner.get(ownerPath);
2689
+ if (!listeners) {
2690
+ listeners = new Set();
2691
+ listenersByOwner.set(ownerPath, listeners);
2692
+ }
2693
+ listeners.add(callback);
2694
+ },
2695
+ off(event, callback) {
2696
+ const listenersByOwner = customListenersMap.get(event);
2697
+ const listeners = listenersByOwner?.get(ownerPath);
2698
+ listeners?.delete(callback);
2699
+ if (listeners?.size === 0) listenersByOwner.delete(ownerPath);
2700
+ if (listenersByOwner?.size === 0) customListenersMap.delete(event);
2701
+ },
2496
2702
  invalidate() {
2497
2703
  location.reload();
2498
2704
  },
2499
2705
  data: dataMap.get(ownerPath),
2500
2706
  };
2501
2707
  }
2708
+
2709
+ function clearCustomListeners(ownerPath) {
2710
+ for (const [event, listenersByOwner] of customListenersMap) {
2711
+ listenersByOwner.delete(ownerPath);
2712
+ if (listenersByOwner.size === 0) customListenersMap.delete(event);
2713
+ }
2714
+ }
2502
2715
  `;
2503
2716
  }
2504
2717
  var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
@@ -2509,7 +2722,8 @@ var init_middleware = __esm({
2509
2722
  init_html();
2510
2723
  init_env();
2511
2724
  init_url();
2512
- __dirname_esm = path4.dirname(fileURLToPath(import.meta.url));
2725
+ init_assets();
2726
+ __dirname_esm = path5.dirname(fileURLToPath(import.meta.url));
2513
2727
  __require2 = createRequire(import.meta.url);
2514
2728
  __refreshRuntimeCache = null;
2515
2729
  REACT_REFRESH_BOUNDARY_HELPERS = `
@@ -2590,33 +2804,40 @@ window.__vite_plugin_react_preamble_installed__ = true;
2590
2804
  });
2591
2805
 
2592
2806
  // src/server/hmr.ts
2593
- import path5 from "path";
2594
- import fs5 from "fs";
2807
+ import path6 from "path";
2808
+ import fs6 from "fs";
2595
2809
  import pc4 from "picocolors";
2596
- async function handleFileChange(file, server) {
2597
- const { moduleGraph, ws, config } = server;
2810
+ async function handleFileChange(file, server, environmentName = "client", timestamp = Date.now()) {
2811
+ const { config } = server;
2812
+ const environment = server.environments[environmentName];
2813
+ if (!environment) {
2814
+ throw new Error(`[nasti] unknown dev environment "${environmentName}"`);
2815
+ }
2816
+ const moduleGraph = environment.moduleGraph;
2598
2817
  const logger = config.logger;
2599
- const relativePath = "/" + path5.relative(config.root, file);
2600
- const shortFile = path5.relative(config.root, file);
2818
+ const relativePath = "/" + path6.relative(config.root, file);
2819
+ const shortFile = path6.relative(config.root, file);
2601
2820
  const mods = moduleGraph.getModulesByFile(file);
2602
2821
  if (!mods || mods.size === 0) {
2603
- return;
2822
+ return null;
2604
2823
  }
2605
2824
  const updates = [];
2606
- const timestamp = Date.now();
2607
2825
  const graph = moduleGraph;
2608
2826
  const invalidatedModules = /* @__PURE__ */ new Set();
2827
+ const affectedSet = /* @__PURE__ */ new Set();
2828
+ let fullReload = false;
2609
2829
  for (const mod of mods) {
2610
2830
  graph.invalidateModuleAndImporters(mod, timestamp, invalidatedModules);
2611
2831
  const ctx = {
2612
2832
  file,
2613
2833
  timestamp,
2614
2834
  modules: [mod],
2615
- read: () => fs5.readFileSync(file, "utf-8"),
2616
- server
2835
+ read: () => fs6.readFileSync(file, "utf-8"),
2836
+ server,
2837
+ environment
2617
2838
  };
2618
2839
  let affectedModules = [mod];
2619
- for (const plugin of config.plugins) {
2840
+ for (const plugin of environment.plugins) {
2620
2841
  if (plugin.handleHotUpdate) {
2621
2842
  const result = await plugin.handleHotUpdate(ctx);
2622
2843
  if (result) {
@@ -2625,12 +2846,12 @@ async function handleFileChange(file, server) {
2625
2846
  }
2626
2847
  }
2627
2848
  for (const affected of affectedModules) {
2849
+ affectedSet.add(affected);
2628
2850
  graph.invalidateModuleAndImporters(affected, timestamp, invalidatedModules);
2629
2851
  const boundaries = graph.getHmrBoundaries(affected);
2630
2852
  if (boundaries.length === 0) {
2631
- logger.info(pc4.green("page reload ") + pc4.dim(shortFile), { timestamp: true });
2632
- ws.send({ type: "full-reload", path: relativePath });
2633
- return;
2853
+ fullReload = true;
2854
+ continue;
2634
2855
  }
2635
2856
  for (const { boundary, acceptedVia } of boundaries) {
2636
2857
  const update = {
@@ -2647,13 +2868,30 @@ async function handleFileChange(file, server) {
2647
2868
  }
2648
2869
  }
2649
2870
  }
2650
- if (updates.length > 0) {
2871
+ const transformed = await Promise.all(
2872
+ [...affectedSet].map(async (module) => ({
2873
+ module,
2874
+ result: await environment.transformRequest(module.url)
2875
+ }))
2876
+ );
2877
+ const logPrefix = environmentName === "client" ? "" : `[${environmentName}] `;
2878
+ if (fullReload) {
2879
+ logger.info(pc4.green(`${logPrefix}reload `) + pc4.dim(shortFile), { timestamp: true });
2880
+ environment.hot.send({ type: "full-reload", path: relativePath });
2881
+ } else if (updates.length > 0) {
2651
2882
  logger.info(
2652
- updates.map((u) => pc4.green("hmr update ") + pc4.dim(u.path)).join("\n"),
2883
+ updates.map((u) => pc4.green(`${logPrefix}hmr update `) + pc4.dim(u.path)).join("\n"),
2653
2884
  { timestamp: true }
2654
2885
  );
2655
- ws.send({ type: "update", updates });
2886
+ environment.hot.send({ type: "update", updates });
2656
2887
  }
2888
+ return {
2889
+ environment,
2890
+ modules: [...affectedSet],
2891
+ updates,
2892
+ transformed,
2893
+ fullReload
2894
+ };
2657
2895
  }
2658
2896
  var init_hmr = __esm({
2659
2897
  "src/server/hmr.ts"() {
@@ -2662,12 +2900,12 @@ var init_hmr = __esm({
2662
2900
  });
2663
2901
 
2664
2902
  // src/plugins/resolve.ts
2665
- import path6 from "path";
2666
- import fs6 from "fs";
2903
+ import path7 from "path";
2904
+ import fs7 from "fs";
2667
2905
  import { createRequire as createRequire2 } from "module";
2668
2906
  function resolvePlugin(config) {
2669
2907
  const { alias, extensions } = config.resolve;
2670
- const require2 = createRequire2(path6.resolve(config.root, "package.json"));
2908
+ const require2 = createRequire2(path7.resolve(config.root, "package.json"));
2671
2909
  const aliasEntries = Object.entries(alias).sort(
2672
2910
  ([a], [b]) => b.length - a.length
2673
2911
  );
@@ -2675,10 +2913,10 @@ function resolvePlugin(config) {
2675
2913
  if (config.framework === "vue") {
2676
2914
  try {
2677
2915
  const vuePkgJson = require2.resolve("vue/package.json", { paths: [config.root] });
2678
- const vueDir = path6.dirname(vuePkgJson);
2679
- const mod = JSON.parse(fs6.readFileSync(vuePkgJson, "utf-8")).module;
2680
- const entry = path6.join(vueDir, mod ?? "dist/vue.runtime.esm-bundler.js");
2681
- if (fs6.existsSync(entry)) vueRuntimeEntry = entry;
2916
+ const vueDir = path7.dirname(vuePkgJson);
2917
+ const mod = JSON.parse(fs7.readFileSync(vuePkgJson, "utf-8")).module;
2918
+ const entry = path7.join(vueDir, mod ?? "dist/vue.runtime.esm-bundler.js");
2919
+ if (fs7.existsSync(entry)) vueRuntimeEntry = entry;
2682
2920
  } catch {
2683
2921
  }
2684
2922
  }
@@ -2690,24 +2928,24 @@ function resolvePlugin(config) {
2690
2928
  if (source === key || source.startsWith(key + "/")) {
2691
2929
  const aliasBase = resolveAliasTarget2(value, config.root);
2692
2930
  const sub = source.slice(key.length).replace(/^\//, "");
2693
- const target = sub ? path6.join(aliasBase, sub) : aliasBase;
2931
+ const target = sub ? path7.join(aliasBase, sub) : aliasBase;
2694
2932
  const resolved = tryResolveFile(target, extensions);
2695
2933
  if (resolved) return resolved;
2696
2934
  break;
2697
2935
  }
2698
2936
  }
2699
2937
  if (source.startsWith("/") && !source.startsWith("//")) {
2700
- const rootRelative = path6.join(config.root, source.slice(1));
2938
+ const rootRelative = path7.join(config.root, source.slice(1));
2701
2939
  const resolved = tryResolveFile(rootRelative, extensions);
2702
2940
  if (resolved) return resolved;
2703
2941
  }
2704
- if (path6.isAbsolute(source) && fs6.existsSync(source)) {
2942
+ if (path7.isAbsolute(source) && fs7.existsSync(source)) {
2705
2943
  const resolved = tryResolveFile(source, extensions);
2706
2944
  if (resolved) return resolved;
2707
2945
  }
2708
2946
  if (source.startsWith(".")) {
2709
- const dir = importer ? path6.dirname(importer) : config.root;
2710
- const absolute = path6.resolve(dir, source);
2947
+ const dir = importer ? path7.dirname(importer) : config.root;
2948
+ const absolute = path7.resolve(dir, source);
2711
2949
  const resolved = tryResolveFile(absolute, extensions);
2712
2950
  if (resolved) return resolved;
2713
2951
  }
@@ -2716,7 +2954,7 @@ function resolvePlugin(config) {
2716
2954
  if (config.command === "build") return null;
2717
2955
  try {
2718
2956
  const resolved = require2.resolve(source, {
2719
- paths: [importer ? path6.dirname(importer) : config.root]
2957
+ paths: [importer ? path7.dirname(importer) : config.root]
2720
2958
  });
2721
2959
  return resolved;
2722
2960
  } catch {
@@ -2727,34 +2965,34 @@ function resolvePlugin(config) {
2727
2965
  },
2728
2966
  load(id) {
2729
2967
  if (id.startsWith("\0")) return null;
2730
- if (!fs6.existsSync(id)) return null;
2968
+ if (!fs7.existsSync(id)) return null;
2731
2969
  if (id.endsWith(".json")) {
2732
- const content = fs6.readFileSync(id, "utf-8");
2970
+ const content = fs7.readFileSync(id, "utf-8");
2733
2971
  return `export default ${content}`;
2734
2972
  }
2735
- return fs6.readFileSync(id, "utf-8");
2973
+ return null;
2736
2974
  }
2737
2975
  };
2738
2976
  }
2739
2977
  function resolveAliasTarget2(value, root) {
2740
- if (path6.isAbsolute(value) && fs6.existsSync(value)) return value;
2741
- if (value.startsWith("/")) return path6.join(root, value.slice(1));
2742
- return path6.resolve(root, value);
2978
+ if (path7.isAbsolute(value) && fs7.existsSync(value)) return value;
2979
+ if (value.startsWith("/")) return path7.join(root, value.slice(1));
2980
+ return path7.resolve(root, value);
2743
2981
  }
2744
2982
  function tryResolveFile(file, extensions) {
2745
- if (fs6.existsSync(file) && fs6.statSync(file).isFile()) {
2983
+ if (fs7.existsSync(file) && fs7.statSync(file).isFile()) {
2746
2984
  return file;
2747
2985
  }
2748
2986
  for (const ext of extensions) {
2749
2987
  const withExt = file + ext;
2750
- if (fs6.existsSync(withExt) && fs6.statSync(withExt).isFile()) {
2988
+ if (fs7.existsSync(withExt) && fs7.statSync(withExt).isFile()) {
2751
2989
  return withExt;
2752
2990
  }
2753
2991
  }
2754
- if (fs6.existsSync(file) && fs6.statSync(file).isDirectory()) {
2992
+ if (fs7.existsSync(file) && fs7.statSync(file).isDirectory()) {
2755
2993
  for (const ext of extensions) {
2756
- const indexFile = path6.join(file, "index" + ext);
2757
- if (fs6.existsSync(indexFile)) {
2994
+ const indexFile = path7.join(file, "index" + ext);
2995
+ if (fs7.existsSync(indexFile)) {
2758
2996
  return indexFile;
2759
2997
  }
2760
2998
  }
@@ -3646,12 +3884,31 @@ var init_node = __esm({
3646
3884
  function createCssEngine() {
3647
3885
  return {
3648
3886
  styles: /* @__PURE__ */ new Map(),
3887
+ modules: /* @__PURE__ */ new Map(),
3888
+ chunks: /* @__PURE__ */ new Map(),
3649
3889
  entryCss: /* @__PURE__ */ new Map(),
3650
3890
  allCss: [],
3651
3891
  pendingSingle: [],
3652
3892
  singleFileName: null
3653
3893
  };
3654
3894
  }
3895
+ function getCssMetadata(engine) {
3896
+ return {
3897
+ modules: Object.fromEntries(
3898
+ [...engine.modules].map(([id, module]) => [id, { ...module }])
3899
+ ),
3900
+ chunks: Object.fromEntries(
3901
+ [...engine.chunks].map(([fileName, chunk]) => [
3902
+ fileName,
3903
+ {
3904
+ fileName,
3905
+ moduleIds: [...chunk.moduleIds],
3906
+ cssFileNames: [...chunk.cssFileNames]
3907
+ }
3908
+ ])
3909
+ )
3910
+ };
3911
+ }
3655
3912
  function normalizeCssModuleId(id) {
3656
3913
  return id.startsWith("\0") ? id.slice(1) : id;
3657
3914
  }
@@ -3699,7 +3956,7 @@ var init_css_engine = __esm({
3699
3956
  });
3700
3957
 
3701
3958
  // src/plugins/tailwind.ts
3702
- import path7 from "path";
3959
+ import path8 from "path";
3703
3960
  import { createRequire as createRequire3 } from "module";
3704
3961
  import { pathToFileURL as pathToFileURL3 } from "url";
3705
3962
  function hasTailwindDirectives(css) {
@@ -3709,7 +3966,7 @@ function hasTailwindDirectives(css) {
3709
3966
  }
3710
3967
  async function loadTailwind(projectRoot) {
3711
3968
  if (cached && cachedRoot === projectRoot) return cached;
3712
- const req = createRequire3(path7.join(projectRoot, "package.json"));
3969
+ const req = createRequire3(path8.join(projectRoot, "package.json"));
3713
3970
  let nodePath;
3714
3971
  let oxidePath;
3715
3972
  try {
@@ -3730,7 +3987,7 @@ async function compileTailwind(css, fromFile, projectRoot) {
3730
3987
  const { node, oxide } = await loadTailwind(projectRoot);
3731
3988
  const dependencies = [];
3732
3989
  const compiler2 = await node.compile(css, {
3733
- base: path7.dirname(fromFile),
3990
+ base: path8.dirname(fromFile),
3734
3991
  from: fromFile,
3735
3992
  onDependency: (p) => dependencies.push(p)
3736
3993
  });
@@ -3752,7 +4009,8 @@ var init_tailwind = __esm({
3752
4009
  });
3753
4010
 
3754
4011
  // src/plugins/css.ts
3755
- import path8 from "path";
4012
+ import path9 from "path";
4013
+ import { SourceMapGenerator } from "source-map-js";
3756
4014
  function cssPlugin(config, engine, consumer = "client") {
3757
4015
  return {
3758
4016
  name: "nasti:css",
@@ -3772,15 +4030,29 @@ function cssPlugin(config, engine, consumer = "client") {
3772
4030
  }
3773
4031
  const rewritten = rewriteCssUrls(cssSource, file, config.root);
3774
4032
  const escaped = JSON.stringify(rewritten);
4033
+ const normalizedId = normalizeCssModuleId(id);
4034
+ const cssModule = { id: normalizedId, source: code, code: rewritten };
4035
+ const map = config.build.sourcemap ? createIdentitySourceMap(code, id) : void 0;
4036
+ engine?.modules.set(normalizedId, cssModule);
4037
+ this.environment?.setCssModule?.(cssModule);
3775
4038
  if (query === "inline") {
3776
4039
  return { code: `export default ${escaped};
3777
- `, moduleType: "js" };
4040
+ `, map, moduleType: "js" };
3778
4041
  }
3779
4042
  if (consumer === "server") {
3780
4043
  return { code: `export default ${escaped};
3781
- `, moduleType: "js" };
4044
+ `, map, moduleType: "js" };
3782
4045
  }
3783
4046
  if (config.command === "serve") {
4047
+ if (config.build.css.inject === false) {
4048
+ return {
4049
+ code: `export default ${escaped};
4050
+ `,
4051
+ map,
4052
+ moduleType: "js",
4053
+ moduleSideEffects: "no-treeshake"
4054
+ };
4055
+ }
3784
4056
  return {
3785
4057
  code: `
3786
4058
  const css = ${escaped};
@@ -3804,16 +4076,18 @@ if (import.meta.hot) {
3804
4076
 
3805
4077
  export default css;
3806
4078
  `,
4079
+ map,
3807
4080
  // bundled dev(DevEngine)下该模块会进 Rolldown:不标 js 会按 .css
3808
4081
  // 扩展名走 CSS 管线触发 #4271 报错;unbundled 中间件忽略此字段
3809
4082
  moduleType: "js"
3810
4083
  };
3811
4084
  }
3812
4085
  if (engine) {
3813
- engine.styles.set(normalizeCssModuleId(id), rewritten);
4086
+ engine.styles.set(normalizedId, rewritten);
3814
4087
  return {
3815
4088
  code: `export default '';
3816
4089
  `,
4090
+ map,
3817
4091
  moduleType: "js",
3818
4092
  // 防止空 stub 被 tree-shake 出 chunk.moduleIds(css-post 靠它定位)
3819
4093
  moduleSideEffects: "no-treeshake"
@@ -3833,18 +4107,34 @@ document.head.appendChild(style);
3833
4107
 
3834
4108
  export default css;
3835
4109
  `,
4110
+ map,
3836
4111
  moduleType: "js"
3837
4112
  };
3838
4113
  }
3839
4114
  };
3840
4115
  }
4116
+ function createIdentitySourceMap(code, id) {
4117
+ const map = new SourceMapGenerator({ file: id });
4118
+ const lines = code.split("\n");
4119
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
4120
+ for (let column = 0; column <= lines[lineIndex].length; column++) {
4121
+ map.addMapping({
4122
+ generated: { line: lineIndex + 1, column },
4123
+ original: { line: lineIndex + 1, column },
4124
+ source: id
4125
+ });
4126
+ }
4127
+ }
4128
+ map.setSourceContent(id, code);
4129
+ return map.toJSON();
4130
+ }
3841
4131
  function rewriteCssUrls(css, from, root) {
3842
4132
  return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
3843
4133
  if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
3844
4134
  return match;
3845
4135
  }
3846
- const resolved = path8.resolve(path8.dirname(from), url);
3847
- const relative = "/" + path8.relative(root, resolved).replace(/\\/g, "/");
4136
+ const resolved = path9.resolve(path9.dirname(from), url);
4137
+ const relative = "/" + path9.relative(root, resolved).replace(/\\/g, "/");
3848
4138
  return `url(${relative})`;
3849
4139
  });
3850
4140
  }
@@ -3860,19 +4150,27 @@ var init_css = __esm({
3860
4150
  function collectChunkCss(chunk, engine) {
3861
4151
  const ids = chunk.moduleIds ?? Object.keys(chunk.modules);
3862
4152
  let css = "";
4153
+ const moduleIds = [];
3863
4154
  for (const id of ids) {
3864
- const styles = engine.styles.get(normalizeCssModuleId(id));
3865
- if (styles) css += styles + "\n";
4155
+ const normalizedId = normalizeCssModuleId(id);
4156
+ const styles = engine.styles.get(normalizedId);
4157
+ if (styles) {
4158
+ css += styles + "\n";
4159
+ moduleIds.push(normalizedId);
4160
+ }
3866
4161
  }
3867
- return css;
4162
+ return { css, moduleIds };
3868
4163
  }
3869
4164
  function cssPostPlugin(config, engine) {
3870
4165
  return {
3871
4166
  name: "nasti:css-post",
3872
4167
  enforce: "post",
3873
4168
  async renderChunk(code, chunk) {
3874
- const css = collectChunkCss(chunk, engine);
4169
+ const { css, moduleIds } = collectChunkCss(chunk, engine);
3875
4170
  if (!css) return null;
4171
+ const ownership = { moduleIds, cssFileNames: [] };
4172
+ engine.chunks.set(chunk.fileName, ownership);
4173
+ if (config.build.css.emit === false) return null;
3876
4174
  if (!config.build.cssCodeSplit) {
3877
4175
  engine.pendingSingle.push(css);
3878
4176
  return null;
@@ -3885,6 +4183,7 @@ function cssPostPlugin(config, engine) {
3885
4183
  });
3886
4184
  const fileName = this.getFileName(ref);
3887
4185
  engine.allCss.push(fileName);
4186
+ ownership.cssFileNames.push(fileName);
3888
4187
  if (chunk.isEntry) {
3889
4188
  const key = chunk.facadeModuleId ?? chunk.name;
3890
4189
  const existing = engine.entryCss.get(key) ?? [];
@@ -3892,13 +4191,14 @@ function cssPostPlugin(config, engine) {
3892
4191
  engine.entryCss.set(key, existing);
3893
4192
  return null;
3894
4193
  }
4194
+ if (config.build.css.inject === false) return null;
3895
4195
  const href = JSON.stringify(config.base + fileName);
3896
4196
  const snippet = `
3897
4197
  ;(function(){try{var d=document,h=${href};if(!d.querySelector('link[data-nasti-css="'+h+'"]')){var l=d.createElement('link');l.rel='stylesheet';l.href=h;l.setAttribute('data-nasti-css',h);d.head.appendChild(l);}}catch(e){}})();`;
3898
4198
  return { code: code + snippet, map: null };
3899
4199
  },
3900
4200
  augmentChunkHash(chunk) {
3901
- const css = collectChunkCss(chunk, engine);
4201
+ const { css } = collectChunkCss(chunk, engine);
3902
4202
  return css || void 0;
3903
4203
  },
3904
4204
  async generateBundle() {
@@ -3909,6 +4209,9 @@ function cssPostPlugin(config, engine) {
3909
4209
  const fileName = this.getFileName(ref);
3910
4210
  engine.singleFileName = fileName;
3911
4211
  engine.allCss.push(fileName);
4212
+ for (const ownership of engine.chunks.values()) {
4213
+ if (ownership.moduleIds.length > 0) ownership.cssFileNames.push(fileName);
4214
+ }
3912
4215
  }
3913
4216
  };
3914
4217
  }
@@ -3919,78 +4222,13 @@ var init_css_post = __esm({
3919
4222
  }
3920
4223
  });
3921
4224
 
3922
- // src/plugins/assets.ts
3923
- import path9 from "path";
3924
- import fs7 from "fs";
3925
- import crypto from "crypto";
3926
- function assetsPlugin(config) {
3927
- return {
3928
- name: "nasti:assets",
3929
- resolveId(source) {
3930
- if (source.endsWith("?url") || source.endsWith("?raw")) {
3931
- return source;
3932
- }
3933
- return null;
3934
- },
3935
- load(id) {
3936
- const ext = path9.extname(id.replace(/\?.*$/, ""));
3937
- if (id.endsWith("?raw")) {
3938
- const file = id.slice(0, -4);
3939
- if (fs7.existsSync(file)) {
3940
- const content = fs7.readFileSync(file, "utf-8");
3941
- return `export default ${JSON.stringify(content)}`;
3942
- }
3943
- }
3944
- if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
3945
- const file = id.replace(/\?.*$/, "");
3946
- if (!fs7.existsSync(file)) return null;
3947
- if (config.command === "serve") {
3948
- const url = "/" + path9.relative(config.root, file);
3949
- return `export default ${JSON.stringify(url)}`;
3950
- }
3951
- const content = fs7.readFileSync(file);
3952
- const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
3953
- const basename = path9.basename(file, ext);
3954
- const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
3955
- return `export default ${JSON.stringify(config.base + hashedName)}`;
3956
- }
3957
- return null;
3958
- }
3959
- };
3960
- }
3961
- var ASSET_EXTENSIONS;
3962
- var init_assets = __esm({
3963
- "src/plugins/assets.ts"() {
3964
- "use strict";
3965
- ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
3966
- ".png",
3967
- ".jpg",
3968
- ".jpeg",
3969
- ".gif",
3970
- ".svg",
3971
- ".ico",
3972
- ".webp",
3973
- ".avif",
3974
- ".mp4",
3975
- ".webm",
3976
- ".ogg",
3977
- ".mp3",
3978
- ".wav",
3979
- ".flac",
3980
- ".aac",
3981
- ".woff",
3982
- ".woff2",
3983
- ".eot",
3984
- ".ttf",
3985
- ".otf",
3986
- ".pdf",
3987
- ".txt"
3988
- ]);
3989
- }
3990
- });
3991
-
3992
4225
  // src/plugins/vue.ts
3993
4226
  import crypto2 from "crypto";
4227
+ import {
4228
+ SourceMapConsumer,
4229
+ SourceMapGenerator as SourceMapGenerator2,
4230
+ SourceNode
4231
+ } from "source-map-js";
3994
4232
  async function loadVueCompiler() {
3995
4233
  if (compiler) return compiler;
3996
4234
  try {
@@ -4000,9 +4238,10 @@ async function loadVueCompiler() {
4000
4238
  return null;
4001
4239
  }
4002
4240
  }
4003
- function vuePlugin(config) {
4241
+ function vuePlugin(config, environmentName = "client") {
4004
4242
  const isDev = config.command === "serve";
4005
4243
  const descriptorCache = /* @__PURE__ */ new Map();
4244
+ const vueOptions = config.environments[environmentName]?.vue ?? {};
4006
4245
  return {
4007
4246
  name: "nasti:vue",
4008
4247
  enforce: "pre",
@@ -4022,32 +4261,63 @@ function vuePlugin(config) {
4022
4261
  const sfc = await loadVueCompiler();
4023
4262
  if (!sfc) return null;
4024
4263
  const [, filePath, indexStr] = match;
4025
- let descriptor = descriptorCache.get(filePath);
4026
- if (!descriptor) {
4264
+ let cached2 = descriptorCache.get(filePath);
4265
+ if (!cached2) {
4027
4266
  try {
4028
4267
  const fs13 = await import("fs");
4029
- const source = fs13.readFileSync(filePath, "utf-8");
4030
- const parsed = sfc.parse(source, { filename: filePath });
4268
+ const rawSource = fs13.readFileSync(filePath, "utf-8");
4269
+ const transformedSfc = await applySourceTransform(
4270
+ vueOptions.transformSfc,
4271
+ rawSource,
4272
+ { filename: filePath, environmentName, type: "sfc" }
4273
+ );
4274
+ const parsed = sfc.parse(transformedSfc.code, {
4275
+ ...vueOptions.parse,
4276
+ filename: filePath,
4277
+ sourceMap: true
4278
+ });
4031
4279
  if (parsed.errors.length) return null;
4032
- descriptor = parsed.descriptor;
4033
- descriptorCache.set(filePath, descriptor);
4280
+ cached2 = {
4281
+ descriptor: parsed.descriptor,
4282
+ sourceMap: transformedSfc.map
4283
+ };
4284
+ descriptorCache.set(filePath, cached2);
4034
4285
  } catch {
4035
4286
  return null;
4036
4287
  }
4037
4288
  }
4289
+ const { descriptor, sourceMap: sfcSourceMap } = cached2;
4038
4290
  const index2 = parseInt(indexStr ?? "0", 10);
4039
4291
  const style = descriptor.styles[index2];
4040
4292
  if (!style) return null;
4041
4293
  const scopeId = hashId(filePath);
4294
+ const transformedStyle = await applySourceTransform(
4295
+ vueOptions.transformStyle,
4296
+ style.content,
4297
+ { filename: filePath, environmentName, type: "style", index: index2 }
4298
+ );
4299
+ const wantsStyleSourceMap = !!config.build.sourcemap || transformedStyle.map != null || sfcSourceMap != null;
4300
+ const styleInputMap = wantsStyleSourceMap ? composeSourceMapChain(
4301
+ [transformedStyle.map, style.map, sfcSourceMap],
4302
+ { filename: filePath, environmentName, type: "style", index: index2 }
4303
+ ) : void 0;
4042
4304
  const result = await sfc.compileStyleAsync({
4043
- source: style.content,
4305
+ ...vueOptions.style,
4306
+ source: transformedStyle.code,
4044
4307
  filename: filePath,
4045
4308
  id: `data-v-${scopeId}`,
4046
4309
  scoped: style.scoped ?? false,
4310
+ inMap: styleInputMap,
4047
4311
  // <style lang="scss|less|stylus"> 需经对应预处理器(缺省 undefined = 纯 CSS)
4048
4312
  preprocessLang: style.lang
4049
4313
  });
4050
- return result.code;
4314
+ if (transformedStyle.map != null && result.map == null) {
4315
+ warnUnchainableMap(
4316
+ { filename: filePath, environmentName, type: "style", index: index2 },
4317
+ "compiler-sfc did not return a style map"
4318
+ );
4319
+ }
4320
+ return wantsStyleSourceMap ? { code: result.code, map: result.map } : result.code;
4051
4321
  },
4052
4322
  async transform(code, id) {
4053
4323
  if (!VUE_FILE_RE.test(id) && !VUE_QUERY_RE.test(id)) return null;
@@ -4059,57 +4329,144 @@ function vuePlugin(config) {
4059
4329
  if (VUE_QUERY_RE.test(id)) {
4060
4330
  return null;
4061
4331
  }
4062
- const { descriptor, errors } = sfc.parse(code, { filename: id });
4332
+ const transformedSfc = await applySourceTransform(
4333
+ vueOptions.transformSfc,
4334
+ code,
4335
+ { filename: id, environmentName, type: "sfc" }
4336
+ );
4337
+ code = transformedSfc.code;
4338
+ const { descriptor, errors } = sfc.parse(code, {
4339
+ ...vueOptions.parse,
4340
+ filename: id,
4341
+ sourceMap: true
4342
+ });
4063
4343
  if (errors.length) {
4064
- console.error(`[nasti:vue] Parse error in ${id}:`, errors[0].message);
4344
+ const firstError = errors[0];
4345
+ console.error(
4346
+ `[nasti:vue] Parse error in ${id}:`,
4347
+ typeof firstError === "string" ? firstError : firstError.message
4348
+ );
4065
4349
  return null;
4066
4350
  }
4067
- descriptorCache.set(id, descriptor);
4351
+ descriptorCache.set(id, {
4352
+ descriptor,
4353
+ sourceMap: transformedSfc.map
4354
+ });
4068
4355
  const scopeId = hashId(id);
4356
+ const wantsSourceMap = !!config.build.sourcemap || transformedSfc.map != null;
4069
4357
  let scriptCode = "";
4358
+ let scriptMap;
4070
4359
  if (descriptor.script || descriptor.scriptSetup) {
4360
+ const inlineTemplate = vueOptions.script?.inlineTemplate !== false;
4071
4361
  const compiled = sfc.compileScript(descriptor, {
4362
+ ...vueOptions.script,
4072
4363
  id: scopeId,
4073
4364
  isProd: !isDev,
4074
- inlineTemplate: true,
4365
+ inlineTemplate,
4366
+ sourceMap: wantsSourceMap,
4075
4367
  // 让 compileScript 产出 `const __sfc__ = ...`(而非默认的 `export default {...}`)。
4076
4368
  // 否则下方追加的 `__sfc__.render` / `__sfc__.__scopeId` / HMR 记录会引用一个
4077
4369
  // 不存在的 `__sfc__`,并与 compileScript 自带的 `export default` 形成双重默认导出。
4078
4370
  genDefaultAs: "__sfc__"
4079
4371
  });
4080
4372
  scriptCode = compiled.content;
4373
+ scriptMap = composeSourceMapChain(
4374
+ [compiled.map, transformedSfc.map],
4375
+ { filename: id, environmentName, type: "sfc" }
4376
+ );
4377
+ if (transformedSfc.map != null && scriptMap == null) {
4378
+ warnUnchainableMap(
4379
+ { filename: id, environmentName, type: "sfc" },
4380
+ "compiler-sfc did not return a script map"
4381
+ );
4382
+ }
4081
4383
  }
4082
4384
  let templateCode = "";
4083
- if (descriptor.template && !descriptor.scriptSetup) {
4385
+ let templateMap;
4386
+ const scriptSetupIsInline = !!descriptor.scriptSetup && vueOptions.script?.inlineTemplate !== false;
4387
+ if (descriptor.template && !scriptSetupIsInline) {
4388
+ const transformedTemplate = await applySourceTransform(
4389
+ vueOptions.transformTemplate,
4390
+ descriptor.template.content,
4391
+ { filename: id, environmentName, type: "template" }
4392
+ );
4393
+ const templateInputMap = composeSourceMapChain(
4394
+ [
4395
+ transformedTemplate.map,
4396
+ descriptor.template.map,
4397
+ transformedSfc.map
4398
+ ],
4399
+ { filename: id, environmentName, type: "template" }
4400
+ );
4401
+ const customCompilerOptions = vueOptions.template?.compilerOptions ?? {};
4084
4402
  const compiled = sfc.compileTemplate({
4085
- source: descriptor.template.content,
4403
+ ...vueOptions.template,
4404
+ source: transformedTemplate.code,
4086
4405
  filename: id,
4087
4406
  id: scopeId,
4088
- compilerOptions: { scopeId: `data-v-${scopeId}` }
4407
+ inMap: templateInputMap,
4408
+ compilerOptions: {
4409
+ ...customCompilerOptions,
4410
+ scopeId: `data-v-${scopeId}`
4411
+ }
4089
4412
  });
4090
4413
  templateCode = compiled.code;
4414
+ if (wantsSourceMap || transformedTemplate.map != null) {
4415
+ templateMap = compiled.map;
4416
+ }
4417
+ if (transformedTemplate.map != null && templateMap == null) {
4418
+ warnUnchainableMap(
4419
+ { filename: id, environmentName, type: "template" },
4420
+ "compiler-sfc did not return a template map"
4421
+ );
4422
+ }
4091
4423
  }
4092
- let output = scriptCode || "const __sfc__ = {}";
4424
+ const outputNode = new SourceNode();
4425
+ let hasMappedOutput = false;
4426
+ const append = (fragment, map) => {
4427
+ const normalizedMap = normalizeSourceMap(
4428
+ map,
4429
+ { filename: id, environmentName, type: "sfc" }
4430
+ );
4431
+ if (!normalizedMap) {
4432
+ outputNode.add(fragment);
4433
+ return;
4434
+ }
4435
+ try {
4436
+ outputNode.add(
4437
+ SourceNode.fromStringWithSourceMap(
4438
+ fragment,
4439
+ new SourceMapConsumer(normalizedMap)
4440
+ )
4441
+ );
4442
+ hasMappedOutput = true;
4443
+ } catch (error) {
4444
+ warnUnchainableMap(
4445
+ { filename: id, environmentName, type: "sfc" },
4446
+ `source-map assembly failed: ${error instanceof Error ? error.message : String(error)}`
4447
+ );
4448
+ outputNode.add(fragment);
4449
+ }
4450
+ };
4451
+ append(scriptCode || "const __sfc__ = {}", scriptMap);
4093
4452
  if (templateCode) {
4094
- output += `
4095
- ${templateCode}
4096
- `;
4097
- output += `
4098
- __sfc__.render = render
4099
- `;
4453
+ append("\n");
4454
+ append(templateCode, templateMap);
4455
+ append("\n");
4456
+ append("\n__sfc__.render = render\n");
4100
4457
  }
4101
4458
  if (descriptor.styles.length > 0) {
4102
4459
  for (let i = 0; i < descriptor.styles.length; i++) {
4103
- output += `
4460
+ append(`
4104
4461
  import "${id}?vue&type=style&index=${i}&lang.css"
4105
- `;
4462
+ `);
4106
4463
  }
4107
4464
  }
4108
- output += `
4465
+ append(`
4109
4466
  __sfc__.__scopeId = "data-v-${scopeId}"
4110
- `;
4467
+ `);
4111
4468
  if (isDev) {
4112
- output += `
4469
+ append(`
4113
4470
  __sfc__.__hmrId = ${JSON.stringify(scopeId)}
4114
4471
  if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
4115
4472
  __VUE_HMR_RUNTIME__.createRecord(__sfc__.__hmrId, __sfc__)
@@ -4123,17 +4480,34 @@ if (import.meta.hot) {
4123
4480
  }
4124
4481
  })
4125
4482
  }
4126
- `;
4483
+ `);
4484
+ }
4485
+ append("\nexport default __sfc__\n");
4486
+ const renderedOutput = outputNode.toStringWithSourceMap({ file: id });
4487
+ const output = renderedOutput.code;
4488
+ const outputMap = hasMappedOutput ? renderedOutput.map.toJSON() : void 0;
4489
+ if (transformedSfc.map != null && outputMap == null) {
4490
+ warnUnchainableMap(
4491
+ { filename: id, environmentName, type: "sfc" },
4492
+ "the compiled SFC output contained no chainable mappings"
4493
+ );
4127
4494
  }
4128
- output += `
4129
- export default __sfc__
4130
- `;
4131
4495
  const lang = descriptor.scriptSetup?.lang ?? descriptor.script?.lang;
4132
4496
  if (lang === "ts") {
4133
- const transpiled = transformCode(`${id}.ts`, output, { sourcemap: false });
4134
- return { code: transpiled.code };
4497
+ const transpiled = transformCode(`${id}.ts`, output, {
4498
+ sourcemap: wantsSourceMap,
4499
+ target: config.build.target
4500
+ });
4501
+ const transpiledMap = transpiled.map ? JSON.parse(transpiled.map) : void 0;
4502
+ return {
4503
+ code: transpiled.code,
4504
+ map: composeSourceMapChain(
4505
+ [transpiledMap, outputMap],
4506
+ { filename: id, environmentName, type: "sfc" }
4507
+ )
4508
+ };
4135
4509
  }
4136
- return { code: output };
4510
+ return { code: output, map: outputMap };
4137
4511
  },
4138
4512
  handleHotUpdate(ctx) {
4139
4513
  const { file, modules } = ctx;
@@ -4147,16 +4521,75 @@ export default __sfc__
4147
4521
  }
4148
4522
  };
4149
4523
  }
4524
+ async function applySourceTransform(transform2, source, context) {
4525
+ if (!transform2) return { code: source };
4526
+ const result = await transform2(source, context);
4527
+ return typeof result === "string" ? { code: result } : result;
4528
+ }
4529
+ function normalizeSourceMap(map, context) {
4530
+ if (map == null) return void 0;
4531
+ try {
4532
+ const value = typeof map === "string" ? JSON.parse(map) : map;
4533
+ if (value && typeof value === "object" && Array.isArray(value.sources) && Array.isArray(value.names) && typeof value.mappings === "string") {
4534
+ return value;
4535
+ }
4536
+ } catch {
4537
+ }
4538
+ warnUnchainableMap(context, "the provided map is not a valid source map");
4539
+ return void 0;
4540
+ }
4541
+ function composeSourceMapChain(maps, context) {
4542
+ const pending = maps.filter((map) => map != null);
4543
+ if (pending.length === 0) return void 0;
4544
+ let composed = normalizeSourceMap(pending.shift(), context);
4545
+ for (const map of pending) {
4546
+ const input = normalizeSourceMap(map, context);
4547
+ if (!input) continue;
4548
+ if (!composed) {
4549
+ composed = input;
4550
+ continue;
4551
+ }
4552
+ try {
4553
+ const consumer = new SourceMapConsumer(composed);
4554
+ if (consumer.sources.length !== 1) {
4555
+ warnUnchainableMap(
4556
+ context,
4557
+ "a generated map has multiple sources and cannot be chained safely"
4558
+ );
4559
+ continue;
4560
+ }
4561
+ const generator = SourceMapGenerator2.fromSourceMap(consumer);
4562
+ generator.applySourceMap(
4563
+ new SourceMapConsumer(input),
4564
+ consumer.sources[0]
4565
+ );
4566
+ composed = generator.toJSON();
4567
+ } catch (error) {
4568
+ warnUnchainableMap(
4569
+ context,
4570
+ `source-map composition failed: ${error instanceof Error ? error.message : String(error)}`
4571
+ );
4572
+ }
4573
+ }
4574
+ return composed;
4575
+ }
4576
+ function warnUnchainableMap(context, reason) {
4577
+ debug3?.(
4578
+ `source map warning for ${context.filename} (${context.type}, ${context.environmentName}): ${reason}`
4579
+ );
4580
+ }
4150
4581
  function hashId(filename) {
4151
4582
  return crypto2.createHash("sha256").update(filename).digest("hex").slice(0, 8);
4152
4583
  }
4153
- var VUE_FILE_RE, VUE_QUERY_RE, compiler;
4584
+ var VUE_FILE_RE, VUE_QUERY_RE, debug3, compiler;
4154
4585
  var init_vue = __esm({
4155
4586
  "src/plugins/vue.ts"() {
4156
4587
  "use strict";
4157
4588
  init_transformer();
4589
+ init_debug();
4158
4590
  VUE_FILE_RE = /\.vue$/;
4159
4591
  VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang[.=]\w+)?/;
4592
+ debug3 = createDebugger("nasti:vue");
4160
4593
  compiler = null;
4161
4594
  }
4162
4595
  });
@@ -4177,7 +4610,7 @@ function resolvePluginList(config, userPlugins, opts = {}) {
4177
4610
  const consumer = opts.consumer ?? environmentOptions?.consumer;
4178
4611
  return [
4179
4612
  // vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
4180
- ...config.framework === "vue" ? [vuePlugin(pluginConfig)] : [],
4613
+ ...config.framework === "vue" ? [vuePlugin(pluginConfig, opts.environmentName ?? "client")] : [],
4181
4614
  resolvePlugin(pluginConfig),
4182
4615
  cssPlugin(pluginConfig, opts.cssEngine, consumer),
4183
4616
  assetsPlugin(pluginConfig),
@@ -4217,14 +4650,14 @@ function createModuleRunner(environment) {
4217
4650
  }
4218
4651
  return new NastiModuleRunner(environment);
4219
4652
  }
4220
- var debug3, NODE_BUILTINS, NastiModuleRunner, AsyncFunction;
4653
+ var debug4, NODE_BUILTINS, NastiModuleRunner, AsyncFunction;
4221
4654
  var init_runnable_environment = __esm({
4222
4655
  "src/server/runnable-environment.ts"() {
4223
4656
  "use strict";
4224
4657
  init_transformer();
4225
4658
  init_env();
4226
4659
  init_debug();
4227
- debug3 = createDebugger("nasti:ssr");
4660
+ debug4 = createDebugger("nasti:ssr");
4228
4661
  NODE_BUILTINS = /* @__PURE__ */ new Set([...builtinModules, ...builtinModules.map((m) => `node:${m}`)]);
4229
4662
  NastiModuleRunner = class {
4230
4663
  environment;
@@ -4302,6 +4735,7 @@ var init_runnable_environment = __esm({
4302
4735
  if (shouldTransform(cleanId)) {
4303
4736
  const result = transformCode(cleanId, code, {
4304
4737
  sourcemap: false,
4738
+ target: this.environment.options.build.target,
4305
4739
  jsxRuntime: "automatic",
4306
4740
  jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
4307
4741
  });
@@ -4318,7 +4752,7 @@ var init_runnable_environment = __esm({
4318
4752
  );
4319
4753
  }
4320
4754
  const runnerResult = await moduleRunnerTransform(resolvedId, code);
4321
- debug3?.(`fetchModule ${resolvedId} (${runnerResult.deps?.length ?? 0} deps)`);
4755
+ debug4?.(`fetchModule ${resolvedId} (${runnerResult.deps?.length ?? 0} deps)`);
4322
4756
  return { id: resolvedId, code: runnerResult.code };
4323
4757
  }
4324
4758
  completeExtension(id) {
@@ -4440,7 +4874,7 @@ async function tryNativeReporterPlugin(config, logger) {
4440
4874
  logInfo: (msg) => logger.info(msg)
4441
4875
  });
4442
4876
  } catch (err) {
4443
- debug4?.(`native viteReporterPlugin unavailable, falling back to JS table: ${err}`);
4877
+ debug5?.(`native viteReporterPlugin unavailable, falling back to JS table: ${err}`);
4444
4878
  return null;
4445
4879
  }
4446
4880
  }
@@ -4495,12 +4929,12 @@ function warnLargeChunks(output, config, logger) {
4495
4929
  )
4496
4930
  );
4497
4931
  }
4498
- var debug4, numberFormatter;
4932
+ var debug5, numberFormatter;
4499
4933
  var init_reporter = __esm({
4500
4934
  "src/build/reporter.ts"() {
4501
4935
  "use strict";
4502
4936
  init_debug();
4503
- debug4 = createDebugger("nasti:reporter");
4937
+ debug5 = createDebugger("nasti:reporter");
4504
4938
  numberFormatter = new Intl.NumberFormat("en", {
4505
4939
  maximumFractionDigits: 2,
4506
4940
  minimumFractionDigits: 2
@@ -4542,6 +4976,24 @@ function createBuildAppContext(config, results) {
4542
4976
  getManifest(environmentName) {
4543
4977
  return results[environmentName]?.manifest;
4544
4978
  },
4979
+ getChunk(environmentName, fileName) {
4980
+ const normalized = normalizeEnvironmentFileName(fileName);
4981
+ return results[environmentName]?.chunks?.[normalized];
4982
+ },
4983
+ getCss(environmentName) {
4984
+ return results[environmentName]?.css;
4985
+ },
4986
+ getSourceMap(environmentName, fileName) {
4987
+ const normalized = normalizeEnvironmentFileName(fileName);
4988
+ return results[environmentName]?.sourceMaps?.[normalized];
4989
+ },
4990
+ resolvePublicPath(environmentName, fileName) {
4991
+ const result = results[environmentName];
4992
+ if (!result) return void 0;
4993
+ const normalized = normalizeEnvironmentFileName(fileName);
4994
+ const base = result.publicPath ?? config.base;
4995
+ return joinPublicPath(base, normalized);
4996
+ },
4545
4997
  emitFile(file) {
4546
4998
  const fileName = normalizeAppFileName(file.fileName);
4547
4999
  const collisionKey = artifactCollisionKey(fileName);
@@ -4571,6 +5023,9 @@ function createBuildAppContext(config, results) {
4571
5023
  }
4572
5024
  };
4573
5025
  }
5026
+ function joinPublicPath(base, fileName) {
5027
+ return `${base.endsWith("/") ? base : `${base}/`}${fileName.replace(/^\//, "")}`;
5028
+ }
4574
5029
  function normalizeEnvironmentFileName(fileName) {
4575
5030
  return path12.posix.normalize(fileName.replace(/\\/g, "/").replace(/^\.\//, ""));
4576
5031
  }
@@ -4673,7 +5128,11 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
4673
5128
  const inputOptions = {
4674
5129
  ...restInputOptions,
4675
5130
  input: entryPoints,
4676
- transform: { ...userTransform, define: mergedDefine },
5131
+ transform: {
5132
+ ...userTransform,
5133
+ target: userTransform?.target ?? envOptions.build.target,
5134
+ define: mergedDefine
5135
+ },
4677
5136
  plugins: rolldownPlugins,
4678
5137
  // client/server consumer 都必须使用当前环境的 conditions/mainFields;Lynx
4679
5138
  // BG/MT 通常同为 client consumer,但仍可能声明不同的运行时条件。
@@ -4696,7 +5155,7 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
4696
5155
  };
4697
5156
  const outputOptions = isServer ? {
4698
5157
  format: "esm",
4699
- sourcemap: !!envOptions.build.sourcemap,
5158
+ sourcemap: envOptions.build.sourcemap,
4700
5159
  minify: !!envOptions.build.minify,
4701
5160
  entryFileNames: "[name].js",
4702
5161
  chunkFileNames: "chunks/[name]-[hash].js",
@@ -4705,7 +5164,7 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
4705
5164
  dir: outDir
4706
5165
  } : {
4707
5166
  format: "esm",
4708
- sourcemap: !!envOptions.build.sourcemap,
5167
+ sourcemap: envOptions.build.sourcemap,
4709
5168
  minify: !!envOptions.build.minify,
4710
5169
  entryFileNames: `${assetsDir}/[name].[hash].js`,
4711
5170
  chunkFileNames: `${assetsDir}/[name].[hash].js`,
@@ -4780,13 +5239,68 @@ function finalizeEnvironmentResult(environment, result) {
4780
5239
  return [name, normalized];
4781
5240
  })
4782
5241
  );
5242
+ const inferredMetadata = inferOutputMetadata(environment, result.output);
4783
5243
  return {
5244
+ publicPath: environment.config.base,
5245
+ ...inferredMetadata,
4784
5246
  ...metadata,
4785
5247
  ...result,
4786
5248
  output: result.output,
5249
+ chunks: {
5250
+ ...inferredMetadata.chunks,
5251
+ ...metadata.chunks,
5252
+ ...result.chunks
5253
+ },
5254
+ assets: {
5255
+ ...inferredMetadata.assets,
5256
+ ...metadata.assets,
5257
+ ...result.assets
5258
+ },
5259
+ sourceMaps: {
5260
+ ...inferredMetadata.sourceMaps,
5261
+ ...metadata.sourceMaps,
5262
+ ...result.sourceMaps
5263
+ },
4787
5264
  ...Object.keys(normalizedEntries).length > 0 ? { entries: normalizedEntries } : {}
4788
5265
  };
4789
5266
  }
5267
+ function inferOutputMetadata(environment, output) {
5268
+ const chunks = {};
5269
+ const assets = {};
5270
+ const sourceMaps = {};
5271
+ const cssChunks = environment.getBuildMetadata().css?.chunks ?? {};
5272
+ const assetModules = environment.getAssetModules();
5273
+ const publicPath = environment.config.base;
5274
+ for (const artifact of output) {
5275
+ const fileName = normalizeEnvironmentFileName(artifact.fileName);
5276
+ if (artifact.map != null) sourceMaps[fileName] = artifact.map;
5277
+ if (artifact.type === "chunk") {
5278
+ const moduleIds = [...artifact.moduleIds ?? []];
5279
+ chunks[fileName] = {
5280
+ fileName,
5281
+ name: artifact.name ?? fileName,
5282
+ isEntry: !!artifact.isEntry,
5283
+ isDynamicEntry: !!artifact.isDynamicEntry,
5284
+ imports: [...artifact.imports ?? []],
5285
+ dynamicImports: [...artifact.dynamicImports ?? []],
5286
+ moduleIds,
5287
+ css: [...cssChunks[fileName]?.cssFileNames ?? []],
5288
+ assets: [
5289
+ ...new Set(
5290
+ moduleIds.map((id) => assetModules[id]).filter((asset) => !!asset)
5291
+ )
5292
+ ]
5293
+ };
5294
+ } else if (artifact.type === "asset") {
5295
+ assets[fileName] = {
5296
+ fileName,
5297
+ names: [...artifact.names ?? (artifact.name ? [artifact.name] : [])],
5298
+ publicPath: joinPublicPath(publicPath, fileName)
5299
+ };
5300
+ }
5301
+ }
5302
+ return { chunks, assets, sourceMaps };
5303
+ }
4790
5304
  function prepareBuildOutputDirectories(config, buildableNames) {
4791
5305
  const directories = /* @__PURE__ */ new Set();
4792
5306
  const protectedPaths = /* @__PURE__ */ new Set();
@@ -4864,6 +5378,7 @@ function createOxcTransformPlugin(config, environment) {
4864
5378
  if (!shouldTransform(id)) return null;
4865
5379
  const result = transformCode(id, code, {
4866
5380
  sourcemap: !!environment.options.build.sourcemap,
5381
+ target: environment.options.build.target,
4867
5382
  jsxRuntime: "automatic",
4868
5383
  jsxImportSource: config.framework === "vue" ? "vue" : "react"
4869
5384
  });
@@ -4877,9 +5392,9 @@ async function build(inlineConfig = {}) {
4877
5392
  const startTime = performance.now();
4878
5393
  logger.info(
4879
5394
  pc6.cyan(`
4880
- nasti v${"2.4.0"} `) + pc6.green(`building for ${config.mode}...`)
5395
+ nasti v${"2.4.2"} `) + pc6.green(`building for ${config.mode}...`)
4881
5396
  );
4882
- debug5?.(`root: ${config.root}`);
5397
+ debug6?.(`root: ${config.root}`);
4883
5398
  const buildableNames = Object.keys(config.environments).filter((name) => {
4884
5399
  const environment = config.environments[name];
4885
5400
  if (!environment.buildEnabled) return false;
@@ -4901,7 +5416,7 @@ nasti v${"2.4.0"} `) + pc6.green(`building for ${config.mode}...`)
4901
5416
  environmentResults[name] = built.result;
4902
5417
  if (name === "client") clientOutput = built.result.output;
4903
5418
  if (buildableNames.length > 1) {
4904
- debug5?.(`environment "${name}" built (${built.result.output.length} files)`);
5419
+ debug6?.(`environment "${name}" built (${built.result.output.length} files)`);
4905
5420
  }
4906
5421
  }
4907
5422
  const pluginApi = getPluginApi(config);
@@ -4997,6 +5512,7 @@ async function buildClientEnvironment(config) {
4997
5512
  const bundle2 = await rolldown(inputOptions);
4998
5513
  const { output } = await bundle2.write(outputOptions);
4999
5514
  await bundle2.close();
5515
+ clientEnv.setBuildMetadata({ css: getCssMetadata(cssEngine) });
5000
5516
  if (html) {
5001
5517
  let processedHtml = html;
5002
5518
  const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
@@ -5010,7 +5526,9 @@ async function buildClientEnvironment(config) {
5010
5526
  processedHtml = processHtml(processedHtml, result);
5011
5527
  }
5012
5528
  }
5013
- processedHtml = injectCssLinks(processedHtml, cssEngine, config);
5529
+ if (clientEnv.options.build.css.inject !== false) {
5530
+ processedHtml = injectCssLinks(processedHtml, cssEngine, config);
5531
+ }
5014
5532
  for (const chunk of output) {
5015
5533
  if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
5016
5534
  processedHtml = replaceEntryScript(
@@ -5048,9 +5566,11 @@ async function buildClientEnvironment(config) {
5048
5566
  async function buildServerEnvironment(config, name) {
5049
5567
  const envOptions = config.environments[name];
5050
5568
  const logger = config.logger;
5569
+ const cssEngine = envOptions.consumer === "client" ? createCssEngine() : void 0;
5051
5570
  const pluginList = resolvePluginList(config, config.plugins, {
5052
5571
  consumer: envOptions.consumer,
5053
- environmentName: name
5572
+ environmentName: name,
5573
+ cssEngine
5054
5574
  });
5055
5575
  const environment = new NastiEnvironment(name, config, {
5056
5576
  mode: "build",
@@ -5093,6 +5613,7 @@ async function buildServerEnvironment(config, name) {
5093
5613
  const bundle2 = await rolldown(inputOptions);
5094
5614
  const { output } = await bundle2.write(outputOptions);
5095
5615
  await bundle2.close();
5616
+ if (cssEngine) environment.setBuildMetadata({ css: getCssMetadata(cssEngine) });
5096
5617
  logger.info(
5097
5618
  pc6.dim(` [${name}] `) + output.map((o) => path13.join(envOptions.build.outDir, o.fileName)).join(pc6.dim(", "))
5098
5619
  );
@@ -5144,7 +5665,7 @@ function replaceEntryScript(html, facadeModuleId, fileName, config, htmlFile, ur
5144
5665
  }
5145
5666
  return processed;
5146
5667
  }
5147
- var debug5, NODE_BUILTINS2;
5668
+ var debug6, NODE_BUILTINS2;
5148
5669
  var init_build = __esm({
5149
5670
  "src/build/index.ts"() {
5150
5671
  "use strict";
@@ -5159,7 +5680,7 @@ var init_build = __esm({
5159
5680
  init_debug();
5160
5681
  init_plugin_api();
5161
5682
  init_build_app_context();
5162
- debug5 = createDebugger("nasti:build");
5683
+ debug6 = createDebugger("nasti:build");
5163
5684
  NODE_BUILTINS2 = /* @__PURE__ */ new Set([...builtinModules2, ...builtinModules2.map((m) => `node:${m}`)]);
5164
5685
  }
5165
5686
  });
@@ -5187,7 +5708,7 @@ async function createBundledDevServer(opts) {
5187
5708
  }
5188
5709
  } catch (err) {
5189
5710
  throw new Error(
5190
- `[nasti] experimental.bundledDev requires rolldown's experimental dev() API (locked to the installed rc; got: ${err.message}). Remove --bundle / experimental.bundledDev to use the default unbundled dev server.`
5711
+ `[nasti] experimental.bundledDev requires rolldown's experimental dev() API (locked version is incompatible; got: ${err.message}). Remove --bundle / experimental.bundledDev to use the default unbundled dev server.`
5191
5712
  );
5192
5713
  }
5193
5714
  const html = await readHtmlFile(config.root, config.environments.client?.html);
@@ -5240,7 +5761,7 @@ async function createBundledDevServer(opts) {
5240
5761
  for (const { clientId, update } of updates) {
5241
5762
  if (update.type === "Noop") continue;
5242
5763
  if (update.type === "FullReload") {
5243
- debug6?.(`full reload for ${clientId}: ${update.reason ?? ""}`);
5764
+ debug7?.(`full reload for ${clientId}: ${update.reason ?? ""}`);
5244
5765
  needsLatestOutput = true;
5245
5766
  continue;
5246
5767
  }
@@ -5290,7 +5811,7 @@ async function createBundledDevServer(opts) {
5290
5811
  },
5291
5812
  {
5292
5813
  watch: { skipWrite: true },
5293
- rebuildStrategy: "auto",
5814
+ rebuildStrategy: "never",
5294
5815
  onOutput(result) {
5295
5816
  if (result instanceof Error) {
5296
5817
  logger.error(pc7.red(`[bundled] build error: ${result.message}`), { error: result });
@@ -5306,7 +5827,13 @@ async function createBundledDevServer(opts) {
5306
5827
  memoryFiles.set(`${file.fileName}.map`, JSON.stringify(file.map));
5307
5828
  }
5308
5829
  }
5309
- debug6?.(`bundle output refreshed (${result.output.length} files)`);
5830
+ debug7?.(`bundle output refreshed (${result.output.length} files)`);
5831
+ },
5832
+ onAdditionalAssets(result) {
5833
+ for (const file of result.output) {
5834
+ const content = file.type === "chunk" ? file.code : file.source;
5835
+ if (content != null) memoryFiles.set(file.fileName, content);
5836
+ }
5310
5837
  },
5311
5838
  async onHmrUpdates(result) {
5312
5839
  if (result instanceof Error) {
@@ -5315,7 +5842,7 @@ async function createBundledDevServer(opts) {
5315
5842
  return;
5316
5843
  }
5317
5844
  const { updates, changedFiles } = result;
5318
- debug6?.(
5845
+ debug7?.(
5319
5846
  `onHmrUpdates(engine watcher): ${changedFiles.length} changed, ${updates.length} updates`
5320
5847
  );
5321
5848
  if (changedFiles.length === 0) return;
@@ -5334,24 +5861,29 @@ async function createBundledDevServer(opts) {
5334
5861
  if (!clientId) return;
5335
5862
  wss.handleUpgrade(req, socket, head, (ws) => {
5336
5863
  bundledClients.set(clientId, ws);
5337
- debug6?.(`bundled client connected: ${clientId}`);
5338
- ws.send(JSON.stringify({ type: "connected" }));
5864
+ debug7?.(`bundled client connected: ${clientId}`);
5865
+ void engine.registerClient(clientId).then(async () => {
5866
+ for (const fileName of entryFileNames.values()) {
5867
+ await engine.notifyPayloadDelivered(fileName);
5868
+ }
5869
+ ws.send(JSON.stringify({ type: "connected" }));
5870
+ }).catch((err) => {
5871
+ debug7?.(`registerClient failed for ${clientId}: ${err?.message ?? err}`);
5872
+ ws.close();
5873
+ });
5339
5874
  ws.on("message", async (raw) => {
5340
5875
  try {
5341
5876
  const msg = JSON.parse(String(raw));
5342
- if (msg.type === "hmr:module-registered" && Array.isArray(msg.modules)) {
5343
- await engine.registerModules(clientId, msg.modules);
5344
- debug6?.(`registered ${msg.modules.length} modules for ${clientId}`);
5345
- } else if (msg.type === "hmr:invalidate") {
5877
+ if (msg.type === "hmr:invalidate") {
5346
5878
  scheduleFullReload();
5347
5879
  }
5348
5880
  } catch (err) {
5349
- debug6?.(`bundled ws message error: ${err.message}`);
5881
+ debug7?.(`bundled ws message error: ${err.message}`);
5350
5882
  }
5351
5883
  });
5352
5884
  ws.on("close", () => {
5353
5885
  bundledClients.delete(clientId);
5354
- engine.removeClient(clientId).catch((err) => debug6?.(`removeClient failed for ${clientId}: ${err?.message ?? err}`));
5886
+ engine.removeClient(clientId).catch((err) => debug7?.(`removeClient failed for ${clientId}: ${err?.message ?? err}`));
5355
5887
  });
5356
5888
  });
5357
5889
  });
@@ -5368,10 +5900,18 @@ async function createBundledDevServer(opts) {
5368
5900
  res.end("// [nasti] lazy endpoint requires id & clientId");
5369
5901
  return;
5370
5902
  }
5371
- const code = await engine.compileEntry(id, clientId);
5903
+ const output = await engine.compileEntry(id, clientId);
5904
+ if (output.sourcemap && output.sourcemapFilename) {
5905
+ memoryFiles.set(output.sourcemapFilename, output.sourcemap);
5906
+ }
5907
+ res.once("finish", () => {
5908
+ void engine.notifyPayloadDelivered(output.filename).catch(
5909
+ (err) => debug7?.(`notifyPayloadDelivered failed: ${err?.message ?? err}`)
5910
+ );
5911
+ });
5372
5912
  res.setHeader("Content-Type", "application/javascript");
5373
5913
  res.setHeader("Cache-Control", "no-store");
5374
- res.end(code + "\n;export {}");
5914
+ res.end(output.code + "\n;export {}");
5375
5915
  return;
5376
5916
  }
5377
5917
  const patchHit = patches.get(pathname.replace(/^\//, ""));
@@ -5392,6 +5932,11 @@ async function createBundledDevServer(opts) {
5392
5932
  res.setHeader("ETag", hit.etag);
5393
5933
  res.setHeader("Content-Type", MIME_TYPES[path14.extname(fileName)] ?? "application/octet-stream");
5394
5934
  res.setHeader("Cache-Control", "no-cache");
5935
+ res.once("finish", () => {
5936
+ void engine.notifyPayloadDelivered(fileName).catch(
5937
+ (err) => debug7?.(`notifyPayloadDelivered failed: ${err?.message ?? err}`)
5938
+ );
5939
+ });
5395
5940
  res.end(hit.content);
5396
5941
  return;
5397
5942
  }
@@ -5491,7 +6036,7 @@ async function renderBundledIndexHtml(html, config, entryFileNames) {
5491
6036
  }
5492
6037
  return processed;
5493
6038
  }
5494
- var debug6, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
6039
+ var debug7, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
5495
6040
  var init_dev_engine = __esm({
5496
6041
  "src/server/bundled/dev-engine.ts"() {
5497
6042
  "use strict";
@@ -5500,7 +6045,7 @@ var init_dev_engine = __esm({
5500
6045
  init_transformer();
5501
6046
  init_middleware();
5502
6047
  init_debug();
5503
- debug6 = createDebugger("nasti:bundled");
6048
+ debug7 = createDebugger("nasti:bundled");
5504
6049
  MIME_TYPES = {
5505
6050
  ".js": "application/javascript",
5506
6051
  ".mjs": "application/javascript",
@@ -5634,7 +6179,7 @@ async function createServer(inlineConfig = {}) {
5634
6179
  const ws = createWebSocketServer(httpServer);
5635
6180
  const pluginApi = getPluginApi(config);
5636
6181
  const clientEnv = new NastiEnvironment("client", config, {
5637
- hot: createWsHotChannel(ws),
6182
+ hot: createWsHotChannel(ws, "client"),
5638
6183
  mode: "dev",
5639
6184
  plugins: allPlugins,
5640
6185
  pluginApi
@@ -5649,13 +6194,40 @@ async function createServer(inlineConfig = {}) {
5649
6194
  environmentName: name
5650
6195
  });
5651
6196
  environments[name] = new NastiEnvironment(name, config, {
6197
+ hot: consumer === "client" ? createWsHotChannel(ws, name) : void 0,
5652
6198
  mode: "dev",
5653
6199
  plugins: envPlugins,
5654
6200
  pluginApi
5655
6201
  });
5656
6202
  }
5657
6203
  for (const [name, environment] of Object.entries(environments)) {
5658
- if (name !== "client" && environment.options.driver) await environment.init();
6204
+ if (name === "client" || environment.consumer === "client" || environment.options.driver) {
6205
+ await environment.init();
6206
+ }
6207
+ }
6208
+ const transformContexts = /* @__PURE__ */ new Map();
6209
+ for (const environment of Object.values(environments)) {
6210
+ if (environment.consumer !== "client" || environment.driver) continue;
6211
+ const environmentConfig = {
6212
+ ...configWithPlugins,
6213
+ resolve: environment.options.resolve,
6214
+ build: environment.options.build,
6215
+ plugins: environment.plugins
6216
+ };
6217
+ const context = {
6218
+ config: environmentConfig,
6219
+ pluginContainer: environment.pluginContainer,
6220
+ moduleGraph: environment.moduleGraph,
6221
+ environment,
6222
+ envDefine: buildEnvDefine(
6223
+ loadEnv(environmentConfig.mode, environmentConfig.root, environmentConfig.envPrefix),
6224
+ environmentConfig.mode,
6225
+ ssrDefineOverrides(environment.consumer)
6226
+ ),
6227
+ onPrune: (paths) => environment.hot.send({ type: "prune", paths })
6228
+ };
6229
+ transformContexts.set(environment.name, context);
6230
+ environment.configureDevPipeline((url) => transformRequest(url, context));
5659
6231
  }
5660
6232
  let ssrRunner = null;
5661
6233
  async function getSsrRunner() {
@@ -5670,7 +6242,6 @@ async function createServer(inlineConfig = {}) {
5670
6242
  return ssrRunner;
5671
6243
  }
5672
6244
  const moduleGraph = clientEnv.moduleGraph;
5673
- const pluginContainer = clientEnv.pluginContainer;
5674
6245
  let bundledServer = null;
5675
6246
  if (config.experimental.bundledDev) {
5676
6247
  const { createBundledDevServer: createBundledDevServer2 } = await Promise.resolve().then(() => (init_dev_engine(), dev_engine_exports));
@@ -5699,6 +6270,15 @@ async function createServer(inlineConfig = {}) {
5699
6270
  let server;
5700
6271
  const environmentServices = {};
5701
6272
  let environmentDriversStarted = false;
6273
+ let devPipelinesStarted = false;
6274
+ const startDevPipelines = async () => {
6275
+ if (devPipelinesStarted) return;
6276
+ devPipelinesStarted = true;
6277
+ for (const environment of Object.values(environments)) {
6278
+ if (!transformContexts.has(environment.name)) continue;
6279
+ await environment.pluginContainer.buildStart();
6280
+ }
6281
+ };
5702
6282
  const logCloseError = (target, error) => {
5703
6283
  const normalized = error instanceof Error ? error : new Error(String(error));
5704
6284
  logger.error(`[nasti] failed to close ${target}`, { error: normalized });
@@ -5750,14 +6330,61 @@ async function createServer(inlineConfig = {}) {
5750
6330
  });
5751
6331
  }
5752
6332
  };
6333
+ const updateClientEnvironments = async (file) => {
6334
+ const timestamp = Date.now();
6335
+ const results = {};
6336
+ for (const environment of Object.values(environments)) {
6337
+ if (environment.consumer !== "client" || environment.driver) continue;
6338
+ try {
6339
+ const result = await handleFileChange(file, server, environment.name, timestamp);
6340
+ if (result) results[environment.name] = result;
6341
+ } catch (error) {
6342
+ const normalized = error instanceof Error ? error : new Error(String(error));
6343
+ logger.error(
6344
+ `[nasti] HMR failed for environment "${environment.name}": ${normalized.message}`,
6345
+ { error: normalized }
6346
+ );
6347
+ try {
6348
+ environment.hot.send({
6349
+ type: "error",
6350
+ err: { message: normalized.message, stack: normalized.stack }
6351
+ });
6352
+ } catch (channelError) {
6353
+ const channelFailure = channelError instanceof Error ? channelError : new Error(String(channelError));
6354
+ logger.error(
6355
+ `[nasti] failed to deliver HMR error to environment "${environment.name}"`,
6356
+ { error: channelFailure }
6357
+ );
6358
+ }
6359
+ }
6360
+ }
6361
+ if (Object.keys(results).length === 0) return;
6362
+ const context = {
6363
+ file,
6364
+ timestamp,
6365
+ environments: Object.freeze({ ...results }),
6366
+ server
6367
+ };
6368
+ for (const plugin of config.plugins) {
6369
+ await plugin.handleHotUpdateApp?.(context);
6370
+ }
6371
+ };
6372
+ const queueClientEnvironmentUpdate = (file) => {
6373
+ void updateClientEnvironments(file).catch((error) => {
6374
+ const normalized = error instanceof Error ? error : new Error(String(error));
6375
+ logger.error(`[nasti] multi-environment HMR failed: ${normalized.message}`, {
6376
+ error: normalized
6377
+ });
6378
+ });
6379
+ };
5753
6380
  watcher.on("change", (file) => {
5754
6381
  ssrRunner?.invalidateFile(file);
5755
- handleFileChange(file, server);
6382
+ queueClientEnvironmentUpdate(file);
5756
6383
  notifyEnvironmentDrivers(file, "change");
5757
6384
  });
5758
6385
  watcher.on("add", (file) => {
5759
6386
  ssrRunner?.invalidateFile(file);
5760
- handleFileChange(file, server);
6387
+ queueClientEnvironmentUpdate(file);
5761
6388
  notifyEnvironmentDrivers(file, "add");
5762
6389
  });
5763
6390
  watcher.on("unlink", (file) => {
@@ -5775,7 +6402,7 @@ async function createServer(inlineConfig = {}) {
5775
6402
  async listen(port) {
5776
6403
  const finalPort = port ?? config.server.port;
5777
6404
  const host = config.server.host === true ? "0.0.0.0" : config.server.host;
5778
- await pluginContainer.buildStart();
6405
+ await startDevPipelines();
5779
6406
  await startEnvironmentDrivers();
5780
6407
  return new Promise((resolve, reject) => {
5781
6408
  let currentPort = finalPort;
@@ -5790,7 +6417,7 @@ async function createServer(inlineConfig = {}) {
5790
6417
  const readyIn = Math.ceil(performance.now() - startTime);
5791
6418
  logger.info(
5792
6419
  `
5793
- ${pc8.cyan(pc8.bold("NASTI"))} ${pc8.cyan(`v${"2.4.0"}`)} ${pc8.dim("ready in")} ${pc8.bold(readyIn)} ${pc8.dim("ms")}
6420
+ ${pc8.cyan(pc8.bold("NASTI"))} ${pc8.cyan(`v${"2.4.2"}`)} ${pc8.dim("ready in")} ${pc8.bold(readyIn)} ${pc8.dim("ms")}
5794
6421
  `
5795
6422
  );
5796
6423
  printServerUrls(
@@ -5817,20 +6444,26 @@ async function createServer(inlineConfig = {}) {
5817
6444
  });
5818
6445
  },
5819
6446
  async transformRequest(url) {
5820
- const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
5821
- return transformRequest2(url, {
5822
- config: configWithPlugins,
5823
- pluginContainer,
5824
- moduleGraph,
5825
- onPrune: (paths) => ws.send({ type: "prune", paths })
5826
- });
6447
+ return clientEnv.transformRequest(url);
6448
+ },
6449
+ async transformEnvironmentRequest(environmentName, url) {
6450
+ const environment = environments[environmentName];
6451
+ if (!environment) {
6452
+ throw new Error(`[nasti] unknown dev environment "${environmentName}"`);
6453
+ }
6454
+ return environment.transformRequest(url);
5827
6455
  },
5828
6456
  async ssrLoadModule(url) {
5829
6457
  const runner = await getSsrRunner();
5830
6458
  return runner.import(url);
5831
6459
  },
5832
6460
  async close() {
5833
- await pluginContainer.buildEnd();
6461
+ if (devPipelinesStarted) {
6462
+ for (const environment of Object.values(environments).reverse()) {
6463
+ if (!transformContexts.has(environment.name)) continue;
6464
+ await environment.pluginContainer.buildEnd();
6465
+ }
6466
+ }
5834
6467
  await bundledServer?.close();
5835
6468
  let environmentCloseFailed = false;
5836
6469
  let firstEnvironmentCloseError;
@@ -5880,12 +6513,7 @@ async function createServer(inlineConfig = {}) {
5880
6513
  }
5881
6514
  throw error;
5882
6515
  }
5883
- app.use(transformMiddleware({
5884
- config: configWithPlugins,
5885
- pluginContainer,
5886
- moduleGraph,
5887
- onPrune: (paths) => ws.send({ type: "prune", paths })
5888
- }));
6516
+ app.use(transformMiddleware(transformContexts.get("client")));
5889
6517
  const publicDir = path15.resolve(config.root, "public");
5890
6518
  app.use(sirv(publicDir, { dev: true, etag: true }));
5891
6519
  app.use(sirv(config.root, { dev: true, etag: true }));
@@ -5924,6 +6552,7 @@ var init_server = __esm({
5924
6552
  init_hmr();
5925
6553
  init_builtins();
5926
6554
  init_plugin_api();
6555
+ init_env();
5927
6556
  }
5928
6557
  });
5929
6558
 
@@ -5982,7 +6611,7 @@ async function buildElectron(inlineConfig = {}) {
5982
6611
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
5983
6612
  const startTime = performance.now();
5984
6613
  assertElectronVersion(config);
5985
- console.log(pc9.cyan("\n\u26A1 nasti build (electron)") + pc9.dim(` v${"2.4.0"}`));
6614
+ console.log(pc9.cyan("\n\u26A1 nasti build (electron)") + pc9.dim(` v${"2.4.2"}`));
5986
6615
  console.log(pc9.dim(` root: ${config.root}`));
5987
6616
  console.log(pc9.dim(` mode: ${config.mode}`));
5988
6617
  console.log(pc9.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -6163,7 +6792,7 @@ async function startElectronDev(inlineConfig = {}) {
6163
6792
  const { noSpawn, ...rest } = inlineConfig;
6164
6793
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
6165
6794
  warnElectronVersion(config);
6166
- console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.4.0"}`));
6795
+ console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.4.2"}`));
6167
6796
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
6168
6797
  const server = await createServer2({
6169
6798
  ...rest,
@@ -6520,7 +7149,7 @@ cli.command("preview [root]", "Preview production build").option("--port <port>"
6520
7149
  const host = options.host === true ? "0.0.0.0" : options.host ?? "localhost";
6521
7150
  http2.createServer(app).listen(port, host, () => {
6522
7151
  logger.info(`
6523
- ${pc11.cyan(pc11.bold("NASTI"))} ${pc11.cyan(`v${"2.4.0"}`)} ${pc11.dim("preview")}
7152
+ ${pc11.cyan(pc11.bold("NASTI"))} ${pc11.cyan(`v${"2.4.2"}`)} ${pc11.dim("preview")}
6524
7153
  `);
6525
7154
  printServerUrls2(
6526
7155
  {
@@ -6537,6 +7166,6 @@ cli.command("preview [root]", "Preview production build").option("--port <port>"
6537
7166
  }
6538
7167
  });
6539
7168
  cli.help();
6540
- cli.version("2.4.0");
7169
+ cli.version("2.4.2");
6541
7170
  cli.parse();
6542
7171
  //# sourceMappingURL=cli.js.map