@nasti-toolchain/nasti 1.7.1 → 2.0.1

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.cjs CHANGED
@@ -5,9 +5,17 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __glob = (map) => (path17) => {
9
+ var fn = map[path17];
10
+ if (fn) return fn();
11
+ throw new Error("Module not found in bundle: " + path17);
12
+ };
8
13
  var __esm = (fn, res) => function __init() {
9
14
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
15
  };
16
+ var __commonJS = (cb, mod) => function __require2() {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ };
11
19
  var __export = (target, all) => {
12
20
  for (var name in all)
13
21
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -29,8 +37,127 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
29
37
  mod
30
38
  ));
31
39
 
40
+ // src/core/logger.ts
41
+ var logger_exports = {};
42
+ __export(logger_exports, {
43
+ LogLevels: () => LogLevels,
44
+ createLogger: () => createLogger,
45
+ printServerUrls: () => printServerUrls
46
+ });
47
+ function getTimeFormatter() {
48
+ return new Intl.DateTimeFormat(void 0, {
49
+ hour: "numeric",
50
+ minute: "numeric",
51
+ second: "numeric"
52
+ });
53
+ }
54
+ function createLogger(level = "info", options = {}) {
55
+ if (options.customLogger) {
56
+ return options.customLogger;
57
+ }
58
+ const timeFormatter = getTimeFormatter();
59
+ const loggedErrors = /* @__PURE__ */ new WeakSet();
60
+ const { prefix = "[nasti]", allowClearScreen = true, console: console_ = console } = options;
61
+ const thresh = LogLevels[level];
62
+ const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
63
+ const clear = canClearScreen ? clearScreen : () => {
64
+ };
65
+ function format(type, msg, options2 = {}) {
66
+ if (options2.timestamp) {
67
+ const tag = type === "info" ? import_picocolors.default.cyan(import_picocolors.default.bold(prefix)) : type === "warn" ? import_picocolors.default.yellow(import_picocolors.default.bold(prefix)) : import_picocolors.default.red(import_picocolors.default.bold(prefix));
68
+ return `${import_picocolors.default.dim(timeFormatter.format(/* @__PURE__ */ new Date()))} ${tag} ${msg}`;
69
+ }
70
+ return msg;
71
+ }
72
+ function output(type, msg, options2 = {}) {
73
+ if (thresh < LogLevels[type]) return;
74
+ const method = type === "info" ? "log" : type;
75
+ if (options2.error) {
76
+ loggedErrors.add(options2.error);
77
+ }
78
+ if (canClearScreen) {
79
+ if (type === lastType && msg === lastMsg) {
80
+ sameCount++;
81
+ clear();
82
+ console_[method](format(type, msg, options2), import_picocolors.default.yellow(`(x${sameCount + 1})`));
83
+ } else {
84
+ sameCount = 0;
85
+ lastMsg = msg;
86
+ lastType = type;
87
+ if (options2.clear) clear();
88
+ console_[method](format(type, msg, options2));
89
+ }
90
+ } else {
91
+ console_[method](format(type, msg, options2));
92
+ }
93
+ }
94
+ const warnedMessages = /* @__PURE__ */ new Set();
95
+ const logger = {
96
+ hasWarned: false,
97
+ info(msg, opts) {
98
+ output("info", msg, opts);
99
+ },
100
+ warn(msg, opts) {
101
+ logger.hasWarned = true;
102
+ output("warn", msg, opts);
103
+ },
104
+ warnOnce(msg, opts) {
105
+ if (warnedMessages.has(msg)) return;
106
+ logger.hasWarned = true;
107
+ output("warn", msg, opts);
108
+ warnedMessages.add(msg);
109
+ },
110
+ error(msg, opts) {
111
+ output("error", msg, opts);
112
+ },
113
+ clearScreen(type) {
114
+ if (thresh >= LogLevels[type]) clear();
115
+ },
116
+ hasErrorLogged(error) {
117
+ return loggedErrors.has(error);
118
+ }
119
+ };
120
+ return logger;
121
+ }
122
+ function clearScreen() {
123
+ const repeatCount = process.stdout.rows - 2;
124
+ const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
125
+ console.log(blank);
126
+ import_node_readline.default.cursorTo(process.stdout, 0, 0);
127
+ import_node_readline.default.clearScreenDown(process.stdout);
128
+ }
129
+ function printServerUrls(urls, info) {
130
+ const colorUrl = (url) => import_picocolors.default.cyan(url.replace(/:(\d+)\//, (_, port) => `:${import_picocolors.default.bold(port)}/`));
131
+ for (const url of urls.local) {
132
+ info(` ${import_picocolors.default.green("\u279C")} ${import_picocolors.default.bold("Local")}: ${colorUrl(url)}`);
133
+ }
134
+ for (const url of urls.network) {
135
+ info(` ${import_picocolors.default.green("\u279C")} ${import_picocolors.default.bold("Network")}: ${colorUrl(url)}`);
136
+ }
137
+ if (urls.network.length === 0) {
138
+ info(
139
+ import_picocolors.default.dim(` ${import_picocolors.default.green("\u279C")} ${import_picocolors.default.bold("Network")}: use `) + import_picocolors.default.bold("--host") + import_picocolors.default.dim(" to expose")
140
+ );
141
+ }
142
+ }
143
+ var import_node_readline, import_picocolors, LogLevels, lastType, lastMsg, sameCount;
144
+ var init_logger = __esm({
145
+ "src/core/logger.ts"() {
146
+ "use strict";
147
+ import_node_readline = __toESM(require("readline"), 1);
148
+ import_picocolors = __toESM(require("picocolors"), 1);
149
+ LogLevels = {
150
+ silent: 0,
151
+ error: 1,
152
+ warn: 2,
153
+ info: 3
154
+ };
155
+ sameCount = 0;
156
+ }
157
+ });
158
+
32
159
  // src/config/defaults.ts
33
- var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaults;
160
+ var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaults;
34
161
  var init_defaults = __esm({
35
162
  "src/config/defaults.ts"() {
36
163
  "use strict";
@@ -57,7 +184,12 @@ var init_defaults = __esm({
57
184
  target: "es2022",
58
185
  rolldownOptions: {},
59
186
  emptyOutDir: true,
60
- css: {}
187
+ css: {},
188
+ reportCompressedSize: true,
189
+ chunkSizeWarningLimit: 500,
190
+ cssCodeSplit: true,
191
+ // 默认跟随 build.minify(resolveConfig 中按 minify 取值填充)
192
+ cssMinify: true
61
193
  };
62
194
  defaultElectron = {
63
195
  main: "src/electron/main.ts",
@@ -72,6 +204,9 @@ var init_defaults = __esm({
72
204
  minVersion: 41,
73
205
  external: ["electron"]
74
206
  };
207
+ defaultExperimental = {
208
+ bundledDev: false
209
+ };
75
210
  defaults = {
76
211
  root: ".",
77
212
  base: "/",
@@ -84,7 +219,9 @@ var init_defaults = __esm({
84
219
  electron: defaultElectron,
85
220
  plugins: [],
86
221
  envPrefix: ["NASTI_", "VITE_"],
87
- logLevel: "info"
222
+ logLevel: "info",
223
+ clearScreen: true,
224
+ experimental: defaultExperimental
88
225
  };
89
226
  }
90
227
  });
@@ -146,17 +283,28 @@ async function resolveConfig(inlineConfig = {}, command) {
146
283
  ...fileConfig.plugins ?? [],
147
284
  ...inlineConfig.plugins ?? []
148
285
  ];
149
- const env = { mode: merged.mode ?? defaults.mode, command };
286
+ const mode = merged.mode ?? (command === "build" ? "production" : "development");
287
+ const env = { mode, command };
150
288
  for (const plugin of rawPlugins) {
151
289
  if (plugin.config) {
152
290
  const result = await plugin.config(merged, env);
153
291
  if (result) Object.assign(merged, result);
154
292
  }
155
293
  }
294
+ const logLevel = merged.logLevel ?? defaults.logLevel;
295
+ const clearScreen2 = merged.clearScreen ?? defaults.clearScreen;
296
+ const logger = createLogger(logLevel, {
297
+ allowClearScreen: clearScreen2,
298
+ customLogger: merged.customLogger
299
+ });
300
+ const mergedBuild = { ...defaults.build, ...merged.build };
301
+ if (merged.build?.cssMinify === void 0) {
302
+ mergedBuild.cssMinify = !!mergedBuild.minify;
303
+ }
156
304
  const resolved = {
157
305
  root,
158
306
  base: merged.base ?? defaults.base,
159
- mode: command === "build" ? "production" : "development",
307
+ mode,
160
308
  target: merged.target ?? defaults.target,
161
309
  framework: merged.framework ?? defaults.framework,
162
310
  command,
@@ -169,11 +317,70 @@ async function resolveConfig(inlineConfig = {}, command) {
169
317
  },
170
318
  plugins: [],
171
319
  server: { ...defaults.server, ...merged.server },
172
- build: { ...defaults.build, ...merged.build },
320
+ build: mergedBuild,
173
321
  electron: { ...defaults.electron, ...merged.electron },
174
322
  envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
175
- logLevel: merged.logLevel ?? defaults.logLevel
323
+ logLevel,
324
+ clearScreen: clearScreen2,
325
+ logger,
326
+ environments: {},
327
+ experimental: {
328
+ bundledDev: merged.experimental?.bundledDev ?? defaults.experimental.bundledDev
329
+ }
176
330
  };
331
+ const userEnvironments = {
332
+ client: {},
333
+ ssr: {},
334
+ ...merged.environments ?? {}
335
+ };
336
+ for (const [name, envOptions] of Object.entries(userEnvironments)) {
337
+ for (const plugin of rawPlugins) {
338
+ if (plugin.configEnvironment) {
339
+ const result = await plugin.configEnvironment(name, envOptions, env);
340
+ if (result) Object.assign(envOptions, deepMerge(envOptions, result));
341
+ }
342
+ }
343
+ }
344
+ for (const [name, envOptions] of Object.entries(userEnvironments)) {
345
+ const consumer = envOptions.consumer ?? (name === "client" ? "client" : "server");
346
+ if (name === "client") {
347
+ if (envOptions.resolve) {
348
+ Object.assign(resolved.resolve, {
349
+ ...envOptions.resolve,
350
+ alias: { ...resolved.resolve.alias, ...envOptions.resolve.alias }
351
+ });
352
+ }
353
+ if (envOptions.build) Object.assign(resolved.build, envOptions.build);
354
+ resolved.environments.client = {
355
+ consumer,
356
+ entry: [],
357
+ // 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
358
+ resolve: resolved.resolve,
359
+ build: resolved.build
360
+ };
361
+ continue;
362
+ }
363
+ resolved.environments[name] = {
364
+ consumer,
365
+ entry: (Array.isArray(envOptions.entry) ? envOptions.entry : envOptions.entry ? [envOptions.entry] : []).map((e) => import_node_path.default.resolve(root, e)),
366
+ resolve: {
367
+ alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
368
+ extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
369
+ // server consumer:node conditions(去 'browser');client 非默认环境沿用 top-level
370
+ conditions: envOptions.resolve?.conditions ?? (consumer === "server" ? ["node", ...resolved.resolve.conditions.filter((c) => c !== "browser")] : [...resolved.resolve.conditions]),
371
+ mainFields: envOptions.resolve?.mainFields ?? (consumer === "server" ? ["module", "main"] : [...resolved.resolve.mainFields])
372
+ },
373
+ build: {
374
+ ...resolved.build,
375
+ ...envOptions.build,
376
+ // 非 client 环境默认产出到 <outDir>/<envName>(如 dist/ssr),可显式覆盖
377
+ outDir: envOptions.build?.outDir ?? import_node_path.default.join(resolved.build.outDir, name),
378
+ // server 产物默认不压缩(可调试性优先,与 Vite SSR 默认一致),可显式覆盖
379
+ minify: envOptions.build?.minify ?? (consumer === "server" ? false : resolved.build.minify)
380
+ }
381
+ };
382
+ }
383
+ assertClientEnvironmentMirror(resolved);
177
384
  const filteredPlugins = rawPlugins.filter((p) => {
178
385
  if (!p.apply) return true;
179
386
  if (typeof p.apply === "function") return p.apply(resolved, env);
@@ -262,11 +469,40 @@ function hasDotNodeFile(dir, depth = 0) {
262
469
  }
263
470
  return false;
264
471
  }
472
+ function assertClientEnvironmentMirror(config) {
473
+ if (process.env.NASTI_DISABLE_MIRROR_ASSERT) return;
474
+ const client = config.environments.client;
475
+ if (!client) {
476
+ throw new Error("[nasti] internal: environments.client missing after resolveConfig");
477
+ }
478
+ if (client.resolve === config.resolve && client.build === config.build) return;
479
+ const pairs = [
480
+ ["resolve", config.resolve, client.resolve],
481
+ ["build", config.build, client.build]
482
+ ];
483
+ for (const [field, top, env] of pairs) {
484
+ const a = JSON.stringify(top);
485
+ const b = JSON.stringify(env);
486
+ if (a !== b) {
487
+ throw new Error(
488
+ `[nasti] config mirror violation: top-level \`${field}\` and \`environments.client.${field}\` diverged.
489
+ top-level: ${a}
490
+ client: ${b}
491
+ top-level \u4E0E client \u73AF\u5883\u5FC5\u987B\u7CBE\u786E\u955C\u50CF \u2014\u2014 \u8BF7\u901A\u8FC7 top-level \u6216 environments.client \u4E4B\u4E00\u914D\u7F6E\uFF0C\u4E0D\u8981\u5728\u89E3\u6790\u540E\u5206\u522B\u4FEE\u6539\u4E24\u8005\u3002`
492
+ );
493
+ }
494
+ }
495
+ }
496
+ function isPlainObject(val) {
497
+ if (val === null || typeof val !== "object") return false;
498
+ const proto = Object.getPrototypeOf(val);
499
+ return proto === Object.prototype || proto === null;
500
+ }
265
501
  function deepMerge(target, source) {
266
502
  const result = { ...target };
267
503
  for (const key of Object.keys(source)) {
268
504
  const val = source[key];
269
- if (val && typeof val === "object" && !Array.isArray(val)) {
505
+ if (isPlainObject(val)) {
270
506
  result[key] = deepMerge(
271
507
  result[key] ?? {},
272
508
  val
@@ -285,6 +521,7 @@ var init_config = __esm({
285
521
  import_node_path = __toESM(require("path"), 1);
286
522
  import_node_fs = __toESM(require("fs"), 1);
287
523
  init_defaults();
524
+ init_logger();
288
525
  CONFIG_FILES = [
289
526
  "nasti.config.ts",
290
527
  "nasti.config.js",
@@ -315,8 +552,11 @@ var init_plugin_container = __esm({
315
552
  config;
316
553
  ctx;
317
554
  emittedFiles = /* @__PURE__ */ new Map();
318
- constructor(config) {
555
+ /** Environment API:容器所属环境(未传时为 undefined,行为同 1.x client) */
556
+ environment;
557
+ constructor(config, environment) {
319
558
  this.config = config;
559
+ this.environment = environment;
320
560
  this.plugins = sortPlugins(config.plugins);
321
561
  this.ctx = this.createContext();
322
562
  }
@@ -337,7 +577,8 @@ var init_plugin_container = __esm({
337
577
  },
338
578
  getModuleInfo(_id) {
339
579
  return null;
340
- }
580
+ },
581
+ environment: container.environment
341
582
  };
342
583
  }
343
584
  /** 返回所有通过 emitFile() 输出的文件 */
@@ -359,13 +600,14 @@ var init_plugin_container = __esm({
359
600
  }
360
601
  }
361
602
  async resolveId(source, importer, options = {}) {
603
+ const ssr = this.environment?.consumer === "server";
362
604
  for (const plugin of this.plugins) {
363
605
  if (!plugin.resolveId) continue;
364
606
  const result = await plugin.resolveId.call(
365
607
  this.ctx,
366
608
  source,
367
609
  importer ?? void 0,
368
- { isEntry: options.isEntry ?? false, ssr: false }
610
+ { isEntry: options.isEntry ?? false, ssr }
369
611
  );
370
612
  if (result != null) return result;
371
613
  }
@@ -539,6 +781,171 @@ var init_module_graph = __esm({
539
781
  }
540
782
  });
541
783
 
784
+ // src/core/hot-channel.ts
785
+ function createNoopHotChannel() {
786
+ return {
787
+ send() {
788
+ },
789
+ on() {
790
+ },
791
+ off() {
792
+ },
793
+ listen() {
794
+ },
795
+ close() {
796
+ },
797
+ setInvokeHandler() {
798
+ }
799
+ };
800
+ }
801
+ function createWsHotChannel(ws) {
802
+ const listeners = /* @__PURE__ */ new Map();
803
+ let invokeHandlers;
804
+ return {
805
+ send(payload) {
806
+ ws.send(payload);
807
+ },
808
+ on(event, listener) {
809
+ let set = listeners.get(event);
810
+ if (!set) listeners.set(event, set = /* @__PURE__ */ new Set());
811
+ set.add(listener);
812
+ },
813
+ off(event, listener) {
814
+ listeners.get(event)?.delete(listener);
815
+ },
816
+ listen() {
817
+ },
818
+ close() {
819
+ ws.close();
820
+ },
821
+ setInvokeHandler(handlers) {
822
+ invokeHandlers = handlers;
823
+ void invokeHandlers;
824
+ }
825
+ };
826
+ }
827
+ var init_hot_channel = __esm({
828
+ "src/core/hot-channel.ts"() {
829
+ "use strict";
830
+ }
831
+ });
832
+
833
+ // src/core/debug.ts
834
+ function createDebugger(namespace, options = {}) {
835
+ if (!DEBUG) return void 0;
836
+ const patterns = DEBUG.split(",").map((p) => p.trim());
837
+ const enabled = patterns.some((p) => {
838
+ if (p === "*" || p === "nasti:*" || p === "vite:*") return true;
839
+ const normalized = p.startsWith("vite:") ? `nasti:${p.slice(5)}` : p;
840
+ return normalized === namespace;
841
+ });
842
+ if (!enabled) return void 0;
843
+ if (options.onlyWhenFocused) {
844
+ const focus = typeof options.onlyWhenFocused === "string" ? options.onlyWhenFocused : namespace;
845
+ if (!patterns.includes(focus)) return void 0;
846
+ }
847
+ let lastTime = performance.now();
848
+ return (...args) => {
849
+ const now = performance.now();
850
+ const elapsed = now - lastTime;
851
+ lastTime = now;
852
+ const msg = args.map((a) => {
853
+ if (typeof a === "string") return a;
854
+ try {
855
+ return JSON.stringify(a);
856
+ } catch {
857
+ return String(a);
858
+ }
859
+ }).join(" ");
860
+ if (filter && !msg.includes(filter)) return;
861
+ console.debug(
862
+ `${import_picocolors2.default.magenta(namespace)} ${msg} ${import_picocolors2.default.dim(`+${Math.round(elapsed)}ms`)}`
863
+ );
864
+ };
865
+ }
866
+ var import_picocolors2, DEBUG, filter;
867
+ var init_debug = __esm({
868
+ "src/core/debug.ts"() {
869
+ "use strict";
870
+ import_picocolors2 = __toESM(require("picocolors"), 1);
871
+ DEBUG = process.env.DEBUG;
872
+ filter = process.env.NASTI_DEBUG_FILTER || process.env.VITE_DEBUG_FILTER;
873
+ }
874
+ });
875
+
876
+ // src/core/environment.ts
877
+ function resolveEnvironmentPlugins(environment, plugins) {
878
+ return plugins.filter((p) => {
879
+ if (!p.applyToEnvironment) return true;
880
+ try {
881
+ return p.applyToEnvironment(environment);
882
+ } catch (err) {
883
+ environment.config.logger.error(
884
+ `[nasti] plugin "${p.name}" applyToEnvironment threw: ${err.message}`,
885
+ { error: err }
886
+ );
887
+ return false;
888
+ }
889
+ });
890
+ }
891
+ var debug, NastiEnvironment;
892
+ var init_environment = __esm({
893
+ "src/core/environment.ts"() {
894
+ "use strict";
895
+ init_plugin_container();
896
+ init_module_graph();
897
+ init_hot_channel();
898
+ init_debug();
899
+ debug = createDebugger("nasti:environment");
900
+ NastiEnvironment = class {
901
+ name;
902
+ consumer;
903
+ mode;
904
+ config;
905
+ options;
906
+ hot;
907
+ /** applyToEnvironment 过滤后的插件(init() 后可用) */
908
+ plugins = [];
909
+ /** per-env 插件容器(init() 后可用;dev 管线使用) */
910
+ pluginContainer = null;
911
+ /** per-env 模块图(dev 管线使用) */
912
+ moduleGraph;
913
+ candidatePlugins;
914
+ initialized = false;
915
+ constructor(name, config, init = {}) {
916
+ const options = config.environments[name];
917
+ if (!options) {
918
+ throw new Error(
919
+ `[nasti] unknown environment "${name}" \u2014 declare it in config.environments`
920
+ );
921
+ }
922
+ this.name = name;
923
+ this.consumer = options.consumer;
924
+ this.mode = init.mode ?? (config.command === "build" ? "build" : "dev");
925
+ this.config = config;
926
+ this.options = options;
927
+ this.hot = init.hot ?? createNoopHotChannel();
928
+ this.moduleGraph = new ModuleGraph();
929
+ this.candidatePlugins = init.plugins ?? config.plugins;
930
+ }
931
+ /** 过滤插件并建 per-env PluginContainer */
932
+ async init() {
933
+ if (this.initialized) return;
934
+ this.initialized = true;
935
+ this.plugins = resolveEnvironmentPlugins(this, this.candidatePlugins);
936
+ this.pluginContainer = new PluginContainer(
937
+ { ...this.config, plugins: this.plugins },
938
+ this
939
+ );
940
+ debug?.(`env "${this.name}" initialized (${this.plugins.length} plugins)`);
941
+ }
942
+ async close() {
943
+ await this.hot.close?.();
944
+ }
945
+ };
946
+ }
947
+ });
948
+
542
949
  // src/server/ws.ts
543
950
  function createWebSocketServer(server) {
544
951
  const wss = new import_ws.WebSocketServer({ noServer: true });
@@ -738,7 +1145,7 @@ function loadEnv(mode, root, prefixes) {
738
1145
  }
739
1146
  return filtered;
740
1147
  }
741
- function buildEnvDefine(env, mode) {
1148
+ function buildEnvDefine(env, mode, overrides = {}) {
742
1149
  const define = {};
743
1150
  for (const [key, value] of Object.entries(env)) {
744
1151
  define[`import.meta.env.${key}`] = JSON.stringify(value);
@@ -747,7 +1154,10 @@ function buildEnvDefine(env, mode) {
747
1154
  define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
748
1155
  define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
749
1156
  define["import.meta.env.SSR"] = "false";
750
- return define;
1157
+ return { ...define, ...overrides };
1158
+ }
1159
+ function ssrDefineOverrides(consumer) {
1160
+ return { "import.meta.env.SSR": consumer === "server" ? "true" : "false" };
751
1161
  }
752
1162
  function replaceEnvInCode(code, define) {
753
1163
  let result = code;
@@ -770,6 +1180,7 @@ var init_env = __esm({
770
1180
  var middleware_exports = {};
771
1181
  __export(middleware_exports, {
772
1182
  REACT_REFRESH_GLOBAL_PREAMBLE: () => REACT_REFRESH_GLOBAL_PREAMBLE,
1183
+ getReactRefreshRuntimeEsm: () => getReactRefreshRuntimeEsm,
773
1184
  transformMiddleware: () => transformMiddleware,
774
1185
  transformRequest: () => transformRequest
775
1186
  });
@@ -908,7 +1319,11 @@ function transformMiddleware(ctx) {
908
1319
  return;
909
1320
  }
910
1321
  } catch (err) {
911
- console.error(`[nasti] Transform error: ${url}`, err.message);
1322
+ ctx.config.logger.error(
1323
+ import_picocolors3.default.red(`Transform error: ${url}
1324
+ `) + (err.stack ?? err.message),
1325
+ { timestamp: true, error: err }
1326
+ );
912
1327
  res.statusCode = 500;
913
1328
  res.end(`Transform error: ${err.message}`);
914
1329
  return;
@@ -927,6 +1342,28 @@ async function transformRequest(url, ctx) {
927
1342
  if (cleanReqUrl === "/@react-refresh") {
928
1343
  return { code: getReactRefreshRuntimeEsm() };
929
1344
  }
1345
+ if (cleanReqUrl.startsWith("/@modules/") && url.includes("?")) {
1346
+ const idParam = new URLSearchParams(url.slice(url.indexOf("?") + 1)).get("id");
1347
+ let realId = null;
1348
+ let realIdValid = false;
1349
+ try {
1350
+ if (idParam) {
1351
+ realId = import_node_fs4.default.realpathSync(idParam);
1352
+ realIdValid = import_node_fs4.default.statSync(realId).isFile() && (realId.includes(`${import_node_path4.default.sep}node_modules${import_node_path4.default.sep}`) || isUnderRoot(realId, config.root));
1353
+ }
1354
+ } catch {
1355
+ realId = null;
1356
+ realIdValid = false;
1357
+ }
1358
+ if (realId && realIdValid) {
1359
+ const mod2 = await moduleGraph.ensureEntryFromUrl(url);
1360
+ moduleGraph.registerModule(mod2, realId);
1361
+ const code2 = await bundlePackageAsEsm(realId, config.root);
1362
+ const transformResult2 = { code: code2 };
1363
+ mod2.transformResult = transformResult2;
1364
+ return transformResult2;
1365
+ }
1366
+ }
930
1367
  if (cleanReqUrl.startsWith("/@modules/")) {
931
1368
  const spec = cleanReqUrl.slice("/@modules/".length);
932
1369
  const virtual = await loadVirtualModule(spec, ctx);
@@ -937,12 +1374,34 @@ async function transformRequest(url, ctx) {
937
1374
  return virtual.result;
938
1375
  }
939
1376
  }
1377
+ const rawQuery = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
1378
+ if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
1379
+ const loaded = await pluginContainer.load(url);
1380
+ if (loaded != null) {
1381
+ let code2 = typeof loaded === "string" ? loaded : loaded.code;
1382
+ const transformed = await pluginContainer.transform(code2, url);
1383
+ if (transformed != null) {
1384
+ code2 = typeof transformed === "string" ? transformed : transformed.code;
1385
+ }
1386
+ const mod2 = await moduleGraph.ensureEntryFromUrl(url);
1387
+ moduleGraph.registerModule(mod2, cleanReqUrl);
1388
+ code2 = injectImportMetaHot(code2, url);
1389
+ code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
1390
+ loadEnv(config.mode, config.root, config.envPrefix),
1391
+ config.mode
1392
+ ));
1393
+ code2 = rewriteImports(code2, config, cleanReqUrl);
1394
+ const transformResult2 = { code: code2 };
1395
+ mod2.transformResult = transformResult2;
1396
+ return transformResult2;
1397
+ }
1398
+ }
940
1399
  const filePath = resolveUrlToFile(url, config.root);
941
1400
  if (!filePath || !import_node_fs4.default.existsSync(filePath)) return null;
942
1401
  const mod = await moduleGraph.ensureEntryFromUrl(url);
943
1402
  moduleGraph.registerModule(mod, filePath);
944
1403
  if (cleanReqUrl.startsWith("/@modules/")) {
945
- const code2 = await bundlePackageAsEsm(filePath);
1404
+ const code2 = await bundlePackageAsEsm(filePath, config.root);
946
1405
  const transformResult2 = { code: code2 };
947
1406
  mod.transformResult = transformResult2;
948
1407
  return transformResult2;
@@ -1005,17 +1464,17 @@ async function loadVirtualModule(spec, ctx) {
1005
1464
  code = rewriteImports(code, config, anchor);
1006
1465
  return { id: resolvedId, result: { code } };
1007
1466
  }
1008
- async function bundlePackageAsEsm(entryFile) {
1467
+ async function bundlePackageAsEsm(entryFile, root) {
1009
1468
  if (!esmBundleCache.has(entryFile)) {
1010
- esmBundleCache.set(entryFile, doBundlePackage(entryFile));
1469
+ esmBundleCache.set(entryFile, doBundlePackage(entryFile, root));
1011
1470
  }
1012
1471
  return esmBundleCache.get(entryFile);
1013
1472
  }
1014
- async function doBundlePackage(entryFile) {
1015
- const shim = await tryGenerateSubpathShim(entryFile);
1473
+ async function doBundlePackage(entryFile, root) {
1474
+ const shim = await tryGenerateSubpathShim(entryFile, root);
1016
1475
  if (shim != null) return shim;
1017
1476
  const { rolldown: rolldown4 } = await import("rolldown");
1018
- const bundle = await rolldown4({
1477
+ const bundle2 = await rolldown4({
1019
1478
  input: entryFile,
1020
1479
  // 仅将其他 npm 包外部化;相对路径(包内部文件)全部内联打包
1021
1480
  external: (id) => {
@@ -1023,27 +1482,28 @@ async function doBundlePackage(entryFile) {
1023
1482
  return true;
1024
1483
  }
1025
1484
  });
1026
- const result = await bundle.generate({ format: "esm", exports: "named" });
1027
- await bundle.close();
1485
+ const result = await bundle2.generate({ format: "esm", exports: "named" });
1486
+ await bundle2.close();
1028
1487
  let code = result.output[0].code;
1029
1488
  code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
1489
+ const externalBaseDir = import_node_path4.default.dirname(entryFile);
1030
1490
  code = code.replace(
1031
1491
  /^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
1032
- (_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
1492
+ (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir)}${q}`
1033
1493
  ).replace(
1034
1494
  /^(export\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
1035
- (_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
1495
+ (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir)}${q}`
1036
1496
  ).replace(
1037
1497
  /^(import\s+)(['"])([^'"./][^'"]*)(\2)/gm,
1038
- (_, prefix, q, spec) => `${prefix}${q}/@modules/${spec}${q}`
1498
+ (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir)}${q}`
1039
1499
  );
1040
- code = rewriteExternalRequires(code);
1500
+ code = rewriteExternalRequires(code, externalBaseDir);
1041
1501
  if (code.includes("__commonJSMin")) {
1042
1502
  code = await injectCjsNamedExports(code, entryFile);
1043
1503
  }
1044
1504
  return code;
1045
1505
  }
1046
- async function tryGenerateSubpathShim(entryFile) {
1506
+ async function tryGenerateSubpathShim(entryFile, root) {
1047
1507
  const NM = `${import_node_path4.default.sep}node_modules${import_node_path4.default.sep}`;
1048
1508
  if (!entryFile.includes(NM)) return null;
1049
1509
  let pkgDir = null;
@@ -1094,9 +1554,11 @@ async function tryGenerateSubpathShim(entryFile) {
1094
1554
  if (!("default" in mainNs)) return null;
1095
1555
  if (mainNs["default"] !== subNs["default"]) return null;
1096
1556
  }
1557
+ const rootMain = resolveNodeModule(root, pkgName);
1558
+ const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + import_node_path4.default.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
1097
1559
  const lines = [
1098
1560
  `// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
1099
- `import * as __pkg from "/@modules/${pkgName}";`
1561
+ `import * as __pkg from "${mainEntryUrl}";`
1100
1562
  ];
1101
1563
  for (const k of subKeys) {
1102
1564
  lines.push(`export const ${k} = __pkg[${JSON.stringify(k)}];`);
@@ -1140,7 +1602,7 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
1140
1602
  }
1141
1603
  return null;
1142
1604
  }
1143
- function rewriteExternalRequires(code) {
1605
+ function rewriteExternalRequires(code, baseDir) {
1144
1606
  const pkgs = /* @__PURE__ */ new Set();
1145
1607
  const re = /__require\(["']([^"']+)["']\)/g;
1146
1608
  let m;
@@ -1152,7 +1614,7 @@ function rewriteExternalRequires(code) {
1152
1614
  const imports = [];
1153
1615
  for (const pkg of pkgs) {
1154
1616
  const safe = pkg.replace(/[^a-zA-Z0-9_$]/g, "_");
1155
- imports.push(`import * as __ns_${safe} from "/@modules/${pkg}";`);
1617
+ imports.push(`import * as __ns_${safe} from "${externalSpecToModuleUrl(pkg, baseDir)}";`);
1156
1618
  imports.push(`var __req_${safe} = "default" in __ns_${safe} ? __ns_${safe}["default"] : __ns_${safe};`);
1157
1619
  result = result.replaceAll(`__require("${pkg}")`, `__req_${safe}`);
1158
1620
  result = result.replaceAll(`__require('${pkg}')`, `__req_${safe}`);
@@ -1161,8 +1623,8 @@ function rewriteExternalRequires(code) {
1161
1623
  }
1162
1624
  async function injectCjsNamedExports(code, entryFile) {
1163
1625
  try {
1164
- const { createRequire: createRequire5 } = await import("module");
1165
- const req = createRequire5(entryFile);
1626
+ const { createRequire: createRequire6 } = await import("module");
1627
+ const req = createRequire6(entryFile);
1166
1628
  const cjsExports = req(entryFile);
1167
1629
  if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
1168
1630
  const namedKeys = Object.keys(cjsExports).filter(
@@ -1249,7 +1711,20 @@ function isUnderRoot(abs, root) {
1249
1711
  const rel = import_node_path4.default.relative(root, abs);
1250
1712
  return !!rel && !rel.startsWith("..") && !import_node_path4.default.isAbsolute(rel);
1251
1713
  }
1252
- function resolveNodeModule(root, moduleName) {
1714
+ function externalSpecToModuleUrl(spec, baseDir) {
1715
+ const resolved = resolveNodeModule(baseDir, spec);
1716
+ return resolved ? `/@modules/${spec}?id=${encodeURIComponent(resolved)}` : `/@modules/${spec}`;
1717
+ }
1718
+ function resolveNodeModule(baseDir, moduleName) {
1719
+ const resolved = resolveNodeModuleEntry(baseDir, moduleName);
1720
+ if (!resolved) return null;
1721
+ try {
1722
+ return import_node_fs4.default.realpathSync(resolved);
1723
+ } catch {
1724
+ return resolved;
1725
+ }
1726
+ }
1727
+ function resolveNodeModuleEntry(root, moduleName) {
1253
1728
  let pkgName;
1254
1729
  let subpath;
1255
1730
  if (moduleName.startsWith("@")) {
@@ -1319,7 +1794,12 @@ function resolvePackageExports(exports2, key, pkgDir) {
1319
1794
  return key === "." ? import_node_path4.default.join(pkgDir, exports2) : null;
1320
1795
  }
1321
1796
  const entry = exports2[key];
1322
- if (entry === void 0) return null;
1797
+ if (entry === void 0) {
1798
+ if (key === "." && typeof exports2 === "object" && !Object.keys(exports2).some((k) => k.startsWith("."))) {
1799
+ return resolveExportValue(exports2, pkgDir);
1800
+ }
1801
+ return null;
1802
+ }
1323
1803
  return resolveExportValue(entry, pkgDir);
1324
1804
  }
1325
1805
  function resolveExportValue(value, pkgDir) {
@@ -1496,7 +1976,7 @@ export function createHotContext(ownerPath) {
1496
1976
  }
1497
1977
  `;
1498
1978
  }
1499
- var import_node_path4, import_node_fs4, import_node_module, import_node_url2, import_meta, __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
1979
+ var import_node_path4, import_node_fs4, import_node_module, import_node_url2, import_picocolors3, import_meta, __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
1500
1980
  var init_middleware = __esm({
1501
1981
  "src/server/middleware.ts"() {
1502
1982
  "use strict";
@@ -1504,6 +1984,7 @@ var init_middleware = __esm({
1504
1984
  import_node_fs4 = __toESM(require("fs"), 1);
1505
1985
  import_node_module = require("module");
1506
1986
  import_node_url2 = require("url");
1987
+ import_picocolors3 = __toESM(require("picocolors"), 1);
1507
1988
  init_transformer();
1508
1989
  init_html();
1509
1990
  init_env();
@@ -1528,7 +2009,9 @@ window.__vite_plugin_react_preamble_installed__ = true;
1528
2009
  // src/server/hmr.ts
1529
2010
  async function handleFileChange(file, server) {
1530
2011
  const { moduleGraph, ws, config } = server;
2012
+ const logger = config.logger;
1531
2013
  const relativePath = "/" + import_node_path5.default.relative(config.root, file);
2014
+ const shortFile = import_node_path5.default.relative(config.root, file);
1532
2015
  const mods = moduleGraph.getModulesByFile(file);
1533
2016
  if (!mods || mods.size === 0) {
1534
2017
  return;
@@ -1556,6 +2039,7 @@ async function handleFileChange(file, server) {
1556
2039
  for (const affected of affectedModules) {
1557
2040
  const boundaries = moduleGraph.getHmrBoundaries(affected);
1558
2041
  if (boundaries.length === 0) {
2042
+ logger.info(import_picocolors4.default.green("page reload ") + import_picocolors4.default.dim(shortFile), { timestamp: true });
1559
2043
  ws.send({ type: "full-reload", path: relativePath });
1560
2044
  return;
1561
2045
  }
@@ -1570,15 +2054,20 @@ async function handleFileChange(file, server) {
1570
2054
  }
1571
2055
  }
1572
2056
  if (updates.length > 0) {
2057
+ logger.info(
2058
+ updates.map((u) => import_picocolors4.default.green("hmr update ") + import_picocolors4.default.dim(u.path)).join("\n"),
2059
+ { timestamp: true }
2060
+ );
1573
2061
  ws.send({ type: "update", updates });
1574
2062
  }
1575
2063
  }
1576
- var import_node_path5, import_node_fs5;
2064
+ var import_node_path5, import_node_fs5, import_picocolors4;
1577
2065
  var init_hmr = __esm({
1578
2066
  "src/server/hmr.ts"() {
1579
2067
  "use strict";
1580
2068
  import_node_path5 = __toESM(require("path"), 1);
1581
2069
  import_node_fs5 = __toESM(require("fs"), 1);
2070
+ import_picocolors4 = __toESM(require("picocolors"), 1);
1582
2071
  }
1583
2072
  });
1584
2073
 
@@ -1688,397 +2177,2470 @@ var init_resolve = __esm({
1688
2177
  }
1689
2178
  });
1690
2179
 
1691
- // src/plugins/tailwind.ts
1692
- function hasTailwindDirectives(css) {
1693
- const withoutBlockComments = css.replace(/\/\*[\s\S]*?\*\//g, "");
1694
- const withoutLineComments = withoutBlockComments.replace(/\/\/.*$/gm, "");
1695
- return TAILWIND_DIRECTIVE_RE.test(withoutLineComments);
1696
- }
1697
- async function loadTailwind(projectRoot) {
1698
- if (cached && cachedRoot === projectRoot) return cached;
1699
- const req = (0, import_node_module3.createRequire)(import_node_path7.default.join(projectRoot, "package.json"));
1700
- let nodePath;
1701
- let oxidePath;
1702
- try {
1703
- nodePath = req.resolve("@tailwindcss/node");
1704
- oxidePath = req.resolve("@tailwindcss/oxide");
1705
- } catch {
1706
- throw new Error(
1707
- "[nasti] CSS contains Tailwind v4 directives but `@tailwindcss/node` and/or `@tailwindcss/oxide` are not installed in this project. Install them with: npm i -D tailwindcss @tailwindcss/node @tailwindcss/oxide"
1708
- );
1709
- }
1710
- const node = await import((0, import_node_url3.pathToFileURL)(nodePath).href);
1711
- const oxide = await import((0, import_node_url3.pathToFileURL)(oxidePath).href);
1712
- cached = { node, oxide };
1713
- cachedRoot = projectRoot;
1714
- return cached;
1715
- }
1716
- async function compileTailwind(css, fromFile, projectRoot) {
1717
- const { node, oxide } = await loadTailwind(projectRoot);
1718
- const dependencies = [];
1719
- const compiler2 = await node.compile(css, {
1720
- base: import_node_path7.default.dirname(fromFile),
1721
- from: fromFile,
1722
- onDependency: (p) => dependencies.push(p)
1723
- });
1724
- const scanner = new oxide.Scanner({ sources: compiler2.sources });
1725
- const candidates = scanner.scan();
1726
- return {
1727
- css: compiler2.build(candidates),
1728
- dependencies: [...dependencies, ...scanner.files]
1729
- };
1730
- }
1731
- var import_node_path7, import_node_module3, import_node_url3, TAILWIND_DIRECTIVE_RE, cached, cachedRoot;
1732
- var init_tailwind = __esm({
1733
- "src/plugins/tailwind.ts"() {
1734
- "use strict";
1735
- import_node_path7 = __toESM(require("path"), 1);
1736
- import_node_module3 = require("module");
1737
- import_node_url3 = require("url");
1738
- TAILWIND_DIRECTIVE_RE = /@(?:import\s+["']tailwindcss(?:\b|\/)|tailwind\b|theme\b|apply\b|plugin\b|source\b|utility\b|variant\b|custom-variant\b|reference\b)/;
1739
- cached = null;
1740
- cachedRoot = null;
2180
+ // require("../lightningcss.*.node") in node_modules/lightningcss/node/index.js
2181
+ var globRequire_lightningcss_node;
2182
+ var init_ = __esm({
2183
+ 'require("../lightningcss.*.node") in node_modules/lightningcss/node/index.js'() {
2184
+ globRequire_lightningcss_node = __glob({});
1741
2185
  }
1742
2186
  });
1743
2187
 
1744
- // src/plugins/css.ts
1745
- function cssPlugin(config) {
1746
- return {
1747
- name: "nasti:css",
1748
- resolveId(source) {
1749
- if (source.endsWith(".css")) return null;
1750
- return null;
1751
- },
1752
- async transform(code, id) {
1753
- if (!id.endsWith(".css")) return null;
1754
- let cssSource = code;
1755
- if (hasTailwindDirectives(code)) {
1756
- const compiled = await compileTailwind(code, id, config.root);
1757
- cssSource = compiled.css;
2188
+ // node_modules/detect-libc/lib/process.js
2189
+ var require_process = __commonJS({
2190
+ "node_modules/detect-libc/lib/process.js"(exports2, module2) {
2191
+ "use strict";
2192
+ var isLinux = () => process.platform === "linux";
2193
+ var report = null;
2194
+ var getReport = () => {
2195
+ if (!report) {
2196
+ if (isLinux() && process.report) {
2197
+ const orig = process.report.excludeNetwork;
2198
+ process.report.excludeNetwork = true;
2199
+ report = process.report.getReport();
2200
+ process.report.excludeNetwork = orig;
2201
+ } else {
2202
+ report = {};
2203
+ }
1758
2204
  }
1759
- const rewritten = rewriteCssUrls(cssSource, id, config.root);
1760
- const escaped = JSON.stringify(rewritten);
1761
- if (config.command === "serve") {
1762
- return {
1763
- code: `
1764
- const css = ${escaped};
1765
- const __nasti_css_id__ = ${JSON.stringify(id)};
1766
- const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
1767
- if (__nasti_existing__) __nasti_existing__.remove();
1768
- const style = document.createElement('style');
1769
- style.setAttribute('data-nasti-css', __nasti_css_id__);
1770
- style.textContent = css;
1771
- document.head.appendChild(style);
2205
+ return report;
2206
+ };
2207
+ module2.exports = { isLinux, getReport };
2208
+ }
2209
+ });
1772
2210
 
1773
- // HMR
1774
- if (import.meta.hot) {
1775
- import.meta.hot.accept();
1776
- import.meta.hot.prune(() => {
1777
- style.remove();
1778
- });
1779
- }
2211
+ // node_modules/detect-libc/lib/filesystem.js
2212
+ var require_filesystem = __commonJS({
2213
+ "node_modules/detect-libc/lib/filesystem.js"(exports2, module2) {
2214
+ "use strict";
2215
+ var fs12 = require("fs");
2216
+ var LDD_PATH = "/usr/bin/ldd";
2217
+ var SELF_PATH = "/proc/self/exe";
2218
+ var MAX_LENGTH = 2048;
2219
+ var readFileSync = (path17) => {
2220
+ const fd = fs12.openSync(path17, "r");
2221
+ const buffer = Buffer.alloc(MAX_LENGTH);
2222
+ const bytesRead = fs12.readSync(fd, buffer, 0, MAX_LENGTH, 0);
2223
+ fs12.close(fd, () => {
2224
+ });
2225
+ return buffer.subarray(0, bytesRead);
2226
+ };
2227
+ var readFile = (path17) => new Promise((resolve, reject) => {
2228
+ fs12.open(path17, "r", (err, fd) => {
2229
+ if (err) {
2230
+ reject(err);
2231
+ } else {
2232
+ const buffer = Buffer.alloc(MAX_LENGTH);
2233
+ fs12.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
2234
+ resolve(buffer.subarray(0, bytesRead));
2235
+ fs12.close(fd, () => {
2236
+ });
2237
+ });
2238
+ }
2239
+ });
2240
+ });
2241
+ module2.exports = {
2242
+ LDD_PATH,
2243
+ SELF_PATH,
2244
+ readFileSync,
2245
+ readFile
2246
+ };
2247
+ }
2248
+ });
1780
2249
 
1781
- export default css;
1782
- `
1783
- };
2250
+ // node_modules/detect-libc/lib/elf.js
2251
+ var require_elf = __commonJS({
2252
+ "node_modules/detect-libc/lib/elf.js"(exports2, module2) {
2253
+ "use strict";
2254
+ var interpreterPath = (elf) => {
2255
+ if (elf.length < 64) {
2256
+ return null;
1784
2257
  }
1785
- const cssConfig = config.build.css || {};
1786
- const nonce = cssConfig.nonce;
1787
- const emitCssFile = cssConfig.emitCssFile;
1788
- if (emitCssFile) {
1789
- const fileName = `assets/${import_node_path8.default.basename(id, ".css")}.css`;
1790
- this.emitFile({
1791
- type: "asset",
1792
- fileName,
1793
- source: rewritten
1794
- });
1795
- return {
1796
- code: `
1797
- const link = document.createElement('link');
1798
- link.rel = 'stylesheet';
1799
- link.href = ${JSON.stringify("/" + fileName)};
1800
- document.head.appendChild(link);
1801
-
1802
- export default ${escaped};
1803
- `,
1804
- moduleType: "js"
1805
- };
2258
+ if (elf.readUInt32BE(0) !== 2135247942) {
2259
+ return null;
1806
2260
  }
1807
- const nonceAttr = nonce ? `style.setAttribute('nonce', ${JSON.stringify(nonce)});` : "";
1808
- return {
1809
- code: `
1810
- const css = ${escaped};
1811
- const style = document.createElement('style');
1812
- style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
1813
- ${nonceAttr}
1814
- style.textContent = css;
1815
- document.head.appendChild(style);
2261
+ if (elf.readUInt8(4) !== 2) {
2262
+ return null;
2263
+ }
2264
+ if (elf.readUInt8(5) !== 1) {
2265
+ return null;
2266
+ }
2267
+ const offset = elf.readUInt32LE(32);
2268
+ const size = elf.readUInt16LE(54);
2269
+ const count = elf.readUInt16LE(56);
2270
+ for (let i = 0; i < count; i++) {
2271
+ const headerOffset = offset + i * size;
2272
+ const type = elf.readUInt32LE(headerOffset);
2273
+ if (type === 3) {
2274
+ const fileOffset = elf.readUInt32LE(headerOffset + 8);
2275
+ const fileSize = elf.readUInt32LE(headerOffset + 32);
2276
+ return elf.subarray(fileOffset, fileOffset + fileSize).toString().replace(/\0.*$/g, "");
2277
+ }
2278
+ }
2279
+ return null;
2280
+ };
2281
+ module2.exports = {
2282
+ interpreterPath
2283
+ };
2284
+ }
2285
+ });
1816
2286
 
1817
- export default css;
1818
- `,
1819
- moduleType: "js"
2287
+ // node_modules/detect-libc/lib/detect-libc.js
2288
+ var require_detect_libc = __commonJS({
2289
+ "node_modules/detect-libc/lib/detect-libc.js"(exports2, module2) {
2290
+ "use strict";
2291
+ var childProcess = require("child_process");
2292
+ var { isLinux, getReport } = require_process();
2293
+ var { LDD_PATH, SELF_PATH, readFile, readFileSync } = require_filesystem();
2294
+ var { interpreterPath } = require_elf();
2295
+ var cachedFamilyInterpreter;
2296
+ var cachedFamilyFilesystem;
2297
+ var cachedVersionFilesystem;
2298
+ var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true";
2299
+ var commandOut = "";
2300
+ var safeCommand = () => {
2301
+ if (!commandOut) {
2302
+ return new Promise((resolve) => {
2303
+ childProcess.exec(command, (err, out) => {
2304
+ commandOut = err ? " " : out;
2305
+ resolve(commandOut);
2306
+ });
2307
+ });
2308
+ }
2309
+ return commandOut;
2310
+ };
2311
+ var safeCommandSync = () => {
2312
+ if (!commandOut) {
2313
+ try {
2314
+ commandOut = childProcess.execSync(command, { encoding: "utf8" });
2315
+ } catch (_err) {
2316
+ commandOut = " ";
2317
+ }
2318
+ }
2319
+ return commandOut;
2320
+ };
2321
+ var GLIBC = "glibc";
2322
+ var RE_GLIBC_VERSION = /LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i;
2323
+ var MUSL = "musl";
2324
+ var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-");
2325
+ var familyFromReport = () => {
2326
+ const report = getReport();
2327
+ if (report.header && report.header.glibcVersionRuntime) {
2328
+ return GLIBC;
2329
+ }
2330
+ if (Array.isArray(report.sharedObjects)) {
2331
+ if (report.sharedObjects.some(isFileMusl)) {
2332
+ return MUSL;
2333
+ }
2334
+ }
2335
+ return null;
2336
+ };
2337
+ var familyFromCommand = (out) => {
2338
+ const [getconf, ldd1] = out.split(/[\r\n]+/);
2339
+ if (getconf && getconf.includes(GLIBC)) {
2340
+ return GLIBC;
2341
+ }
2342
+ if (ldd1 && ldd1.includes(MUSL)) {
2343
+ return MUSL;
2344
+ }
2345
+ return null;
2346
+ };
2347
+ var familyFromInterpreterPath = (path17) => {
2348
+ if (path17) {
2349
+ if (path17.includes("/ld-musl-")) {
2350
+ return MUSL;
2351
+ } else if (path17.includes("/ld-linux-")) {
2352
+ return GLIBC;
2353
+ }
2354
+ }
2355
+ return null;
2356
+ };
2357
+ var getFamilyFromLddContent = (content) => {
2358
+ content = content.toString();
2359
+ if (content.includes("musl")) {
2360
+ return MUSL;
2361
+ }
2362
+ if (content.includes("GNU C Library")) {
2363
+ return GLIBC;
2364
+ }
2365
+ return null;
2366
+ };
2367
+ var familyFromFilesystem = async () => {
2368
+ if (cachedFamilyFilesystem !== void 0) {
2369
+ return cachedFamilyFilesystem;
2370
+ }
2371
+ cachedFamilyFilesystem = null;
2372
+ try {
2373
+ const lddContent = await readFile(LDD_PATH);
2374
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
2375
+ } catch (e) {
2376
+ }
2377
+ return cachedFamilyFilesystem;
2378
+ };
2379
+ var familyFromFilesystemSync = () => {
2380
+ if (cachedFamilyFilesystem !== void 0) {
2381
+ return cachedFamilyFilesystem;
2382
+ }
2383
+ cachedFamilyFilesystem = null;
2384
+ try {
2385
+ const lddContent = readFileSync(LDD_PATH);
2386
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
2387
+ } catch (e) {
2388
+ }
2389
+ return cachedFamilyFilesystem;
2390
+ };
2391
+ var familyFromInterpreter = async () => {
2392
+ if (cachedFamilyInterpreter !== void 0) {
2393
+ return cachedFamilyInterpreter;
2394
+ }
2395
+ cachedFamilyInterpreter = null;
2396
+ try {
2397
+ const selfContent = await readFile(SELF_PATH);
2398
+ const path17 = interpreterPath(selfContent);
2399
+ cachedFamilyInterpreter = familyFromInterpreterPath(path17);
2400
+ } catch (e) {
2401
+ }
2402
+ return cachedFamilyInterpreter;
2403
+ };
2404
+ var familyFromInterpreterSync = () => {
2405
+ if (cachedFamilyInterpreter !== void 0) {
2406
+ return cachedFamilyInterpreter;
2407
+ }
2408
+ cachedFamilyInterpreter = null;
2409
+ try {
2410
+ const selfContent = readFileSync(SELF_PATH);
2411
+ const path17 = interpreterPath(selfContent);
2412
+ cachedFamilyInterpreter = familyFromInterpreterPath(path17);
2413
+ } catch (e) {
2414
+ }
2415
+ return cachedFamilyInterpreter;
2416
+ };
2417
+ var family = async () => {
2418
+ let family2 = null;
2419
+ if (isLinux()) {
2420
+ family2 = await familyFromInterpreter();
2421
+ if (!family2) {
2422
+ family2 = await familyFromFilesystem();
2423
+ if (!family2) {
2424
+ family2 = familyFromReport();
2425
+ }
2426
+ if (!family2) {
2427
+ const out = await safeCommand();
2428
+ family2 = familyFromCommand(out);
2429
+ }
2430
+ }
2431
+ }
2432
+ return family2;
2433
+ };
2434
+ var familySync = () => {
2435
+ let family2 = null;
2436
+ if (isLinux()) {
2437
+ family2 = familyFromInterpreterSync();
2438
+ if (!family2) {
2439
+ family2 = familyFromFilesystemSync();
2440
+ if (!family2) {
2441
+ family2 = familyFromReport();
2442
+ }
2443
+ if (!family2) {
2444
+ const out = safeCommandSync();
2445
+ family2 = familyFromCommand(out);
2446
+ }
2447
+ }
2448
+ }
2449
+ return family2;
2450
+ };
2451
+ var isNonGlibcLinux = async () => isLinux() && await family() !== GLIBC;
2452
+ var isNonGlibcLinuxSync = () => isLinux() && familySync() !== GLIBC;
2453
+ var versionFromFilesystem = async () => {
2454
+ if (cachedVersionFilesystem !== void 0) {
2455
+ return cachedVersionFilesystem;
2456
+ }
2457
+ cachedVersionFilesystem = null;
2458
+ try {
2459
+ const lddContent = await readFile(LDD_PATH);
2460
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
2461
+ if (versionMatch) {
2462
+ cachedVersionFilesystem = versionMatch[1];
2463
+ }
2464
+ } catch (e) {
2465
+ }
2466
+ return cachedVersionFilesystem;
2467
+ };
2468
+ var versionFromFilesystemSync = () => {
2469
+ if (cachedVersionFilesystem !== void 0) {
2470
+ return cachedVersionFilesystem;
2471
+ }
2472
+ cachedVersionFilesystem = null;
2473
+ try {
2474
+ const lddContent = readFileSync(LDD_PATH);
2475
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
2476
+ if (versionMatch) {
2477
+ cachedVersionFilesystem = versionMatch[1];
2478
+ }
2479
+ } catch (e) {
2480
+ }
2481
+ return cachedVersionFilesystem;
2482
+ };
2483
+ var versionFromReport = () => {
2484
+ const report = getReport();
2485
+ if (report.header && report.header.glibcVersionRuntime) {
2486
+ return report.header.glibcVersionRuntime;
2487
+ }
2488
+ return null;
2489
+ };
2490
+ var versionSuffix = (s) => s.trim().split(/\s+/)[1];
2491
+ var versionFromCommand = (out) => {
2492
+ const [getconf, ldd1, ldd2] = out.split(/[\r\n]+/);
2493
+ if (getconf && getconf.includes(GLIBC)) {
2494
+ return versionSuffix(getconf);
2495
+ }
2496
+ if (ldd1 && ldd2 && ldd1.includes(MUSL)) {
2497
+ return versionSuffix(ldd2);
2498
+ }
2499
+ return null;
2500
+ };
2501
+ var version = async () => {
2502
+ let version2 = null;
2503
+ if (isLinux()) {
2504
+ version2 = await versionFromFilesystem();
2505
+ if (!version2) {
2506
+ version2 = versionFromReport();
2507
+ }
2508
+ if (!version2) {
2509
+ const out = await safeCommand();
2510
+ version2 = versionFromCommand(out);
2511
+ }
2512
+ }
2513
+ return version2;
2514
+ };
2515
+ var versionSync = () => {
2516
+ let version2 = null;
2517
+ if (isLinux()) {
2518
+ version2 = versionFromFilesystemSync();
2519
+ if (!version2) {
2520
+ version2 = versionFromReport();
2521
+ }
2522
+ if (!version2) {
2523
+ const out = safeCommandSync();
2524
+ version2 = versionFromCommand(out);
2525
+ }
2526
+ }
2527
+ return version2;
2528
+ };
2529
+ module2.exports = {
2530
+ GLIBC,
2531
+ MUSL,
2532
+ family,
2533
+ familySync,
2534
+ isNonGlibcLinux,
2535
+ isNonGlibcLinuxSync,
2536
+ version,
2537
+ versionSync
2538
+ };
2539
+ }
2540
+ });
2541
+
2542
+ // node_modules/lightningcss/node/browserslistToTargets.js
2543
+ var require_browserslistToTargets = __commonJS({
2544
+ "node_modules/lightningcss/node/browserslistToTargets.js"(exports2, module2) {
2545
+ "use strict";
2546
+ var BROWSER_MAPPING = {
2547
+ and_chr: "chrome",
2548
+ and_ff: "firefox",
2549
+ ie_mob: "ie",
2550
+ op_mob: "opera",
2551
+ and_qq: null,
2552
+ and_uc: null,
2553
+ baidu: null,
2554
+ bb: null,
2555
+ kaios: null,
2556
+ op_mini: null
2557
+ };
2558
+ function browserslistToTargets2(browserslist) {
2559
+ let targets = {};
2560
+ for (let browser of browserslist) {
2561
+ let [name, v] = browser.split(" ");
2562
+ if (BROWSER_MAPPING[name] === null) {
2563
+ continue;
2564
+ }
2565
+ let version = parseVersion(v);
2566
+ if (version == null) {
2567
+ continue;
2568
+ }
2569
+ if (targets[name] == null || version < targets[name]) {
2570
+ targets[name] = version;
2571
+ }
2572
+ }
2573
+ return targets;
2574
+ }
2575
+ function parseVersion(version) {
2576
+ let [major, minor = 0, patch = 0] = version.split("-")[0].split(".").map((v) => parseInt(v, 10));
2577
+ if (isNaN(major) || isNaN(minor) || isNaN(patch)) {
2578
+ return null;
2579
+ }
2580
+ return major << 16 | minor << 8 | patch;
2581
+ }
2582
+ module2.exports = browserslistToTargets2;
2583
+ }
2584
+ });
2585
+
2586
+ // node_modules/lightningcss/node/composeVisitors.js
2587
+ var require_composeVisitors = __commonJS({
2588
+ "node_modules/lightningcss/node/composeVisitors.js"(exports2, module2) {
2589
+ "use strict";
2590
+ function composeVisitors2(visitors) {
2591
+ if (visitors.length === 1) {
2592
+ return visitors[0];
2593
+ }
2594
+ if (visitors.some((v) => typeof v === "function")) {
2595
+ return (opts) => {
2596
+ let v = visitors.map((v2) => typeof v2 === "function" ? v2(opts) : v2);
2597
+ return composeVisitors2(v);
2598
+ };
2599
+ }
2600
+ let res = {};
2601
+ composeSimpleVisitors(res, visitors, "StyleSheet");
2602
+ composeSimpleVisitors(res, visitors, "StyleSheetExit");
2603
+ composeObjectVisitors(res, visitors, "Rule", ruleVisitor, wrapCustomAndUnknownAtRule);
2604
+ composeObjectVisitors(res, visitors, "RuleExit", ruleVisitor, wrapCustomAndUnknownAtRule);
2605
+ composeObjectVisitors(res, visitors, "Declaration", declarationVisitor, wrapCustomProperty);
2606
+ composeObjectVisitors(res, visitors, "DeclarationExit", declarationVisitor, wrapCustomProperty);
2607
+ composeSimpleVisitors(res, visitors, "Url");
2608
+ composeSimpleVisitors(res, visitors, "Color");
2609
+ composeSimpleVisitors(res, visitors, "Image");
2610
+ composeSimpleVisitors(res, visitors, "ImageExit");
2611
+ composeSimpleVisitors(res, visitors, "Length");
2612
+ composeSimpleVisitors(res, visitors, "Angle");
2613
+ composeSimpleVisitors(res, visitors, "Ratio");
2614
+ composeSimpleVisitors(res, visitors, "Resolution");
2615
+ composeSimpleVisitors(res, visitors, "Time");
2616
+ composeSimpleVisitors(res, visitors, "CustomIdent");
2617
+ composeSimpleVisitors(res, visitors, "DashedIdent");
2618
+ composeArrayFunctions(res, visitors, "MediaQuery");
2619
+ composeArrayFunctions(res, visitors, "MediaQueryExit");
2620
+ composeSimpleVisitors(res, visitors, "SupportsCondition");
2621
+ composeSimpleVisitors(res, visitors, "SupportsConditionExit");
2622
+ composeArrayFunctions(res, visitors, "Selector");
2623
+ composeTokenVisitors(res, visitors, "Token", "token", false);
2624
+ composeTokenVisitors(res, visitors, "Function", "function", false);
2625
+ composeTokenVisitors(res, visitors, "FunctionExit", "function", true);
2626
+ composeTokenVisitors(res, visitors, "Variable", "var", false);
2627
+ composeTokenVisitors(res, visitors, "VariableExit", "var", true);
2628
+ composeTokenVisitors(res, visitors, "EnvironmentVariable", "env", false);
2629
+ composeTokenVisitors(res, visitors, "EnvironmentVariableExit", "env", true);
2630
+ return res;
2631
+ }
2632
+ module2.exports = composeVisitors2;
2633
+ function wrapCustomAndUnknownAtRule(k, f) {
2634
+ if (k === "unknown") {
2635
+ return ((value) => f({ type: "unknown", value }));
2636
+ }
2637
+ if (k === "custom") {
2638
+ return ((value) => f({ type: "custom", value }));
2639
+ }
2640
+ return f;
2641
+ }
2642
+ function wrapCustomProperty(k, f) {
2643
+ return k === "custom" ? ((value) => f({ property: "custom", value })) : f;
2644
+ }
2645
+ function ruleVisitor(f, item) {
2646
+ if (typeof f === "object") {
2647
+ if (item.type === "unknown") {
2648
+ let v = f.unknown;
2649
+ if (typeof v === "object") {
2650
+ v = v[item.value.name];
2651
+ }
2652
+ return v?.(item.value);
2653
+ }
2654
+ if (item.type === "custom") {
2655
+ let v = f.custom;
2656
+ if (typeof v === "object") {
2657
+ v = v[item.value.name];
2658
+ }
2659
+ return v?.(item.value);
2660
+ }
2661
+ return f[item.type]?.(item);
2662
+ }
2663
+ return f?.(item);
2664
+ }
2665
+ function declarationVisitor(f, item) {
2666
+ if (typeof f === "object") {
2667
+ let name = item.property;
2668
+ if (item.property === "unparsed") {
2669
+ name = item.value.propertyId.property;
2670
+ } else if (item.property === "custom") {
2671
+ let v = f.custom;
2672
+ if (typeof v === "object") {
2673
+ v = v[item.value.name];
2674
+ }
2675
+ return v?.(item.value);
2676
+ }
2677
+ return f[name]?.(item);
2678
+ }
2679
+ return f?.(item);
2680
+ }
2681
+ function extractObjectsOrFunctions(visitors, key) {
2682
+ let values = [];
2683
+ let hasFunction = false;
2684
+ let allKeys = /* @__PURE__ */ new Set();
2685
+ for (let visitor of visitors) {
2686
+ let v = visitor[key];
2687
+ if (v) {
2688
+ if (typeof v === "function") {
2689
+ hasFunction = true;
2690
+ } else {
2691
+ for (let key2 in v) {
2692
+ allKeys.add(key2);
2693
+ }
2694
+ }
2695
+ values.push(v);
2696
+ }
2697
+ }
2698
+ return [values, hasFunction, allKeys];
2699
+ }
2700
+ function composeObjectVisitors(res, visitors, key, apply, wrapKey) {
2701
+ let [values, hasFunction, allKeys] = extractObjectsOrFunctions(visitors, key);
2702
+ if (values.length === 0) {
2703
+ return;
2704
+ }
2705
+ if (values.length === 1) {
2706
+ res[key] = values[0];
2707
+ return;
2708
+ }
2709
+ let f = createArrayVisitor(visitors, (visitor, item) => apply(visitor[key], item));
2710
+ if (hasFunction) {
2711
+ res[key] = f;
2712
+ } else {
2713
+ let v = {};
2714
+ for (let k of allKeys) {
2715
+ v[k] = wrapKey(k, f);
2716
+ }
2717
+ res[key] = v;
2718
+ }
2719
+ }
2720
+ function composeTokenVisitors(res, visitors, key, type, isExit) {
2721
+ let [values, hasFunction, allKeys] = extractObjectsOrFunctions(visitors, key);
2722
+ if (values.length === 0) {
2723
+ return;
2724
+ }
2725
+ if (values.length === 1) {
2726
+ res[key] = values[0];
2727
+ return;
2728
+ }
2729
+ let f = createTokenVisitor(visitors, type, isExit);
2730
+ if (hasFunction) {
2731
+ res[key] = f;
2732
+ } else {
2733
+ let v = {};
2734
+ for (let key2 of allKeys) {
2735
+ v[key2] = f;
2736
+ }
2737
+ res[key] = v;
2738
+ }
2739
+ }
2740
+ function createTokenVisitor(visitors, type, isExit) {
2741
+ let v = createArrayVisitor(visitors, (visitor, item) => {
2742
+ let f;
2743
+ switch (item.type) {
2744
+ case "token":
2745
+ f = visitor.Token;
2746
+ if (typeof f === "object") {
2747
+ f = f[item.value.type];
2748
+ }
2749
+ break;
2750
+ case "function":
2751
+ f = isExit ? visitor.FunctionExit : visitor.Function;
2752
+ if (typeof f === "object") {
2753
+ f = f[item.value.name];
2754
+ }
2755
+ break;
2756
+ case "var":
2757
+ f = isExit ? visitor.VariableExit : visitor.Variable;
2758
+ break;
2759
+ case "env":
2760
+ f = isExit ? visitor.EnvironmentVariableExit : visitor.EnvironmentVariable;
2761
+ if (typeof f === "object") {
2762
+ let name;
2763
+ switch (item.value.name.type) {
2764
+ case "ua":
2765
+ case "unknown":
2766
+ name = item.value.name.value;
2767
+ break;
2768
+ case "custom":
2769
+ name = item.value.name.ident;
2770
+ break;
2771
+ }
2772
+ f = f[name];
2773
+ }
2774
+ break;
2775
+ case "color":
2776
+ f = visitor.Color;
2777
+ break;
2778
+ case "url":
2779
+ f = visitor.Url;
2780
+ break;
2781
+ case "length":
2782
+ f = visitor.Length;
2783
+ break;
2784
+ case "angle":
2785
+ f = visitor.Angle;
2786
+ break;
2787
+ case "time":
2788
+ f = visitor.Time;
2789
+ break;
2790
+ case "resolution":
2791
+ f = visitor.Resolution;
2792
+ break;
2793
+ case "dashed-ident":
2794
+ f = visitor.DashedIdent;
2795
+ break;
2796
+ }
2797
+ if (!f) {
2798
+ return;
2799
+ }
2800
+ let res = f(item.value);
2801
+ switch (item.type) {
2802
+ case "color":
2803
+ case "url":
2804
+ case "length":
2805
+ case "angle":
2806
+ case "time":
2807
+ case "resolution":
2808
+ case "dashed-ident":
2809
+ if (Array.isArray(res)) {
2810
+ res = res.map((value) => ({ type: item.type, value }));
2811
+ } else if (res) {
2812
+ res = { type: item.type, value: res };
2813
+ }
2814
+ break;
2815
+ }
2816
+ return res;
2817
+ });
2818
+ return (value) => v({ type, value });
2819
+ }
2820
+ function extractFunctions(visitors, key) {
2821
+ let functions = [];
2822
+ for (let visitor of visitors) {
2823
+ let f = visitor[key];
2824
+ if (f) {
2825
+ functions.push(f);
2826
+ }
2827
+ }
2828
+ return functions;
2829
+ }
2830
+ function composeSimpleVisitors(res, visitors, key) {
2831
+ let functions = extractFunctions(visitors, key);
2832
+ if (functions.length === 0) {
2833
+ return;
2834
+ }
2835
+ if (functions.length === 1) {
2836
+ res[key] = functions[0];
2837
+ return;
2838
+ }
2839
+ res[key] = (arg) => {
2840
+ let mutated = false;
2841
+ for (let f of functions) {
2842
+ let res2 = f(arg);
2843
+ if (res2) {
2844
+ arg = res2;
2845
+ mutated = true;
2846
+ }
2847
+ }
2848
+ return mutated ? arg : void 0;
2849
+ };
2850
+ }
2851
+ function composeArrayFunctions(res, visitors, key) {
2852
+ let functions = extractFunctions(visitors, key);
2853
+ if (functions.length === 0) {
2854
+ return;
2855
+ }
2856
+ if (functions.length === 1) {
2857
+ res[key] = functions[0];
2858
+ return;
2859
+ }
2860
+ res[key] = createArrayVisitor(functions, (f, item) => f(item));
2861
+ }
2862
+ function createArrayVisitor(visitors, apply) {
2863
+ let seen = new Bitset(visitors.length);
2864
+ return (arg) => {
2865
+ let arr = [arg];
2866
+ let mutated = false;
2867
+ seen.clear();
2868
+ for (let i = 0; i < arr.length; i++) {
2869
+ for (let v = 0; v < visitors.length && i < arr.length; ) {
2870
+ if (seen.get(v)) {
2871
+ v++;
2872
+ continue;
2873
+ }
2874
+ let item = arr[i];
2875
+ let visitor = visitors[v];
2876
+ let res = apply(visitor, item);
2877
+ if (Array.isArray(res)) {
2878
+ if (res.length === 0) {
2879
+ arr.splice(i, 1);
2880
+ } else if (res.length === 1) {
2881
+ arr[i] = res[0];
2882
+ } else {
2883
+ arr.splice(i, 1, ...res);
2884
+ }
2885
+ mutated = true;
2886
+ seen.set(v);
2887
+ v = 0;
2888
+ } else if (res) {
2889
+ arr[i] = res;
2890
+ mutated = true;
2891
+ seen.set(v);
2892
+ v = 0;
2893
+ } else {
2894
+ v++;
2895
+ }
2896
+ }
2897
+ }
2898
+ if (!mutated) {
2899
+ return;
2900
+ }
2901
+ return arr.length === 1 ? arr[0] : arr;
2902
+ };
2903
+ }
2904
+ var Bitset = class {
2905
+ constructor(maxBits = 32) {
2906
+ this.bits = 0;
2907
+ this.more = maxBits > 32 ? new Uint32Array(Math.ceil((maxBits - 32) / 32)) : null;
2908
+ }
2909
+ /** @param {number} bit */
2910
+ get(bit) {
2911
+ if (bit >= 32 && this.more) {
2912
+ let i = Math.floor((bit - 32) / 32);
2913
+ let b = bit % 32;
2914
+ return Boolean(this.more[i] & 1 << b);
2915
+ } else {
2916
+ return Boolean(this.bits & 1 << bit);
2917
+ }
2918
+ }
2919
+ /** @param {number} bit */
2920
+ set(bit) {
2921
+ if (bit >= 32 && this.more) {
2922
+ let i = Math.floor((bit - 32) / 32);
2923
+ let b = bit % 32;
2924
+ this.more[i] |= 1 << b;
2925
+ } else {
2926
+ this.bits |= 1 << bit;
2927
+ }
2928
+ }
2929
+ clear() {
2930
+ this.bits = 0;
2931
+ if (this.more) {
2932
+ this.more.fill(0);
2933
+ }
2934
+ }
2935
+ };
2936
+ }
2937
+ });
2938
+
2939
+ // node_modules/lightningcss/node/flags.js
2940
+ var require_flags = __commonJS({
2941
+ "node_modules/lightningcss/node/flags.js"(exports2) {
2942
+ "use strict";
2943
+ exports2.Features = {
2944
+ Nesting: 1,
2945
+ NotSelectorList: 2,
2946
+ DirSelector: 4,
2947
+ LangSelectorList: 8,
2948
+ IsSelector: 16,
2949
+ TextDecorationThicknessPercent: 32,
2950
+ MediaIntervalSyntax: 64,
2951
+ MediaRangeSyntax: 128,
2952
+ CustomMediaQueries: 256,
2953
+ ClampFunction: 512,
2954
+ ColorFunction: 1024,
2955
+ OklabColors: 2048,
2956
+ LabColors: 4096,
2957
+ P3Colors: 8192,
2958
+ HexAlphaColors: 16384,
2959
+ SpaceSeparatedColorNotation: 32768,
2960
+ FontFamilySystemUi: 65536,
2961
+ DoublePositionGradients: 131072,
2962
+ VendorPrefixes: 262144,
2963
+ LogicalProperties: 524288,
2964
+ LightDark: 1048576,
2965
+ Selectors: 31,
2966
+ MediaQueries: 448,
2967
+ Colors: 1113088
2968
+ };
2969
+ }
2970
+ });
2971
+
2972
+ // node_modules/lightningcss/node/index.js
2973
+ var require_node = __commonJS({
2974
+ "node_modules/lightningcss/node/index.js"(exports2, module2) {
2975
+ "use strict";
2976
+ init_();
2977
+ var parts = [process.platform, process.arch];
2978
+ if (process.platform === "linux") {
2979
+ const { MUSL, familySync } = require_detect_libc();
2980
+ const family = familySync();
2981
+ if (family === MUSL) {
2982
+ parts.push("musl");
2983
+ } else if (process.arch === "arm") {
2984
+ parts.push("gnueabihf");
2985
+ } else {
2986
+ parts.push("gnu");
2987
+ }
2988
+ } else if (process.platform === "win32") {
2989
+ parts.push("msvc");
2990
+ }
2991
+ var native;
2992
+ try {
2993
+ native = require(`lightningcss-${parts.join("-")}`);
2994
+ } catch (err) {
2995
+ native = globRequire_lightningcss_node(`../lightningcss.${parts.join("-")}.node`);
2996
+ }
2997
+ module2.exports.transform = wrap(native.transform);
2998
+ module2.exports.transformStyleAttribute = wrap(native.transformStyleAttribute);
2999
+ module2.exports.bundle = wrap(native.bundle);
3000
+ module2.exports.bundleAsync = wrap(native.bundleAsync);
3001
+ module2.exports.browserslistToTargets = require_browserslistToTargets();
3002
+ module2.exports.composeVisitors = require_composeVisitors();
3003
+ module2.exports.Features = require_flags().Features;
3004
+ function wrap(call) {
3005
+ return (options) => {
3006
+ if (typeof options.visitor === "function") {
3007
+ let deps = [];
3008
+ options.visitor = options.visitor({
3009
+ addDependency(dep) {
3010
+ deps.push(dep);
3011
+ }
3012
+ });
3013
+ let result = call(options);
3014
+ if (result instanceof Promise) {
3015
+ result = result.then((res) => {
3016
+ if (deps.length) {
3017
+ res.dependencies ??= [];
3018
+ res.dependencies.push(...deps);
3019
+ }
3020
+ return res;
3021
+ });
3022
+ } else if (deps.length) {
3023
+ result.dependencies ??= [];
3024
+ result.dependencies.push(...deps);
3025
+ }
3026
+ return result;
3027
+ } else {
3028
+ return call(options);
3029
+ }
1820
3030
  };
1821
3031
  }
1822
- };
3032
+ }
3033
+ });
3034
+
3035
+ // node_modules/lightningcss/node/index.mjs
3036
+ var node_exports = {};
3037
+ __export(node_exports, {
3038
+ Features: () => Features,
3039
+ browserslistToTargets: () => browserslistToTargets,
3040
+ bundle: () => bundle,
3041
+ bundleAsync: () => bundleAsync,
3042
+ composeVisitors: () => composeVisitors,
3043
+ transform: () => transform,
3044
+ transformStyleAttribute: () => transformStyleAttribute
3045
+ });
3046
+ var import_index, transform, transformStyleAttribute, bundle, bundleAsync, browserslistToTargets, composeVisitors, Features;
3047
+ var init_node = __esm({
3048
+ "node_modules/lightningcss/node/index.mjs"() {
3049
+ "use strict";
3050
+ import_index = __toESM(require_node(), 1);
3051
+ ({ transform, transformStyleAttribute, bundle, bundleAsync, browserslistToTargets, composeVisitors, Features } = import_index.default);
3052
+ }
3053
+ });
3054
+
3055
+ // src/core/css-engine.ts
3056
+ function createCssEngine() {
3057
+ return {
3058
+ styles: /* @__PURE__ */ new Map(),
3059
+ entryCss: /* @__PURE__ */ new Map(),
3060
+ allCss: [],
3061
+ pendingSingle: [],
3062
+ singleFileName: null
3063
+ };
3064
+ }
3065
+ function normalizeCssModuleId(id) {
3066
+ return id.startsWith("\0") ? id.slice(1) : id;
3067
+ }
3068
+ async function minifyCss(css, config) {
3069
+ if (lightningCss === void 0) {
3070
+ try {
3071
+ lightningCss = await Promise.resolve().then(() => (init_node(), node_exports));
3072
+ } catch {
3073
+ lightningCss = null;
3074
+ debug2?.("lightningcss unavailable, falling back to regex minifier");
3075
+ }
3076
+ }
3077
+ if (lightningCss) {
3078
+ try {
3079
+ const result = lightningCss.transform({
3080
+ filename: "bundle.css",
3081
+ code: Buffer.from(css),
3082
+ minify: true,
3083
+ // 不展开 @import(Tailwind 已 flatten;裸 @import 保留原样交给浏览器)
3084
+ errorRecovery: true
3085
+ });
3086
+ for (const w of result.warnings ?? []) {
3087
+ config.logger.warnOnce(`[nasti:css] ${w.message}`);
3088
+ }
3089
+ return result.code.toString();
3090
+ } catch (err) {
3091
+ config.logger.warnOnce(
3092
+ `[nasti:css] Lightning CSS minify failed (${err.message}), emitting unminified CSS`
3093
+ );
3094
+ return css;
3095
+ }
3096
+ }
3097
+ return fallbackMinify(css);
3098
+ }
3099
+ function fallbackMinify(css) {
3100
+ return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s*([{}:;,])\s*/g, "$1").replace(/;}/g, "}").replace(/\s+/g, " ").trim();
3101
+ }
3102
+ var debug2, lightningCss;
3103
+ var init_css_engine = __esm({
3104
+ "src/core/css-engine.ts"() {
3105
+ "use strict";
3106
+ init_debug();
3107
+ debug2 = createDebugger("nasti:css");
3108
+ }
3109
+ });
3110
+
3111
+ // src/plugins/tailwind.ts
3112
+ function hasTailwindDirectives(css) {
3113
+ const withoutBlockComments = css.replace(/\/\*[\s\S]*?\*\//g, "");
3114
+ const withoutLineComments = withoutBlockComments.replace(/\/\/.*$/gm, "");
3115
+ return TAILWIND_DIRECTIVE_RE.test(withoutLineComments);
3116
+ }
3117
+ async function loadTailwind(projectRoot) {
3118
+ if (cached && cachedRoot === projectRoot) return cached;
3119
+ const req = (0, import_node_module3.createRequire)(import_node_path7.default.join(projectRoot, "package.json"));
3120
+ let nodePath;
3121
+ let oxidePath;
3122
+ try {
3123
+ nodePath = req.resolve("@tailwindcss/node");
3124
+ oxidePath = req.resolve("@tailwindcss/oxide");
3125
+ } catch {
3126
+ throw new Error(
3127
+ "[nasti] CSS contains Tailwind v4 directives but `@tailwindcss/node` and/or `@tailwindcss/oxide` are not installed in this project. Install them with: npm i -D tailwindcss @tailwindcss/node @tailwindcss/oxide"
3128
+ );
3129
+ }
3130
+ const node = await import((0, import_node_url3.pathToFileURL)(nodePath).href);
3131
+ const oxide = await import((0, import_node_url3.pathToFileURL)(oxidePath).href);
3132
+ cached = { node, oxide };
3133
+ cachedRoot = projectRoot;
3134
+ return cached;
3135
+ }
3136
+ async function compileTailwind(css, fromFile, projectRoot) {
3137
+ const { node, oxide } = await loadTailwind(projectRoot);
3138
+ const dependencies = [];
3139
+ const compiler2 = await node.compile(css, {
3140
+ base: import_node_path7.default.dirname(fromFile),
3141
+ from: fromFile,
3142
+ onDependency: (p) => dependencies.push(p)
3143
+ });
3144
+ const scanner = new oxide.Scanner({ sources: compiler2.sources });
3145
+ const candidates = scanner.scan();
3146
+ return {
3147
+ css: compiler2.build(candidates),
3148
+ dependencies: [...dependencies, ...scanner.files]
3149
+ };
3150
+ }
3151
+ var import_node_path7, import_node_module3, import_node_url3, TAILWIND_DIRECTIVE_RE, cached, cachedRoot;
3152
+ var init_tailwind = __esm({
3153
+ "src/plugins/tailwind.ts"() {
3154
+ "use strict";
3155
+ import_node_path7 = __toESM(require("path"), 1);
3156
+ import_node_module3 = require("module");
3157
+ import_node_url3 = require("url");
3158
+ TAILWIND_DIRECTIVE_RE = /@(?:import\s+["']tailwindcss(?:\b|\/)|tailwind\b|theme\b|apply\b|plugin\b|source\b|utility\b|variant\b|custom-variant\b|reference\b)/;
3159
+ cached = null;
3160
+ cachedRoot = null;
3161
+ }
3162
+ });
3163
+
3164
+ // src/plugins/css.ts
3165
+ function cssPlugin(config, engine, consumer = "client") {
3166
+ return {
3167
+ name: "nasti:css",
3168
+ resolveId(source) {
3169
+ if (source.endsWith(".css")) return null;
3170
+ return null;
3171
+ },
3172
+ async transform(code, id) {
3173
+ const [file, query = ""] = id.split("?", 2);
3174
+ const isCssRequest = file.endsWith(".css") || /\.css$/.test(id);
3175
+ if (!isCssRequest) return null;
3176
+ if (query === "raw" || query === "url") return null;
3177
+ let cssSource = code;
3178
+ if (hasTailwindDirectives(code)) {
3179
+ const compiled = await compileTailwind(code, id, config.root);
3180
+ cssSource = compiled.css;
3181
+ }
3182
+ const rewritten = rewriteCssUrls(cssSource, file, config.root);
3183
+ const escaped = JSON.stringify(rewritten);
3184
+ if (query === "inline") {
3185
+ return { code: `export default ${escaped};
3186
+ `, moduleType: "js" };
3187
+ }
3188
+ if (consumer === "server") {
3189
+ return { code: `export default ${escaped};
3190
+ `, moduleType: "js" };
3191
+ }
3192
+ if (config.command === "serve") {
3193
+ return {
3194
+ code: `
3195
+ const css = ${escaped};
3196
+ const __nasti_css_id__ = ${JSON.stringify(id)};
3197
+ const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
3198
+ if (__nasti_existing__) __nasti_existing__.remove();
3199
+ const style = document.createElement('style');
3200
+ style.setAttribute('data-nasti-css', __nasti_css_id__);
3201
+ style.textContent = css;
3202
+ document.head.appendChild(style);
3203
+
3204
+ // HMR\uFF08prune \u5728 bundled \u6A21\u5F0F\u7684 rolldown hot context \u4E0A\u4E0D\u5B58\u5728\uFF0C\u987B\u5B88\u536B\uFF09
3205
+ if (import.meta.hot) {
3206
+ import.meta.hot.accept();
3207
+ if (import.meta.hot.prune) {
3208
+ import.meta.hot.prune(() => {
3209
+ style.remove();
3210
+ });
3211
+ }
3212
+ }
3213
+
3214
+ export default css;
3215
+ `,
3216
+ // bundled dev(DevEngine)下该模块会进 Rolldown:不标 js 会按 .css
3217
+ // 扩展名走 CSS 管线触发 #4271 报错;unbundled 中间件忽略此字段
3218
+ moduleType: "js"
3219
+ };
3220
+ }
3221
+ if (engine) {
3222
+ engine.styles.set(normalizeCssModuleId(id), rewritten);
3223
+ return {
3224
+ code: `export default '';
3225
+ `,
3226
+ moduleType: "js",
3227
+ // 防止空 stub 被 tree-shake 出 chunk.moduleIds(css-post 靠它定位)
3228
+ moduleSideEffects: "no-treeshake"
3229
+ };
3230
+ }
3231
+ const cssConfig = config.build.css || {};
3232
+ const nonce = cssConfig.nonce;
3233
+ const nonceAttr = nonce ? `style.setAttribute('nonce', ${JSON.stringify(nonce)});` : "";
3234
+ return {
3235
+ code: `
3236
+ const css = ${escaped};
3237
+ const style = document.createElement('style');
3238
+ style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
3239
+ ${nonceAttr}
3240
+ style.textContent = css;
3241
+ document.head.appendChild(style);
3242
+
3243
+ export default css;
3244
+ `,
3245
+ moduleType: "js"
3246
+ };
3247
+ }
3248
+ };
3249
+ }
3250
+ function rewriteCssUrls(css, from, root) {
3251
+ return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
3252
+ if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
3253
+ return match;
3254
+ }
3255
+ const resolved = import_node_path8.default.resolve(import_node_path8.default.dirname(from), url);
3256
+ const relative = "/" + import_node_path8.default.relative(root, resolved).replace(/\\/g, "/");
3257
+ return `url(${relative})`;
3258
+ });
3259
+ }
3260
+ var import_node_path8;
3261
+ var init_css = __esm({
3262
+ "src/plugins/css.ts"() {
3263
+ "use strict";
3264
+ import_node_path8 = __toESM(require("path"), 1);
3265
+ init_css_engine();
3266
+ init_tailwind();
3267
+ }
3268
+ });
3269
+
3270
+ // src/plugins/css-post.ts
3271
+ function collectChunkCss(chunk, engine) {
3272
+ const ids = chunk.moduleIds ?? Object.keys(chunk.modules);
3273
+ let css = "";
3274
+ for (const id of ids) {
3275
+ const styles = engine.styles.get(normalizeCssModuleId(id));
3276
+ if (styles) css += styles + "\n";
3277
+ }
3278
+ return css;
3279
+ }
3280
+ function cssPostPlugin(config, engine) {
3281
+ return {
3282
+ name: "nasti:css-post",
3283
+ enforce: "post",
3284
+ async renderChunk(code, chunk) {
3285
+ const css = collectChunkCss(chunk, engine);
3286
+ if (!css) return null;
3287
+ if (!config.build.cssCodeSplit) {
3288
+ engine.pendingSingle.push(css);
3289
+ return null;
3290
+ }
3291
+ const finalCss = config.build.cssMinify ? await minifyCss(css, config) : css;
3292
+ const ref = this.emitFile({
3293
+ type: "asset",
3294
+ name: `${chunk.name}.css`,
3295
+ source: finalCss
3296
+ });
3297
+ const fileName = this.getFileName(ref);
3298
+ engine.allCss.push(fileName);
3299
+ if (chunk.isEntry) {
3300
+ const key = chunk.facadeModuleId ?? chunk.name;
3301
+ const existing = engine.entryCss.get(key) ?? [];
3302
+ existing.push(fileName);
3303
+ engine.entryCss.set(key, existing);
3304
+ return null;
3305
+ }
3306
+ const href = JSON.stringify(config.base + fileName);
3307
+ const snippet = `
3308
+ ;(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){}})();`;
3309
+ return { code: code + snippet, map: null };
3310
+ },
3311
+ augmentChunkHash(chunk) {
3312
+ const css = collectChunkCss(chunk, engine);
3313
+ return css || void 0;
3314
+ },
3315
+ async generateBundle() {
3316
+ if (config.build.cssCodeSplit || engine.pendingSingle.length === 0) return;
3317
+ const merged = engine.pendingSingle.join("\n");
3318
+ const finalCss = config.build.cssMinify ? await minifyCss(merged, config) : merged;
3319
+ const ref = this.emitFile({ type: "asset", name: "style.css", source: finalCss });
3320
+ const fileName = this.getFileName(ref);
3321
+ engine.singleFileName = fileName;
3322
+ engine.allCss.push(fileName);
3323
+ }
3324
+ };
3325
+ }
3326
+ var init_css_post = __esm({
3327
+ "src/plugins/css-post.ts"() {
3328
+ "use strict";
3329
+ init_css_engine();
3330
+ }
3331
+ });
3332
+
3333
+ // src/plugins/assets.ts
3334
+ function assetsPlugin(config) {
3335
+ return {
3336
+ name: "nasti:assets",
3337
+ resolveId(source) {
3338
+ if (source.endsWith("?url") || source.endsWith("?raw")) {
3339
+ return source;
3340
+ }
3341
+ return null;
3342
+ },
3343
+ load(id) {
3344
+ const ext = import_node_path9.default.extname(id.replace(/\?.*$/, ""));
3345
+ if (id.endsWith("?raw")) {
3346
+ const file = id.slice(0, -4);
3347
+ if (import_node_fs7.default.existsSync(file)) {
3348
+ const content = import_node_fs7.default.readFileSync(file, "utf-8");
3349
+ return `export default ${JSON.stringify(content)}`;
3350
+ }
3351
+ }
3352
+ if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
3353
+ const file = id.replace(/\?.*$/, "");
3354
+ if (!import_node_fs7.default.existsSync(file)) return null;
3355
+ if (config.command === "serve") {
3356
+ const url = "/" + import_node_path9.default.relative(config.root, file);
3357
+ return `export default ${JSON.stringify(url)}`;
3358
+ }
3359
+ const content = import_node_fs7.default.readFileSync(file);
3360
+ const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
3361
+ const basename = import_node_path9.default.basename(file, ext);
3362
+ const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
3363
+ return `export default ${JSON.stringify(config.base + hashedName)}`;
3364
+ }
3365
+ return null;
3366
+ }
3367
+ };
3368
+ }
3369
+ var import_node_path9, import_node_fs7, import_node_crypto, ASSET_EXTENSIONS;
3370
+ var init_assets = __esm({
3371
+ "src/plugins/assets.ts"() {
3372
+ "use strict";
3373
+ import_node_path9 = __toESM(require("path"), 1);
3374
+ import_node_fs7 = __toESM(require("fs"), 1);
3375
+ import_node_crypto = __toESM(require("crypto"), 1);
3376
+ ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
3377
+ ".png",
3378
+ ".jpg",
3379
+ ".jpeg",
3380
+ ".gif",
3381
+ ".svg",
3382
+ ".ico",
3383
+ ".webp",
3384
+ ".avif",
3385
+ ".mp4",
3386
+ ".webm",
3387
+ ".ogg",
3388
+ ".mp3",
3389
+ ".wav",
3390
+ ".flac",
3391
+ ".aac",
3392
+ ".woff",
3393
+ ".woff2",
3394
+ ".eot",
3395
+ ".ttf",
3396
+ ".otf",
3397
+ ".pdf",
3398
+ ".txt"
3399
+ ]);
3400
+ }
3401
+ });
3402
+
3403
+ // src/plugins/vue.ts
3404
+ async function loadVueCompiler() {
3405
+ if (compiler) return compiler;
3406
+ try {
3407
+ compiler = await import("@vue/compiler-sfc");
3408
+ return compiler;
3409
+ } catch {
3410
+ return null;
3411
+ }
3412
+ }
3413
+ function vuePlugin(config) {
3414
+ const isDev = config.command === "serve";
3415
+ const descriptorCache = /* @__PURE__ */ new Map();
3416
+ return {
3417
+ name: "nasti:vue",
3418
+ enforce: "pre",
3419
+ async resolveId(source) {
3420
+ if (VUE_QUERY_RE.test(source)) {
3421
+ return source;
3422
+ }
3423
+ return null;
3424
+ },
3425
+ // 虚拟子模块必须有 load 钩子:build 下 Rolldown 否则会按字面路径读盘,
3426
+ // 抛 UNLOADABLE_DEPENDENCY(1.x Vue 生产构建因此直接失败)。
3427
+ // style 子块在这里编译成 CSS 字符串,交给 css 插件统一处理
3428
+ // (dev = <style> 注入 + HMR;build = CssEngine 抽取成 hashed .css)。
3429
+ async load(id) {
3430
+ const match = id.match(/(.+\.vue)\?vue&type=style(?:&index=(\d+))?/);
3431
+ if (!match) return null;
3432
+ const sfc = await loadVueCompiler();
3433
+ if (!sfc) return null;
3434
+ const [, filePath, indexStr] = match;
3435
+ let descriptor = descriptorCache.get(filePath);
3436
+ if (!descriptor) {
3437
+ try {
3438
+ const fs12 = await import("fs");
3439
+ const source = fs12.readFileSync(filePath, "utf-8");
3440
+ const parsed = sfc.parse(source, { filename: filePath });
3441
+ if (parsed.errors.length) return null;
3442
+ descriptor = parsed.descriptor;
3443
+ descriptorCache.set(filePath, descriptor);
3444
+ } catch {
3445
+ return null;
3446
+ }
3447
+ }
3448
+ const index2 = parseInt(indexStr ?? "0", 10);
3449
+ const style = descriptor.styles[index2];
3450
+ if (!style) return null;
3451
+ const scopeId = hashId(filePath);
3452
+ const result = await sfc.compileStyleAsync({
3453
+ source: style.content,
3454
+ filename: filePath,
3455
+ id: `data-v-${scopeId}`,
3456
+ scoped: style.scoped ?? false,
3457
+ // <style lang="scss|less|stylus"> 需经对应预处理器(缺省 undefined = 纯 CSS)
3458
+ preprocessLang: style.lang
3459
+ });
3460
+ return result.code;
3461
+ },
3462
+ async transform(code, id) {
3463
+ if (!VUE_FILE_RE.test(id) && !VUE_QUERY_RE.test(id)) return null;
3464
+ const sfc = await loadVueCompiler();
3465
+ if (!sfc) {
3466
+ console.warn("[nasti:vue] @vue/compiler-sfc not found. Install it: npm install @vue/compiler-sfc");
3467
+ return null;
3468
+ }
3469
+ if (VUE_QUERY_RE.test(id)) {
3470
+ return null;
3471
+ }
3472
+ const { descriptor, errors } = sfc.parse(code, { filename: id });
3473
+ if (errors.length) {
3474
+ console.error(`[nasti:vue] Parse error in ${id}:`, errors[0].message);
3475
+ return null;
3476
+ }
3477
+ descriptorCache.set(id, descriptor);
3478
+ const scopeId = hashId(id);
3479
+ let scriptCode = "";
3480
+ if (descriptor.script || descriptor.scriptSetup) {
3481
+ const compiled = sfc.compileScript(descriptor, {
3482
+ id: scopeId,
3483
+ isProd: !isDev,
3484
+ inlineTemplate: true,
3485
+ // 让 compileScript 产出 `const __sfc__ = ...`(而非默认的 `export default {...}`)。
3486
+ // 否则下方追加的 `__sfc__.render` / `__sfc__.__scopeId` / HMR 记录会引用一个
3487
+ // 不存在的 `__sfc__`,并与 compileScript 自带的 `export default` 形成双重默认导出。
3488
+ genDefaultAs: "__sfc__"
3489
+ });
3490
+ scriptCode = compiled.content;
3491
+ }
3492
+ let templateCode = "";
3493
+ if (descriptor.template && !descriptor.scriptSetup) {
3494
+ const compiled = sfc.compileTemplate({
3495
+ source: descriptor.template.content,
3496
+ filename: id,
3497
+ id: scopeId,
3498
+ compilerOptions: { scopeId: `data-v-${scopeId}` }
3499
+ });
3500
+ templateCode = compiled.code;
3501
+ }
3502
+ let output = scriptCode || "const __sfc__ = {}";
3503
+ if (templateCode) {
3504
+ output += `
3505
+ ${templateCode}
3506
+ `;
3507
+ output += `
3508
+ __sfc__.render = render
3509
+ `;
3510
+ }
3511
+ if (descriptor.styles.length > 0) {
3512
+ for (let i = 0; i < descriptor.styles.length; i++) {
3513
+ output += `
3514
+ import "${id}?vue&type=style&index=${i}&lang.css"
3515
+ `;
3516
+ }
3517
+ }
3518
+ output += `
3519
+ __sfc__.__scopeId = "data-v-${scopeId}"
3520
+ `;
3521
+ if (isDev) {
3522
+ output += `
3523
+ __sfc__.__hmrId = ${JSON.stringify(scopeId)}
3524
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
3525
+ __VUE_HMR_RUNTIME__.createRecord(__sfc__.__hmrId, __sfc__)
3526
+ }
3527
+ if (import.meta.hot) {
3528
+ import.meta.hot.accept((mod) => {
3529
+ if (!mod) return
3530
+ const { default: updated } = mod
3531
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
3532
+ __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)
3533
+ }
3534
+ })
3535
+ }
3536
+ `;
3537
+ }
3538
+ output += `
3539
+ export default __sfc__
3540
+ `;
3541
+ const lang = descriptor.scriptSetup?.lang ?? descriptor.script?.lang;
3542
+ if (lang === "ts") {
3543
+ const transpiled = transformCode(`${id}.ts`, output, { sourcemap: false });
3544
+ return { code: transpiled.code };
3545
+ }
3546
+ return { code: output };
3547
+ },
3548
+ handleHotUpdate(ctx) {
3549
+ const { file, modules } = ctx;
3550
+ if (VUE_FILE_RE.test(file)) {
3551
+ for (const mod of modules) {
3552
+ mod.isSelfAccepting = true;
3553
+ }
3554
+ descriptorCache.delete(file);
3555
+ }
3556
+ return modules;
3557
+ }
3558
+ };
3559
+ }
3560
+ function hashId(filename) {
3561
+ return import_node_crypto2.default.createHash("sha256").update(filename).digest("hex").slice(0, 8);
3562
+ }
3563
+ var import_node_crypto2, VUE_FILE_RE, VUE_QUERY_RE, compiler;
3564
+ var init_vue = __esm({
3565
+ "src/plugins/vue.ts"() {
3566
+ "use strict";
3567
+ import_node_crypto2 = __toESM(require("crypto"), 1);
3568
+ init_transformer();
3569
+ VUE_FILE_RE = /\.vue$/;
3570
+ VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang[.=]\w+)?/;
3571
+ compiler = null;
3572
+ }
3573
+ });
3574
+
3575
+ // src/plugins/builtins.ts
3576
+ function resolvePluginList(config, userPlugins, opts = {}) {
3577
+ const isServe = config.command === "serve";
3578
+ return [
3579
+ // vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
3580
+ ...config.framework === "vue" ? [vuePlugin(config)] : [],
3581
+ resolvePlugin(config),
3582
+ cssPlugin(config, opts.cssEngine, opts.consumer),
3583
+ assetsPlugin(config),
3584
+ ...isServe ? [htmlPlugin(config)] : [],
3585
+ ...userPlugins,
3586
+ // cssPostPlugin 最后(enforce: 'post' 语义):renderChunk 聚合抽取
3587
+ ...!isServe && opts.cssEngine ? [cssPostPlugin(config, opts.cssEngine)] : []
3588
+ ];
3589
+ }
3590
+ var init_builtins = __esm({
3591
+ "src/plugins/builtins.ts"() {
3592
+ "use strict";
3593
+ init_resolve();
3594
+ init_css();
3595
+ init_css_post();
3596
+ init_assets();
3597
+ init_vue();
3598
+ init_html();
3599
+ }
3600
+ });
3601
+
3602
+ // src/server/runnable-environment.ts
3603
+ var runnable_environment_exports = {};
3604
+ __export(runnable_environment_exports, {
3605
+ NastiModuleRunner: () => NastiModuleRunner,
3606
+ createModuleRunner: () => createModuleRunner
3607
+ });
3608
+ function createModuleRunner(environment) {
3609
+ if (environment.consumer !== "server") {
3610
+ throw new Error(
3611
+ `[nasti] module runner requires a server-consumer environment (got "${environment.name}" / ${environment.consumer})`
3612
+ );
3613
+ }
3614
+ return new NastiModuleRunner(environment);
3615
+ }
3616
+ var import_node_path10, import_node_fs8, import_node_module4, import_node_url4, debug3, NODE_BUILTINS, NastiModuleRunner, AsyncFunction;
3617
+ var init_runnable_environment = __esm({
3618
+ "src/server/runnable-environment.ts"() {
3619
+ "use strict";
3620
+ import_node_path10 = __toESM(require("path"), 1);
3621
+ import_node_fs8 = __toESM(require("fs"), 1);
3622
+ import_node_module4 = require("module");
3623
+ import_node_url4 = require("url");
3624
+ init_transformer();
3625
+ init_env();
3626
+ init_debug();
3627
+ debug3 = createDebugger("nasti:ssr");
3628
+ NODE_BUILTINS = /* @__PURE__ */ new Set([...import_node_module4.builtinModules, ...import_node_module4.builtinModules.map((m) => `node:${m}`)]);
3629
+ NastiModuleRunner = class {
3630
+ environment;
3631
+ config;
3632
+ cache = /* @__PURE__ */ new Map();
3633
+ envDefine;
3634
+ require;
3635
+ constructor(environment) {
3636
+ this.environment = environment;
3637
+ this.config = environment.config;
3638
+ this.envDefine = buildEnvDefine(
3639
+ loadEnv(this.config.mode, this.config.root, this.config.envPrefix),
3640
+ this.config.mode,
3641
+ ssrDefineOverrides(environment.consumer)
3642
+ );
3643
+ this.require = (0, import_node_module4.createRequire)(import_node_path10.default.join(this.config.root, "package.json"));
3644
+ const handlers = {
3645
+ fetchModule: async (id, importer) => this.fetchModule(id, importer),
3646
+ getBuiltins: () => [/^node:/, ...import_node_module4.builtinModules]
3647
+ };
3648
+ environment.hot.setInvokeHandler?.(handlers);
3649
+ }
3650
+ /** 入口:加载并执行一个模块(url 为根相对或绝对路径) */
3651
+ async import(rawUrl) {
3652
+ const id = this.resolveToId(rawUrl);
3653
+ return this.instantiate(id);
3654
+ }
3655
+ /** 文件变更时按文件失效(含其所属的虚拟子模块) */
3656
+ invalidateFile(file) {
3657
+ for (const key of [...this.cache.keys()]) {
3658
+ if (key === file || key.startsWith(file + "?")) {
3659
+ this.cache.delete(key);
3660
+ }
3661
+ }
3662
+ }
3663
+ invalidateAll() {
3664
+ this.cache.clear();
3665
+ }
3666
+ resolveToId(rawUrl) {
3667
+ if (import_node_path10.default.isAbsolute(rawUrl) && import_node_fs8.default.existsSync(rawUrl.split("?")[0])) return rawUrl;
3668
+ const clean = rawUrl.replace(/^\//, "");
3669
+ return import_node_path10.default.resolve(this.config.root, clean);
3670
+ }
3671
+ /**
3672
+ * fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
3673
+ * resolve(插件 resolveId → 文件系统)→ load/读盘 → 插件 transform →
3674
+ * oxc(TS/JSX)→ moduleRunnerTransform。
3675
+ */
3676
+ async fetchModule(id, importer) {
3677
+ if (NODE_BUILTINS.has(id)) return { externalize: id };
3678
+ if (!id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0")) {
3679
+ return { externalize: id };
3680
+ }
3681
+ const container = this.environment.pluginContainer;
3682
+ let resolvedId = id;
3683
+ if (id.startsWith(".") && importer) {
3684
+ const resolved = await container.resolveId(id, importer);
3685
+ resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : import_node_path10.default.resolve(import_node_path10.default.dirname(importer.split("?")[0]), id);
3686
+ }
3687
+ resolvedId = this.completeExtension(resolvedId);
3688
+ const cleanId = resolvedId.split("?")[0];
3689
+ let code;
3690
+ const loaded = await container.load(resolvedId);
3691
+ if (loaded != null) {
3692
+ code = typeof loaded === "string" ? loaded : loaded.code;
3693
+ } else if (import_node_fs8.default.existsSync(cleanId)) {
3694
+ code = import_node_fs8.default.readFileSync(cleanId, "utf-8");
3695
+ } else {
3696
+ throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
3697
+ }
3698
+ const transformed = await container.transform(code, resolvedId);
3699
+ if (transformed != null) {
3700
+ code = typeof transformed === "string" ? transformed : transformed.code;
3701
+ }
3702
+ if (shouldTransform(cleanId)) {
3703
+ const result = transformCode(cleanId, code, {
3704
+ sourcemap: false,
3705
+ jsxRuntime: "automatic",
3706
+ jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
3707
+ });
3708
+ code = result.code;
3709
+ }
3710
+ code = replaceEnvInCode(code, this.envDefine);
3711
+ let moduleRunnerTransform;
3712
+ try {
3713
+ ;
3714
+ ({ moduleRunnerTransform } = await import("rolldown/experimental"));
3715
+ } catch (err) {
3716
+ throw new Error(
3717
+ `[nasti:ssr] rolldown/experimental moduleRunnerTransform unavailable (installed rolldown incompatible?): ${err.message}`
3718
+ );
3719
+ }
3720
+ const runnerResult = await moduleRunnerTransform(resolvedId, code);
3721
+ debug3?.(`fetchModule ${resolvedId} (${runnerResult.deps?.length ?? 0} deps)`);
3722
+ return { id: resolvedId, code: runnerResult.code };
3723
+ }
3724
+ completeExtension(id) {
3725
+ const clean = id.split("?")[0];
3726
+ const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
3727
+ if (import_node_fs8.default.existsSync(clean) && import_node_fs8.default.statSync(clean).isFile()) return id;
3728
+ const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
3729
+ if (jsMatch) {
3730
+ for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
3731
+ if (import_node_fs8.default.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
3732
+ }
3733
+ }
3734
+ for (const ext of this.config.resolve.extensions) {
3735
+ if (import_node_fs8.default.existsSync(clean + ext)) return clean + ext + query;
3736
+ }
3737
+ for (const ext of this.config.resolve.extensions) {
3738
+ const indexPath = import_node_path10.default.join(clean, `index${ext}`);
3739
+ if (import_node_fs8.default.existsSync(indexPath)) return indexPath;
3740
+ }
3741
+ return id;
3742
+ }
3743
+ async instantiate(id) {
3744
+ const cached2 = this.cache.get(id);
3745
+ if (cached2) return cached2.promise ?? Promise.resolve(cached2.exports);
3746
+ const entry = { exports: {}, promise: null };
3747
+ this.cache.set(id, entry);
3748
+ entry.promise = this.evaluate(id, entry).then(() => {
3749
+ entry.promise = null;
3750
+ return entry.exports;
3751
+ }).catch((err) => {
3752
+ this.cache.delete(id);
3753
+ throw err;
3754
+ });
3755
+ return entry.promise;
3756
+ }
3757
+ async evaluate(id, entry) {
3758
+ const fetched = await this.fetchModule(id);
3759
+ if ("externalize" in fetched) {
3760
+ const spec = fetched.externalize;
3761
+ const mod = await this.importExternal(spec);
3762
+ entry.exports = mod;
3763
+ return;
3764
+ }
3765
+ const ssrImport = async (dep) => {
3766
+ if (NODE_BUILTINS.has(dep) || !dep.startsWith(".") && !import_node_path10.default.isAbsolute(dep) && !dep.startsWith("\0")) {
3767
+ return this.importExternal(dep);
3768
+ }
3769
+ const depId = dep.startsWith(".") ? this.completeExtension(import_node_path10.default.resolve(import_node_path10.default.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
3770
+ return this.instantiate(depId);
3771
+ };
3772
+ const ssrExportAll = (sourceModule) => {
3773
+ for (const key of Object.keys(sourceModule)) {
3774
+ if (key !== "default" && !(key in entry.exports)) {
3775
+ Object.defineProperty(entry.exports, key, {
3776
+ enumerable: true,
3777
+ configurable: true,
3778
+ get: () => sourceModule[key]
3779
+ });
3780
+ }
3781
+ }
3782
+ };
3783
+ const importMeta = {
3784
+ url: (0, import_node_url4.pathToFileURL)(fetched.id.split("?")[0]).href,
3785
+ env: { SSR: true, MODE: this.config.mode, DEV: this.config.mode !== "production", PROD: this.config.mode === "production" },
3786
+ hot: void 0
3787
+ };
3788
+ const fn = new AsyncFunction(
3789
+ "__vite_ssr_exports__",
3790
+ "__vite_ssr_import__",
3791
+ "__vite_ssr_dynamic_import__",
3792
+ "__vite_ssr_exportAll__",
3793
+ "__vite_ssr_import_meta__",
3794
+ `"use strict";${fetched.code}
3795
+ //# sourceURL=${fetched.id}`
3796
+ );
3797
+ await fn(entry.exports, ssrImport, ssrImport, ssrExportAll, importMeta);
3798
+ }
3799
+ async importExternal(spec) {
3800
+ try {
3801
+ return await (spec.startsWith("node:") || !import_node_path10.default.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import((0, import_node_url4.pathToFileURL)(spec).href));
3802
+ } catch (err) {
3803
+ throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
3804
+ }
3805
+ }
3806
+ /** bare specifier → 项目 node_modules 的绝对 URL(避免相对 Nasti 自身解析) */
3807
+ resolveExternalSpecifier(spec) {
3808
+ if (spec.startsWith("node:")) return spec;
3809
+ if (NODE_BUILTINS.has(spec)) return `node:${spec}`;
3810
+ try {
3811
+ return (0, import_node_url4.pathToFileURL)(this.require.resolve(spec)).href;
3812
+ } catch {
3813
+ return spec;
3814
+ }
3815
+ }
3816
+ };
3817
+ AsyncFunction = Object.getPrototypeOf(async function() {
3818
+ }).constructor;
3819
+ }
3820
+ });
3821
+
3822
+ // src/build/reporter.ts
3823
+ async function tryNativeReporterPlugin(config, logger) {
3824
+ try {
3825
+ const { viteReporterPlugin } = await import("rolldown/experimental");
3826
+ if (typeof viteReporterPlugin !== "function") return null;
3827
+ return viteReporterPlugin({
3828
+ root: config.root,
3829
+ isTty: process.stdout.isTTY ?? false,
3830
+ isLib: false,
3831
+ assetsDir: config.build.assetsDir,
3832
+ chunkLimit: config.build.chunkSizeWarningLimit,
3833
+ // 大 chunk 警告由 JS 侧 warnLargeChunks() 经 logger.warn 输出,
3834
+ // 原生侧只产 info 级表格,避免警告被 logLevel 过滤吞掉
3835
+ warnLargeChunks: false,
3836
+ reportCompressedSize: config.build.reportCompressedSize,
3837
+ logInfo: (msg) => logger.info(msg)
3838
+ });
3839
+ } catch (err) {
3840
+ debug4?.(`native viteReporterPlugin unavailable, falling back to JS table: ${err}`);
3841
+ return null;
3842
+ }
3843
+ }
3844
+ function displaySize(bytes) {
3845
+ return `${numberFormatter.format(bytes / 1e3)} kB`;
3846
+ }
3847
+ function byteLength(content) {
3848
+ if (content == null) return 0;
3849
+ return typeof content === "string" ? Buffer.byteLength(content) : content.byteLength;
3850
+ }
3851
+ function reportBuildOutput(output, config, logger) {
3852
+ const entries = [];
3853
+ const compressed = config.build.reportCompressedSize;
3854
+ for (const file of output) {
3855
+ const content = file.type === "chunk" ? file.code : file.source;
3856
+ const size = byteLength(content);
3857
+ let gzip = null;
3858
+ if (compressed && content != null) {
3859
+ gzip = (0, import_node_zlib.gzipSync)(typeof content === "string" ? Buffer.from(content) : content).byteLength;
3860
+ }
3861
+ const ext = import_node_path11.default.extname(file.fileName);
3862
+ const group = file.type === "chunk" ? "js" : ext === ".css" ? "css" : "assets";
3863
+ entries.push({ name: file.fileName, size, gzip, group });
3864
+ }
3865
+ const groupOrder = { assets: 0, css: 1, js: 2 };
3866
+ entries.sort((a, b) => groupOrder[a.group] - groupOrder[b.group] || a.size - b.size);
3867
+ const outDirPrefix = `${config.build.outDir.replace(/\/$/, "")}/`;
3868
+ const maxNameLen = Math.max(...entries.map((e) => (outDirPrefix + e.name).length), 0);
3869
+ const maxSizeLen = Math.max(...entries.map((e) => displaySize(e.size).length), 0);
3870
+ const groupColor = { assets: import_picocolors5.default.green, css: import_picocolors5.default.magenta, js: import_picocolors5.default.cyan };
3871
+ for (const e of entries) {
3872
+ const color = groupColor[e.group];
3873
+ const namePart = import_picocolors5.default.dim(outDirPrefix) + color(e.name.padEnd(maxNameLen - outDirPrefix.length));
3874
+ const sizePart = import_picocolors5.default.dim(import_picocolors5.default.bold(displaySize(e.size).padStart(maxSizeLen)));
3875
+ const gzipPart = e.gzip != null ? import_picocolors5.default.dim(` \u2502 gzip: ${displaySize(e.gzip)}`) : "";
3876
+ logger.info(`${namePart} ${sizePart}${gzipPart}`);
3877
+ }
3878
+ }
3879
+ function warnLargeChunks(output, config, logger) {
3880
+ const limit = config.build.chunkSizeWarningLimit;
3881
+ const large = output.filter(
3882
+ (f) => f.type === "chunk" && byteLength(f.code) / 1e3 > limit
3883
+ );
3884
+ if (large.length === 0) return;
3885
+ logger.warn(
3886
+ import_picocolors5.default.yellow(
3887
+ `
3888
+ (!) Some chunks are larger than ${limit} kB after minification. Consider:
3889
+ - Using dynamic import() to code-split the application
3890
+ - Configuring build.rolldownOptions.output.advancedChunks to isolate large dependencies
3891
+ - Adjusting build.chunkSizeWarningLimit to silence this warning`
3892
+ )
3893
+ );
3894
+ }
3895
+ var import_node_path11, import_node_zlib, import_picocolors5, debug4, numberFormatter;
3896
+ var init_reporter = __esm({
3897
+ "src/build/reporter.ts"() {
3898
+ "use strict";
3899
+ import_node_path11 = __toESM(require("path"), 1);
3900
+ import_node_zlib = require("zlib");
3901
+ import_picocolors5 = __toESM(require("picocolors"), 1);
3902
+ init_debug();
3903
+ debug4 = createDebugger("nasti:reporter");
3904
+ numberFormatter = new Intl.NumberFormat("en", {
3905
+ maximumFractionDigits: 2,
3906
+ minimumFractionDigits: 2
3907
+ });
3908
+ }
3909
+ });
3910
+
3911
+ // src/build/index.ts
3912
+ var build_exports = {};
3913
+ __export(build_exports, {
3914
+ build: () => build,
3915
+ getRolldownOptions: () => getRolldownOptions,
3916
+ resolveClientEntries: () => resolveClientEntries,
3917
+ toRolldownPlugins: () => toRolldownPlugins
3918
+ });
3919
+ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
3920
+ const config = environment.config;
3921
+ const envOptions = environment.options;
3922
+ const isServer = environment.consumer === "server";
3923
+ const outDir = import_node_path12.default.resolve(config.root, envOptions.build.outDir);
3924
+ const assetsDir = envOptions.build.assetsDir;
3925
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = envOptions.build.rolldownOptions;
3926
+ const vueDefine = config.framework === "vue" ? {
3927
+ __VUE_OPTIONS_API__: "true",
3928
+ __VUE_PROD_DEVTOOLS__: "false",
3929
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false"
3930
+ } : {};
3931
+ const env = loadEnv(config.mode, config.root, config.envPrefix);
3932
+ const envDefine = buildEnvDefine(env, config.mode, ssrDefineOverrides(environment.consumer));
3933
+ const mergedDefine = { ...vueDefine, ...userTransform?.define ?? {}, ...envDefine };
3934
+ const inputOptions = {
3935
+ ...restInputOptions,
3936
+ input: entryPoints,
3937
+ transform: { ...userTransform, define: mergedDefine },
3938
+ plugins: rolldownPlugins,
3939
+ ...isServer ? {
3940
+ platform: restInputOptions.platform ?? "node",
3941
+ resolve: {
3942
+ conditionNames: envOptions.resolve.conditions,
3943
+ mainFields: envOptions.resolve.mainFields,
3944
+ ...restInputOptions.resolve
3945
+ },
3946
+ // server 产物:node 内建恒外部化;bare specifier 默认外部化
3947
+ //(同 Vite ssr.external 默认 —— 依赖由 node_modules 运行时解析),
3948
+ // 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
3949
+ external: restInputOptions.external ?? ((id) => {
3950
+ if (NODE_BUILTINS2.has(id)) return true;
3951
+ return !id.startsWith(".") && !import_node_path12.default.isAbsolute(id) && !id.startsWith("\0");
3952
+ })
3953
+ } : {}
3954
+ };
3955
+ const outputOptions = isServer ? {
3956
+ format: "esm",
3957
+ sourcemap: !!envOptions.build.sourcemap,
3958
+ minify: !!envOptions.build.minify,
3959
+ entryFileNames: "[name].js",
3960
+ chunkFileNames: "chunks/[name]-[hash].js",
3961
+ assetFileNames: `${assetsDir}/[name].[hash][extname]`,
3962
+ ...userOutput,
3963
+ dir: outDir
3964
+ } : {
3965
+ format: "esm",
3966
+ sourcemap: !!envOptions.build.sourcemap,
3967
+ minify: !!envOptions.build.minify,
3968
+ entryFileNames: `${assetsDir}/[name].[hash].js`,
3969
+ chunkFileNames: `${assetsDir}/[name].[hash].js`,
3970
+ assetFileNames: `${assetsDir}/[name].[hash][extname]`,
3971
+ // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
3972
+ ...userOutput,
3973
+ // dir 始终由 Nasti 掌管 —— HTML 改写依赖固定的产物目录,故放在最后强制生效
3974
+ dir: outDir
3975
+ };
3976
+ return { inputOptions, outputOptions, outDir };
3977
+ }
3978
+ function toRolldownPlugins(plugins) {
3979
+ return plugins.map((p) => ({
3980
+ name: p.name,
3981
+ resolveId: p.resolveId,
3982
+ load: p.load,
3983
+ transform: p.transform,
3984
+ buildStart: p.buildStart,
3985
+ buildEnd: p.buildEnd,
3986
+ // closeBundle 在 bundle.close() 时触发 —— PWA manifest/SW 等终态产物依赖
3987
+ closeBundle: p.closeBundle,
3988
+ renderChunk: p.renderChunk,
3989
+ augmentChunkHash: p.augmentChunkHash,
3990
+ generateBundle: p.generateBundle
3991
+ }));
3992
+ }
3993
+ function resolveClientEntries(config, html) {
3994
+ const entryPoints = [];
3995
+ if (html) {
3996
+ const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
3997
+ for (const match of scriptMatches) {
3998
+ const src = match[1];
3999
+ if (src && !src.startsWith("http")) {
4000
+ entryPoints.push(import_node_path12.default.resolve(config.root, src.replace(/^\//, "")));
4001
+ }
4002
+ }
4003
+ }
4004
+ if (entryPoints.length === 0) {
4005
+ const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
4006
+ for (const entry of fallbackEntries) {
4007
+ const fullPath = import_node_path12.default.resolve(config.root, entry);
4008
+ if (import_node_fs9.default.existsSync(fullPath)) {
4009
+ entryPoints.push(fullPath);
4010
+ break;
4011
+ }
4012
+ }
4013
+ }
4014
+ return entryPoints;
4015
+ }
4016
+ function createOxcTransformPlugin(config, environment) {
4017
+ return {
4018
+ name: "nasti:oxc-transform",
4019
+ transform(code, id) {
4020
+ if (!shouldTransform(id)) return null;
4021
+ const result = transformCode(id, code, {
4022
+ sourcemap: !!environment.options.build.sourcemap,
4023
+ jsxRuntime: "automatic",
4024
+ jsxImportSource: config.framework === "vue" ? "vue" : "react"
4025
+ });
4026
+ return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
4027
+ }
4028
+ };
4029
+ }
4030
+ async function build(inlineConfig = {}) {
4031
+ const config = await resolveConfig(inlineConfig, "build");
4032
+ const logger = config.logger;
4033
+ const startTime = performance.now();
4034
+ logger.info(
4035
+ import_picocolors6.default.cyan(`
4036
+ nasti v${"2.0.1"} `) + import_picocolors6.default.green(`building for ${config.mode}...`)
4037
+ );
4038
+ debug5?.(`root: ${config.root}`);
4039
+ const buildableNames = Object.keys(config.environments).filter(
4040
+ (name) => name === "client" || config.environments[name].entry.length > 0
4041
+ );
4042
+ buildableNames.sort((a, b) => a === "client" ? -1 : b === "client" ? 1 : 0);
4043
+ const environments = {};
4044
+ let clientOutput = [];
4045
+ for (const name of buildableNames) {
4046
+ const output = name === "client" ? await buildClientEnvironment(config) : await buildServerEnvironment(config, name);
4047
+ environments[name] = output;
4048
+ if (name === "client") clientOutput = output;
4049
+ if (buildableNames.length > 1) {
4050
+ debug5?.(`environment "${name}" built (${output.length} files)`);
4051
+ }
4052
+ }
4053
+ const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
4054
+ const totalSize = Object.values(environments).flat().reduce((sum, chunk) => {
4055
+ const content = chunk.type === "chunk" ? chunk.code : chunk.source;
4056
+ if (content == null) return sum;
4057
+ return sum + (typeof content === "string" ? Buffer.byteLength(content) : content.byteLength);
4058
+ }, 0);
4059
+ const fileCount = Object.values(environments).flat().length;
4060
+ const envSuffix = buildableNames.length > 1 ? ` (${buildableNames.join(" + ")})` : "";
4061
+ logger.info(import_picocolors6.default.green(`\u2713 built in ${elapsed}s`) + import_picocolors6.default.dim(envSuffix));
4062
+ logger.info(import_picocolors6.default.dim(` ${fileCount} files, ${displaySize(totalSize)} total \u2192 ${config.build.outDir}/`));
4063
+ return { output: clientOutput, environments };
4064
+ }
4065
+ async function buildClientEnvironment(config) {
4066
+ const logger = config.logger;
4067
+ const outDir = import_node_path12.default.resolve(config.root, config.build.outDir);
4068
+ if (config.build.emptyOutDir && import_node_fs9.default.existsSync(outDir)) {
4069
+ import_node_fs9.default.rmSync(outDir, { recursive: true, force: true });
4070
+ }
4071
+ import_node_fs9.default.mkdirSync(outDir, { recursive: true });
4072
+ const html = await readHtmlFile(config.root);
4073
+ const entryPoints = resolveClientEntries(config, html);
4074
+ if (entryPoints.length === 0) {
4075
+ throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
4076
+ }
4077
+ const cssEngine = createCssEngine();
4078
+ const pluginList = resolvePluginList(config, config.plugins, { cssEngine });
4079
+ const clientEnv = new NastiEnvironment("client", { ...config, plugins: pluginList }, {
4080
+ mode: "build",
4081
+ plugins: pluginList
4082
+ });
4083
+ await clientEnv.init();
4084
+ const allPlugins = clientEnv.plugins;
4085
+ const nativeReporter = config.logLevel === "silent" ? null : await tryNativeReporterPlugin(config, logger);
4086
+ const rolldownPlugins = [
4087
+ createOxcTransformPlugin(config, clientEnv),
4088
+ ...toRolldownPlugins(allPlugins),
4089
+ ...nativeReporter ? [nativeReporter] : []
4090
+ ];
4091
+ const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
4092
+ const bundle2 = await (0, import_rolldown.rolldown)(inputOptions);
4093
+ const { output } = await bundle2.write(outputOptions);
4094
+ await bundle2.close();
4095
+ if (html) {
4096
+ let processedHtml = html;
4097
+ const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
4098
+ for (const p of htmlPlugins) {
4099
+ const result = await p.transformIndexHtml(processedHtml);
4100
+ if (typeof result === "string") {
4101
+ processedHtml = result;
4102
+ } else if (result && "html" in result) {
4103
+ processedHtml = processHtml(result.html, result.tags);
4104
+ } else if (Array.isArray(result)) {
4105
+ processedHtml = processHtml(processedHtml, result);
4106
+ }
4107
+ }
4108
+ processedHtml = injectCssLinks(processedHtml, cssEngine, config);
4109
+ for (const chunk of output) {
4110
+ if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
4111
+ const originalEntry = import_node_path12.default.relative(config.root, chunk.facadeModuleId);
4112
+ processedHtml = processedHtml.replace(
4113
+ new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
4114
+ `$1${config.base}${chunk.fileName}$3`
4115
+ );
4116
+ }
4117
+ }
4118
+ import_node_fs9.default.writeFileSync(import_node_path12.default.resolve(outDir, "index.html"), processedHtml);
4119
+ }
4120
+ if (!nativeReporter && config.logLevel !== "silent") {
4121
+ reportBuildOutput(output, config, logger);
4122
+ }
4123
+ warnLargeChunks(output, config, logger);
4124
+ return output;
1823
4125
  }
1824
- function rewriteCssUrls(css, from, root) {
1825
- return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
1826
- if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
1827
- return match;
4126
+ async function buildServerEnvironment(config, name) {
4127
+ const envOptions = config.environments[name];
4128
+ const logger = config.logger;
4129
+ for (const entry of envOptions.entry) {
4130
+ if (!import_node_fs9.default.existsSync(entry)) {
4131
+ throw new Error(`[nasti] environment "${name}" entry not found: ${entry}`);
1828
4132
  }
1829
- const resolved = import_node_path8.default.resolve(import_node_path8.default.dirname(from), url);
1830
- const relative = "/" + import_node_path8.default.relative(root, resolved);
1831
- return `url(${relative})`;
4133
+ }
4134
+ const pluginList = resolvePluginList(config, config.plugins, { consumer: envOptions.consumer });
4135
+ const environment = new NastiEnvironment(name, { ...config, plugins: pluginList }, {
4136
+ mode: "build",
4137
+ plugins: pluginList
1832
4138
  });
4139
+ await environment.init();
4140
+ const rolldownPlugins = [
4141
+ createOxcTransformPlugin(config, environment),
4142
+ ...toRolldownPlugins(environment.plugins)
4143
+ ];
4144
+ const { inputOptions, outputOptions, outDir } = getRolldownOptions(
4145
+ environment,
4146
+ envOptions.entry,
4147
+ rolldownPlugins
4148
+ );
4149
+ if (envOptions.build.emptyOutDir && import_node_fs9.default.existsSync(outDir)) {
4150
+ import_node_fs9.default.rmSync(outDir, { recursive: true, force: true });
4151
+ }
4152
+ import_node_fs9.default.mkdirSync(outDir, { recursive: true });
4153
+ const bundle2 = await (0, import_rolldown.rolldown)(inputOptions);
4154
+ const { output } = await bundle2.write(outputOptions);
4155
+ await bundle2.close();
4156
+ logger.info(
4157
+ import_picocolors6.default.dim(` [${name}] `) + output.map((o) => import_node_path12.default.join(envOptions.build.outDir, o.fileName)).join(import_picocolors6.default.dim(", "))
4158
+ );
4159
+ return output;
1833
4160
  }
1834
- var import_node_path8;
1835
- var init_css = __esm({
1836
- "src/plugins/css.ts"() {
4161
+ function injectCssLinks(html, cssEngine, config) {
4162
+ const cssLinkTags = [];
4163
+ if (cssEngine.singleFileName) {
4164
+ cssLinkTags.push({
4165
+ tag: "link",
4166
+ attrs: { rel: "stylesheet", href: config.base + cssEngine.singleFileName },
4167
+ injectTo: "head"
4168
+ });
4169
+ } else {
4170
+ for (const files of cssEngine.entryCss.values()) {
4171
+ for (const file of files) {
4172
+ cssLinkTags.push({
4173
+ tag: "link",
4174
+ attrs: { rel: "stylesheet", href: config.base + file },
4175
+ injectTo: "head"
4176
+ });
4177
+ }
4178
+ }
4179
+ }
4180
+ return cssLinkTags.length > 0 ? processHtml(html, cssLinkTags) : html;
4181
+ }
4182
+ function escapeRegExp(string) {
4183
+ return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
4184
+ }
4185
+ var import_node_path12, import_node_fs9, import_node_module5, import_rolldown, import_picocolors6, debug5, NODE_BUILTINS2;
4186
+ var init_build = __esm({
4187
+ "src/build/index.ts"() {
1837
4188
  "use strict";
1838
- import_node_path8 = __toESM(require("path"), 1);
1839
- init_tailwind();
4189
+ import_node_path12 = __toESM(require("path"), 1);
4190
+ import_node_fs9 = __toESM(require("fs"), 1);
4191
+ import_node_module5 = require("module");
4192
+ import_rolldown = require("rolldown");
4193
+ init_config();
4194
+ init_builtins();
4195
+ init_environment();
4196
+ init_css_engine();
4197
+ init_html();
4198
+ init_transformer();
4199
+ init_env();
4200
+ init_reporter();
4201
+ init_debug();
4202
+ import_picocolors6 = __toESM(require("picocolors"), 1);
4203
+ debug5 = createDebugger("nasti:build");
4204
+ NODE_BUILTINS2 = /* @__PURE__ */ new Set([...import_node_module5.builtinModules, ...import_node_module5.builtinModules.map((m) => `node:${m}`)]);
1840
4205
  }
1841
4206
  });
1842
4207
 
1843
- // src/plugins/assets.ts
1844
- function assetsPlugin(config) {
1845
- return {
1846
- name: "nasti:assets",
1847
- resolveId(source) {
1848
- if (source.endsWith("?url") || source.endsWith("?raw")) {
1849
- return source;
4208
+ // src/server/bundled/dev-engine.ts
4209
+ var dev_engine_exports = {};
4210
+ __export(dev_engine_exports, {
4211
+ createBundledDevServer: () => createBundledDevServer
4212
+ });
4213
+ async function createBundledDevServer(opts) {
4214
+ const { config, clientEnv, httpServer } = opts;
4215
+ const logger = config.logger;
4216
+ let devFn;
4217
+ let refreshWrapperFn = null;
4218
+ try {
4219
+ const experimental = await import("rolldown/experimental");
4220
+ devFn = experimental.dev;
4221
+ if (typeof devFn !== "function") throw new Error("dev() export missing");
4222
+ if (typeof experimental.viteReactRefreshWrapperPlugin === "function") {
4223
+ refreshWrapperFn = experimental.viteReactRefreshWrapperPlugin;
4224
+ }
4225
+ } catch (err) {
4226
+ throw new Error(
4227
+ `[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.`
4228
+ );
4229
+ }
4230
+ const html = await readHtmlFile(config.root);
4231
+ const entryPoints = resolveClientEntries(config, html);
4232
+ if (entryPoints.length === 0) {
4233
+ throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
4234
+ }
4235
+ const memoryFiles = new MemoryFiles();
4236
+ const patches = new MemoryFiles();
4237
+ const entryFileNames = /* @__PURE__ */ new Map();
4238
+ const bundledClients = /* @__PURE__ */ new Map();
4239
+ const useReactRefresh = config.framework !== "vue" && refreshWrapperFn != null;
4240
+ const rolldownPlugins = [
4241
+ ...useReactRefresh ? [
4242
+ createReactRefreshRuntimePlugin(entryPoints),
4243
+ createBundledOxcRefreshPlugin()
4244
+ ] : [],
4245
+ ...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins)),
4246
+ ...useReactRefresh ? [
4247
+ refreshWrapperFn({
4248
+ cwd: config.root,
4249
+ include: [/\.[jt]sx(\?.*)?$/],
4250
+ exclude: [/node_modules/],
4251
+ jsxImportSource: "react",
4252
+ reactRefreshHost: ""
4253
+ })
4254
+ ] : []
4255
+ ];
4256
+ const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
4257
+ let fullReloadTimer = null;
4258
+ const scheduleFullReload = () => {
4259
+ if (fullReloadTimer) clearTimeout(fullReloadTimer);
4260
+ fullReloadTimer = setTimeout(() => {
4261
+ logger.info(import_picocolors7.default.green("page reload ") + import_picocolors7.default.dim("(bundled)"), { timestamp: true });
4262
+ broadcast({ type: "hmr:reload" });
4263
+ }, 30);
4264
+ };
4265
+ const broadcast = (payload) => {
4266
+ const data = JSON.stringify(payload);
4267
+ for (const ws of bundledClients.values()) {
4268
+ if (ws.readyState === 1) ws.send(data);
4269
+ }
4270
+ };
4271
+ const sendTo = (clientId, payload) => {
4272
+ const ws = bundledClients.get(clientId);
4273
+ if (ws && ws.readyState === 1) ws.send(JSON.stringify(payload));
4274
+ };
4275
+ async function processUpdates(updates, changedFiles) {
4276
+ let needsLatestOutput = false;
4277
+ for (const { clientId, update } of updates) {
4278
+ if (update.type === "Noop") continue;
4279
+ if (update.type === "FullReload") {
4280
+ debug6?.(`full reload for ${clientId}: ${update.reason ?? ""}`);
4281
+ needsLatestOutput = true;
4282
+ continue;
4283
+ }
4284
+ const patchPath = `__nasti_patch/${update.filename}`;
4285
+ patches.set(patchPath, update.code + "\n;export {}");
4286
+ if (update.sourcemap && update.sourcemapFilename) {
4287
+ patches.set(`__nasti_patch/${update.sourcemapFilename}`, update.sourcemap);
4288
+ }
4289
+ const url = `/${patchPath}`;
4290
+ logger.info(
4291
+ import_picocolors7.default.green("hmr update ") + import_picocolors7.default.dim(changedFiles.map((f) => import_node_path13.default.relative(config.root, f)).join(", ")),
4292
+ { timestamp: true }
4293
+ );
4294
+ sendTo(clientId, { type: "hmr:update", path: url, url });
4295
+ }
4296
+ if (needsLatestOutput) {
4297
+ await engine.ensureLatestBuildOutput();
4298
+ scheduleFullReload();
4299
+ }
4300
+ }
4301
+ const engine = await devFn(
4302
+ {
4303
+ ...inputOptions,
4304
+ cwd: config.root,
4305
+ // Rolldown bug 规避:inlineConst 与 dev patch 机制冲突(vitejs/vite#21843)
4306
+ optimization: { ...inputOptions.optimization, inlineConst: false },
4307
+ experimental: {
4308
+ ...inputOptions.experimental,
4309
+ devMode: {
4310
+ lazy: true,
4311
+ // 默认 DevRuntime 把 ws 地址烤进 bundle:指向 Nasti dev server 本身
4312
+ //(端口被占自动 +1 时 HMR ws 会失联 —— 已知限制,产物仍可服务)
4313
+ host: config.server.host === true ? "localhost" : config.server.host || "localhost",
4314
+ port: config.server.port
4315
+ }
1850
4316
  }
1851
- return null;
1852
4317
  },
1853
- load(id) {
1854
- const ext = import_node_path9.default.extname(id.replace(/\?.*$/, ""));
1855
- if (id.endsWith("?raw")) {
1856
- const file = id.slice(0, -4);
1857
- if (import_node_fs7.default.existsSync(file)) {
1858
- const content = import_node_fs7.default.readFileSync(file, "utf-8");
1859
- return `export default ${JSON.stringify(content)}`;
4318
+ {
4319
+ ...outputOptions,
4320
+ entryFileNames: "assets/[name].js",
4321
+ chunkFileNames: "assets/[name]-[hash].js",
4322
+ minify: false,
4323
+ sourcemap: true
4324
+ },
4325
+ {
4326
+ watch: { skipWrite: true },
4327
+ rebuildStrategy: "auto",
4328
+ onOutput(result) {
4329
+ if (result instanceof Error) {
4330
+ logger.error(import_picocolors7.default.red(`[bundled] build error: ${result.message}`), { error: result });
4331
+ return;
4332
+ }
4333
+ for (const file of result.output) {
4334
+ const content = file.type === "chunk" ? file.code : file.source;
4335
+ if (content != null) memoryFiles.set(file.fileName, content);
4336
+ if (file.type === "chunk" && file.isEntry && file.facadeModuleId) {
4337
+ entryFileNames.set(file.facadeModuleId, file.fileName);
4338
+ }
4339
+ if (file.type === "chunk" && file.map) {
4340
+ memoryFiles.set(`${file.fileName}.map`, JSON.stringify(file.map));
4341
+ }
4342
+ }
4343
+ debug6?.(`bundle output refreshed (${result.output.length} files)`);
4344
+ },
4345
+ async onHmrUpdates(result) {
4346
+ if (result instanceof Error) {
4347
+ logger.error(import_picocolors7.default.red(`[bundled] hmr error: ${result.message}`), { error: result });
4348
+ broadcast({ type: "error", err: { message: result.message, stack: result.stack } });
4349
+ return;
1860
4350
  }
4351
+ const { updates, changedFiles } = result;
4352
+ debug6?.(
4353
+ `onHmrUpdates(engine watcher): ${changedFiles.length} changed, ${updates.length} updates`
4354
+ );
4355
+ if (changedFiles.length === 0) return;
4356
+ await processUpdates(updates, changedFiles);
1861
4357
  }
1862
- if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
1863
- const file = id.replace(/\?.*$/, "");
1864
- if (!import_node_fs7.default.existsSync(file)) return null;
1865
- if (config.command === "serve") {
1866
- const url = "/" + import_node_path9.default.relative(config.root, file);
1867
- return `export default ${JSON.stringify(url)}`;
4358
+ }
4359
+ );
4360
+ await engine.run();
4361
+ await engine.ensureCurrentBuildFinish();
4362
+ logger.info(import_picocolors7.default.dim(` bundled dev engine ready (${entryPoints.length} entries, in-memory)`));
4363
+ const wss = new import_ws2.WebSocketServer({ noServer: true });
4364
+ httpServer.on("upgrade", (req, socket, head) => {
4365
+ if (req.headers["sec-websocket-protocol"] === "nasti-hmr") return;
4366
+ const url = new URL(req.url ?? "/", "http://localhost");
4367
+ const clientId = url.searchParams.get("clientId");
4368
+ if (!clientId) return;
4369
+ wss.handleUpgrade(req, socket, head, (ws) => {
4370
+ bundledClients.set(clientId, ws);
4371
+ debug6?.(`bundled client connected: ${clientId}`);
4372
+ ws.send(JSON.stringify({ type: "connected" }));
4373
+ ws.on("message", async (raw) => {
4374
+ try {
4375
+ const msg = JSON.parse(String(raw));
4376
+ if (msg.type === "hmr:module-registered" && Array.isArray(msg.modules)) {
4377
+ await engine.registerModules(clientId, msg.modules);
4378
+ debug6?.(`registered ${msg.modules.length} modules for ${clientId}`);
4379
+ } else if (msg.type === "hmr:invalidate") {
4380
+ scheduleFullReload();
4381
+ }
4382
+ } catch (err) {
4383
+ debug6?.(`bundled ws message error: ${err.message}`);
1868
4384
  }
1869
- const content = import_node_fs7.default.readFileSync(file);
1870
- const hash = import_node_crypto.default.createHash("sha256").update(content).digest("hex").slice(0, 8);
1871
- const basename = import_node_path9.default.basename(file, ext);
1872
- const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
1873
- return `export default ${JSON.stringify(config.base + hashedName)}`;
4385
+ });
4386
+ ws.on("close", () => {
4387
+ bundledClients.delete(clientId);
4388
+ engine.removeClient(clientId).catch((err) => debug6?.(`removeClient failed for ${clientId}: ${err?.message ?? err}`));
4389
+ });
4390
+ });
4391
+ });
4392
+ const middleware = (req, res, next) => {
4393
+ void (async () => {
4394
+ const rawUrl = req.url ?? "/";
4395
+ const url = new URL(rawUrl, "http://localhost");
4396
+ const pathname = decodeURIComponent(url.pathname);
4397
+ if (pathname === "/@vite/lazy" || pathname === "/@nasti/lazy") {
4398
+ const id = url.searchParams.get("id");
4399
+ const clientId = url.searchParams.get("clientId");
4400
+ if (!id || !clientId) {
4401
+ res.statusCode = 400;
4402
+ res.end("// [nasti] lazy endpoint requires id & clientId");
4403
+ return;
4404
+ }
4405
+ const code = await engine.compileEntry(id, clientId);
4406
+ res.setHeader("Content-Type", "application/javascript");
4407
+ res.setHeader("Cache-Control", "no-store");
4408
+ res.end(code + "\n;export {}");
4409
+ return;
1874
4410
  }
1875
- return null;
4411
+ const patchHit = patches.get(pathname.replace(/^\//, ""));
4412
+ if (patchHit) {
4413
+ res.setHeader("Content-Type", "application/javascript");
4414
+ res.setHeader("Cache-Control", "no-store");
4415
+ res.end(patchHit.content);
4416
+ return;
4417
+ }
4418
+ const fileName = pathname.replace(/^\//, "");
4419
+ const hit = memoryFiles.get(fileName);
4420
+ if (hit) {
4421
+ if (req.headers["if-none-match"] === hit.etag) {
4422
+ res.statusCode = 304;
4423
+ res.end();
4424
+ return;
4425
+ }
4426
+ res.setHeader("ETag", hit.etag);
4427
+ res.setHeader("Content-Type", MIME_TYPES[import_node_path13.default.extname(fileName)] ?? "application/octet-stream");
4428
+ res.setHeader("Cache-Control", "no-cache");
4429
+ res.end(hit.content);
4430
+ return;
4431
+ }
4432
+ if (pathname === "/" || pathname.endsWith(".html")) {
4433
+ const rawHtml = await readHtmlFile(config.root);
4434
+ if (rawHtml) {
4435
+ res.setHeader("Content-Type", "text/html");
4436
+ res.setHeader("Cache-Control", "no-store");
4437
+ res.end(await renderBundledIndexHtml(rawHtml, config, entryFileNames));
4438
+ return;
4439
+ }
4440
+ }
4441
+ next();
4442
+ })().catch((err) => {
4443
+ config.logger.error(import_picocolors7.default.red(`[bundled] ${err.message}`), { error: err });
4444
+ res.statusCode = 500;
4445
+ res.end(`[nasti bundled] ${err.message}`);
4446
+ });
4447
+ };
4448
+ return {
4449
+ middleware,
4450
+ async close() {
4451
+ if (fullReloadTimer) clearTimeout(fullReloadTimer);
4452
+ wss.close();
4453
+ await engine.close();
1876
4454
  }
1877
4455
  };
1878
4456
  }
1879
- var import_node_path9, import_node_fs7, import_node_crypto, ASSET_EXTENSIONS;
1880
- var init_assets = __esm({
1881
- "src/plugins/assets.ts"() {
1882
- "use strict";
1883
- import_node_path9 = __toESM(require("path"), 1);
1884
- import_node_fs7 = __toESM(require("fs"), 1);
1885
- import_node_crypto = __toESM(require("crypto"), 1);
1886
- ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
1887
- ".png",
1888
- ".jpg",
1889
- ".jpeg",
1890
- ".gif",
1891
- ".svg",
1892
- ".ico",
1893
- ".webp",
1894
- ".avif",
1895
- ".mp4",
1896
- ".webm",
1897
- ".ogg",
1898
- ".mp3",
1899
- ".wav",
1900
- ".flac",
1901
- ".aac",
1902
- ".woff",
1903
- ".woff2",
1904
- ".eot",
1905
- ".ttf",
1906
- ".otf",
1907
- ".pdf",
1908
- ".txt"
1909
- ]);
1910
- }
1911
- });
1912
-
1913
- // src/plugins/vue.ts
1914
- async function loadVueCompiler() {
1915
- if (compiler) return compiler;
1916
- try {
1917
- compiler = await import("@vue/compiler-sfc");
1918
- return compiler;
1919
- } catch {
1920
- return null;
1921
- }
4457
+ function stripCatchAllLoad(plugins) {
4458
+ return plugins.map(
4459
+ (p) => p?.name === "nasti:resolve" ? { ...p, load: void 0 } : p
4460
+ );
1922
4461
  }
1923
- function vuePlugin(config) {
1924
- const isDev = config.command === "serve";
1925
- const descriptorCache = /* @__PURE__ */ new Map();
4462
+ function createReactRefreshRuntimePlugin(entryPoints) {
4463
+ const entryIds = new Set(entryPoints.map((p) => import_node_path13.default.resolve(p)));
1926
4464
  return {
1927
- name: "nasti:vue",
1928
- enforce: "pre",
1929
- async resolveId(source) {
1930
- if (VUE_QUERY_RE.test(source)) {
1931
- return source;
1932
- }
4465
+ name: "nasti:bundled-react-refresh",
4466
+ resolveId(source) {
4467
+ if (source === REFRESH_RUNTIME_URL) return REFRESH_RUNTIME_URL;
4468
+ if (source === PREAMBLE_SPEC) return RESOLVED_PREAMBLE_ID;
1933
4469
  return null;
1934
4470
  },
1935
- async transform(code, id) {
1936
- if (!VUE_FILE_RE.test(id) && !VUE_QUERY_RE.test(id)) return null;
1937
- const sfc = await loadVueCompiler();
1938
- if (!sfc) {
1939
- console.warn("[nasti:vue] @vue/compiler-sfc not found. Install it: npm install @vue/compiler-sfc");
1940
- return null;
1941
- }
1942
- if (VUE_QUERY_RE.test(id)) {
1943
- return handleVueSubBlock(id, sfc, descriptorCache, config);
1944
- }
1945
- const { descriptor, errors } = sfc.parse(code, { filename: id });
1946
- if (errors.length) {
1947
- console.error(`[nasti:vue] Parse error in ${id}:`, errors[0].message);
1948
- return null;
1949
- }
1950
- descriptorCache.set(id, descriptor);
1951
- const scopeId = hashId(id);
1952
- let scriptCode = "";
1953
- if (descriptor.script || descriptor.scriptSetup) {
1954
- const compiled = sfc.compileScript(descriptor, {
1955
- id: scopeId,
1956
- isProd: !isDev,
1957
- inlineTemplate: true,
1958
- // 让 compileScript 产出 `const __sfc__ = ...`(而非默认的 `export default {...}`)。
1959
- // 否则下方追加的 `__sfc__.render` / `__sfc__.__scopeId` / HMR 记录会引用一个
1960
- // 不存在的 `__sfc__`,并与 compileScript 自带的 `export default` 形成双重默认导出。
1961
- genDefaultAs: "__sfc__"
1962
- });
1963
- scriptCode = compiled.content;
1964
- }
1965
- let templateCode = "";
1966
- if (descriptor.template && !descriptor.scriptSetup) {
1967
- const compiled = sfc.compileTemplate({
1968
- source: descriptor.template.content,
1969
- filename: id,
1970
- id: scopeId,
1971
- compilerOptions: { scopeId: `data-v-${scopeId}` }
1972
- });
1973
- templateCode = compiled.code;
1974
- }
1975
- let output = scriptCode || "const __sfc__ = {}";
1976
- if (templateCode) {
1977
- output += `
1978
- ${templateCode}
1979
- `;
1980
- output += `
1981
- __sfc__.render = render
1982
- `;
4471
+ load(id) {
4472
+ if (id === REFRESH_RUNTIME_URL) {
4473
+ return { code: getReactRefreshRuntimeEsm() + WRAPPER_RUNTIME_HELPERS, moduleType: "js" };
1983
4474
  }
1984
- if (descriptor.styles.length > 0) {
1985
- for (let i = 0; i < descriptor.styles.length; i++) {
1986
- const style = descriptor.styles[i];
1987
- const lang2 = style.lang ?? "css";
1988
- output += `
1989
- import "${id}?vue&type=style&index=${i}&lang=${lang2}"
1990
- `;
1991
- }
4475
+ if (id === RESOLVED_PREAMBLE_ID) {
4476
+ return { code: BUNDLED_PREAMBLE_CODE, moduleType: "js" };
1992
4477
  }
1993
- output += `
1994
- __sfc__.__scopeId = "data-v-${scopeId}"
1995
- `;
1996
- if (isDev) {
1997
- output += `
1998
- __sfc__.__hmrId = ${JSON.stringify(scopeId)}
1999
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
2000
- __VUE_HMR_RUNTIME__.createRecord(__sfc__.__hmrId, __sfc__)
4478
+ return null;
4479
+ },
4480
+ transform(code, id) {
4481
+ if (!entryIds.has(import_node_path13.default.resolve(id.split("?")[0]))) return null;
4482
+ return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
4483
+ ${code}`, map: null };
4484
+ }
4485
+ };
2001
4486
  }
2002
- if (import.meta.hot) {
2003
- import.meta.hot.accept((mod) => {
2004
- if (!mod) return
2005
- const { default: updated } = mod
2006
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
2007
- __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)
4487
+ function createBundledOxcRefreshPlugin() {
4488
+ return {
4489
+ name: "nasti:bundled-oxc-refresh",
4490
+ transform(code, id) {
4491
+ const clean = id.split("?")[0];
4492
+ if (!/\.[jt]sx$/.test(clean) || clean.includes("/node_modules/")) return null;
4493
+ const result = transformCode(clean, code, {
4494
+ sourcemap: true,
4495
+ jsxRuntime: "automatic",
4496
+ jsxImportSource: "react",
4497
+ reactRefresh: true
4498
+ });
4499
+ return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2008
4500
  }
2009
- })
4501
+ };
2010
4502
  }
2011
- `;
4503
+ async function renderBundledIndexHtml(html, config, entryFileNames) {
4504
+ let processed = html;
4505
+ for (const plugin of config.plugins) {
4506
+ if (!plugin.transformIndexHtml || plugin.name === "nasti:html") continue;
4507
+ const result = await plugin.transformIndexHtml(processed);
4508
+ if (typeof result === "string") {
4509
+ processed = result;
4510
+ } else if (result && "html" in result) {
4511
+ processed = processHtml(result.html, result.tags);
4512
+ } else if (Array.isArray(result)) {
4513
+ processed = processHtml(processed, result);
4514
+ }
4515
+ }
4516
+ for (const [facadeModuleId, fileName] of entryFileNames) {
4517
+ const originalEntry = import_node_path13.default.relative(config.root, facadeModuleId);
4518
+ processed = processed.replace(
4519
+ new RegExp(`(src=["'])/?(${originalEntry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})(["'])`, "g"),
4520
+ `$1/${fileName}$3`
4521
+ );
4522
+ }
4523
+ return processed;
4524
+ }
4525
+ var import_node_path13, import_node_crypto3, import_ws2, import_picocolors7, debug6, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
4526
+ var init_dev_engine = __esm({
4527
+ "src/server/bundled/dev-engine.ts"() {
4528
+ "use strict";
4529
+ import_node_path13 = __toESM(require("path"), 1);
4530
+ import_node_crypto3 = __toESM(require("crypto"), 1);
4531
+ import_ws2 = require("ws");
4532
+ import_picocolors7 = __toESM(require("picocolors"), 1);
4533
+ init_build();
4534
+ init_html();
4535
+ init_transformer();
4536
+ init_middleware();
4537
+ init_debug();
4538
+ debug6 = createDebugger("nasti:bundled");
4539
+ MIME_TYPES = {
4540
+ ".js": "application/javascript",
4541
+ ".mjs": "application/javascript",
4542
+ ".css": "text/css",
4543
+ ".html": "text/html",
4544
+ ".json": "application/json",
4545
+ ".map": "application/json",
4546
+ ".svg": "image/svg+xml",
4547
+ ".png": "image/png",
4548
+ ".jpg": "image/jpeg",
4549
+ ".wasm": "application/wasm"
4550
+ };
4551
+ MemoryFiles = class {
4552
+ files = /* @__PURE__ */ new Map();
4553
+ set(fileName, content) {
4554
+ const etag = `"${import_node_crypto3.default.createHash("sha1").update(content).digest("base64").slice(0, 27)}"`;
4555
+ this.files.set(fileName, { content, etag });
2012
4556
  }
2013
- output += `
2014
- export default __sfc__
2015
- `;
2016
- const lang = descriptor.scriptSetup?.lang ?? descriptor.script?.lang;
2017
- if (lang === "ts") {
2018
- const transpiled = transformCode(`${id}.ts`, output, { sourcemap: false });
2019
- return { code: transpiled.code };
4557
+ get(fileName) {
4558
+ return this.files.get(fileName);
2020
4559
  }
2021
- return { code: output };
2022
- },
2023
- handleHotUpdate(ctx) {
2024
- const { file, modules } = ctx;
2025
- if (VUE_FILE_RE.test(file)) {
2026
- for (const mod of modules) {
2027
- mod.isSelfAccepting = true;
2028
- }
2029
- descriptorCache.delete(file);
4560
+ clear() {
4561
+ this.files.clear();
4562
+ }
4563
+ };
4564
+ PREAMBLE_SPEC = "nasti:react-preamble";
4565
+ RESOLVED_PREAMBLE_ID = "\0nasti:react-preamble";
4566
+ REFRESH_RUNTIME_URL = "/@react-refresh";
4567
+ BUNDLED_PREAMBLE_CODE = `
4568
+ import __rt from ${JSON.stringify(REFRESH_RUNTIME_URL)};
4569
+ __rt.injectIntoGlobalHook(window);
4570
+ window.$RefreshReg$ = () => {};
4571
+ window.$RefreshSig$ = () => (type) => type;
4572
+ window.__vite_plugin_react_preamble_installed__ = true;
4573
+ `;
4574
+ WRAPPER_RUNTIME_HELPERS = `
4575
+ // \u2500\u2500 viteReactRefreshWrapperPlugin \u8FD0\u884C\u65F6\u5951\u7EA6\uFF08@vitejs/plugin-react \u540C\u6B3E\uFF09\u2500\u2500
4576
+ function __isPlainObject(obj) {
4577
+ return Object.prototype.toString.call(obj) === '[object Object]' &&
4578
+ (obj.constructor === Object || obj.constructor === undefined);
4579
+ }
4580
+ function __isCompoundComponent(type) {
4581
+ if (!__isPlainObject(type)) return false;
4582
+ for (const key in type) {
4583
+ if (!isLikelyComponentType(type[key])) return false;
4584
+ }
4585
+ return true;
4586
+ }
4587
+ export function registerExportsForReactRefresh(filename, moduleExports) {
4588
+ for (const key in moduleExports) {
4589
+ if (key === '__esModule') continue;
4590
+ const exportValue = moduleExports[key];
4591
+ if (isLikelyComponentType(exportValue)) {
4592
+ register(exportValue, filename + ' export ' + key);
4593
+ } else if (__isCompoundComponent(exportValue)) {
4594
+ for (const subKey in exportValue) {
4595
+ register(exportValue[subKey], filename + ' export ' + key + '-' + subKey);
2030
4596
  }
2031
- return modules;
2032
4597
  }
2033
- };
4598
+ }
2034
4599
  }
2035
- async function handleVueSubBlock(id, sfc, cache, config) {
2036
- const match = id.match(/(.+\.vue)\?vue&type=(\w+)(?:&index=(\d+))?(?:&lang=(\w+))?/);
2037
- if (!match) return null;
2038
- const [, filePath, type, indexStr, lang] = match;
2039
- const descriptor = cache.get(filePath);
2040
- if (!descriptor) return null;
2041
- if (type === "style") {
2042
- const index = parseInt(indexStr ?? "0", 10);
2043
- const style = descriptor.styles[index];
2044
- if (!style) return null;
2045
- const scopeId = hashId(filePath);
2046
- const result = await sfc.compileStyleAsync({
2047
- source: style.content,
2048
- filename: filePath,
2049
- id: `data-v-${scopeId}`,
2050
- scoped: style.scoped ?? false
2051
- });
2052
- const cssCode = JSON.stringify(result.code);
2053
- return {
2054
- code: `
2055
- const css = ${cssCode};
2056
- const style = document.createElement('style');
2057
- style.setAttribute('data-v-${scopeId}', '');
2058
- style.textContent = css;
2059
- document.head.appendChild(style);
2060
-
2061
- if (import.meta.hot) {
2062
- import.meta.hot.accept();
2063
- import.meta.hot.prune(() => style.remove());
4600
+ let __enqueueTimer;
4601
+ const __hooks = [];
4602
+ window.__registerBeforePerformReactRefresh = (cb) => { __hooks.push(cb); };
4603
+ function __enqueueUpdate() {
4604
+ clearTimeout(__enqueueTimer);
4605
+ __enqueueTimer = setTimeout(async () => {
4606
+ if (__hooks.length) await Promise.all(__hooks.map((cb) => cb()));
4607
+ performReactRefresh();
4608
+ }, 16);
2064
4609
  }
2065
- `
2066
- };
4610
+ function __predicateOnExport(ignoredExports, moduleExports, predicate) {
4611
+ for (const key in moduleExports) {
4612
+ if (ignoredExports.includes(key)) continue;
4613
+ if (!predicate(key, moduleExports[key])) return key;
2067
4614
  }
2068
- return null;
4615
+ return true;
2069
4616
  }
2070
- function hashId(filename) {
2071
- return import_node_crypto2.default.createHash("sha256").update(filename).digest("hex").slice(0, 8);
4617
+ export function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
4618
+ const ignoredExports = window.__getReactRefreshIgnoredExports?.({ id }) ?? [];
4619
+ if (__predicateOnExport(ignoredExports, prevExports, (key) => key in nextExports) !== true) {
4620
+ return 'Could not Fast Refresh (export removed)';
4621
+ }
4622
+ if (__predicateOnExport(ignoredExports, nextExports, (key) => key in prevExports) !== true) {
4623
+ return 'Could not Fast Refresh (new export)';
4624
+ }
4625
+ let hasExports = false;
4626
+ const allExportsAreComponentsOrUnchanged = __predicateOnExport(
4627
+ ignoredExports,
4628
+ nextExports,
4629
+ (key, value) => {
4630
+ hasExports = true;
4631
+ if (isLikelyComponentType(value)) return true;
4632
+ if (__isCompoundComponent(value)) return true;
4633
+ return prevExports[key] === nextExports[key];
4634
+ },
4635
+ );
4636
+ if (hasExports && allExportsAreComponentsOrUnchanged === true) {
4637
+ __enqueueUpdate();
4638
+ } else {
4639
+ return 'Could not Fast Refresh ("' + allExportsAreComponentsOrUnchanged + '" export is incompatible)';
4640
+ }
2072
4641
  }
2073
- var import_node_crypto2, VUE_FILE_RE, VUE_QUERY_RE, compiler;
2074
- var init_vue = __esm({
2075
- "src/plugins/vue.ts"() {
2076
- "use strict";
2077
- import_node_crypto2 = __toESM(require("crypto"), 1);
2078
- init_transformer();
2079
- VUE_FILE_RE = /\.vue$/;
2080
- VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang=\w+)?/;
2081
- compiler = null;
4642
+ export const __hmr_import = (module) => import(/* @vite-ignore */ module);
4643
+ `;
2082
4644
  }
2083
4645
  });
2084
4646
 
@@ -2088,38 +4650,71 @@ __export(server_exports, {
2088
4650
  createServer: () => createServer
2089
4651
  });
2090
4652
  async function createServer(inlineConfig = {}) {
4653
+ const startTime = performance.now();
2091
4654
  const config = await resolveConfig(inlineConfig, "serve");
2092
- const allPlugins = [
2093
- ...config.framework === "vue" ? [vuePlugin(config)] : [],
2094
- resolvePlugin(config),
2095
- cssPlugin(config),
2096
- assetsPlugin(config),
2097
- htmlPlugin(config),
2098
- ...config.plugins
2099
- ];
4655
+ const logger = config.logger;
4656
+ const allPlugins = resolvePluginList(config, config.plugins);
2100
4657
  const configWithPlugins = { ...config, plugins: allPlugins };
2101
- const moduleGraph = new ModuleGraph();
2102
- const pluginContainer = new PluginContainer(configWithPlugins);
2103
4658
  const app = (0, import_connect.default)();
4659
+ const httpServer = import_node_http.default.createServer(app);
4660
+ const ws = createWebSocketServer(httpServer);
4661
+ const clientEnv = new NastiEnvironment("client", configWithPlugins, {
4662
+ hot: createWsHotChannel(ws),
4663
+ mode: "dev",
4664
+ plugins: allPlugins
4665
+ });
4666
+ await clientEnv.init();
4667
+ const environments = { client: clientEnv };
4668
+ for (const name of Object.keys(config.environments)) {
4669
+ if (name === "client") continue;
4670
+ const consumer = config.environments[name].consumer;
4671
+ const envPlugins = resolvePluginList(config, config.plugins, { consumer });
4672
+ environments[name] = new NastiEnvironment(name, { ...config, plugins: envPlugins }, {
4673
+ mode: "dev",
4674
+ plugins: envPlugins
4675
+ });
4676
+ }
4677
+ let ssrRunner = null;
4678
+ async function getSsrRunner() {
4679
+ if (ssrRunner) return ssrRunner;
4680
+ const ssrEnv = environments.ssr;
4681
+ if (!ssrEnv) {
4682
+ throw new Error('[nasti] no "ssr" environment configured (config.environments.ssr)');
4683
+ }
4684
+ await ssrEnv.init();
4685
+ const { createModuleRunner: createModuleRunner2 } = await Promise.resolve().then(() => (init_runnable_environment(), runnable_environment_exports));
4686
+ ssrRunner = createModuleRunner2(ssrEnv);
4687
+ return ssrRunner;
4688
+ }
4689
+ const moduleGraph = clientEnv.moduleGraph;
4690
+ const pluginContainer = clientEnv.pluginContainer;
4691
+ let bundledServer = null;
4692
+ if (config.experimental.bundledDev) {
4693
+ const { createBundledDevServer: createBundledDevServer2 } = await Promise.resolve().then(() => (init_dev_engine(), dev_engine_exports));
4694
+ bundledServer = await createBundledDevServer2({
4695
+ config: configWithPlugins,
4696
+ clientEnv,
4697
+ httpServer
4698
+ });
4699
+ app.use(bundledServer.middleware);
4700
+ }
2104
4701
  app.use(transformMiddleware({
2105
4702
  config: configWithPlugins,
2106
4703
  pluginContainer,
2107
4704
  moduleGraph
2108
4705
  }));
2109
- const publicDir = import_node_path10.default.resolve(config.root, "public");
4706
+ const publicDir = import_node_path14.default.resolve(config.root, "public");
2110
4707
  app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
2111
4708
  app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
2112
- const httpServer = import_node_http.default.createServer(app);
2113
- const ws = createWebSocketServer(httpServer);
2114
4709
  const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
2115
- const outDirAbs = import_node_path10.default.resolve(config.root, config.build.outDir);
4710
+ const outDirAbs = import_node_path14.default.resolve(config.root, config.build.outDir);
2116
4711
  const watcher = (0, import_chokidar.watch)(config.root, {
2117
4712
  ignored: (filePath) => {
2118
4713
  if (filePath === config.root) return false;
2119
- if (filePath === outDirAbs || filePath.startsWith(outDirAbs + import_node_path10.default.sep)) return true;
2120
- const rel = import_node_path10.default.relative(config.root, filePath);
2121
- if (!rel || rel.startsWith("..") || import_node_path10.default.isAbsolute(rel)) return false;
2122
- for (const seg of rel.split(import_node_path10.default.sep)) {
4714
+ if (filePath === outDirAbs || filePath.startsWith(outDirAbs + import_node_path14.default.sep)) return true;
4715
+ const rel = import_node_path14.default.relative(config.root, filePath);
4716
+ if (!rel || rel.startsWith("..") || import_node_path14.default.isAbsolute(rel)) return false;
4717
+ for (const seg of rel.split(import_node_path14.default.sep)) {
2123
4718
  if (ignoredSegments.has(seg)) return true;
2124
4719
  }
2125
4720
  return false;
@@ -2128,9 +4723,11 @@ async function createServer(inlineConfig = {}) {
2128
4723
  });
2129
4724
  let server;
2130
4725
  watcher.on("change", (file) => {
4726
+ ssrRunner?.invalidateFile(file);
2131
4727
  handleFileChange(file, server);
2132
4728
  });
2133
4729
  watcher.on("add", (file) => {
4730
+ ssrRunner?.invalidateFile(file);
2134
4731
  handleFileChange(file, server);
2135
4732
  });
2136
4733
  server = {
@@ -2139,6 +4736,7 @@ async function createServer(inlineConfig = {}) {
2139
4736
  moduleGraph,
2140
4737
  watcher,
2141
4738
  ws,
4739
+ environments,
2142
4740
  async listen(port) {
2143
4741
  const finalPort = port ?? config.server.port;
2144
4742
  const host = config.server.host === true ? "0.0.0.0" : config.server.host;
@@ -2148,23 +4746,27 @@ async function createServer(inlineConfig = {}) {
2148
4746
  const onListening = () => {
2149
4747
  const actualPort = httpServer.address()?.port ?? currentPort;
2150
4748
  config.server.port = actualPort;
2151
- const localUrl = `http://localhost:${actualPort}`;
2152
- const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
2153
- console.log();
2154
- console.log(import_picocolors.default.cyan(" nasti dev server") + import_picocolors.default.dim(` v${"1.7.1"}`));
2155
- console.log();
2156
- console.log(` ${import_picocolors.default.green(">")} Local: ${import_picocolors.default.cyan(localUrl)}`);
2157
- if (networkUrl) {
2158
- console.log(` ${import_picocolors.default.green(">")} Network: ${import_picocolors.default.cyan(networkUrl)}`);
2159
- }
2160
- console.log();
4749
+ const localUrl = `http://localhost:${actualPort}/`;
4750
+ const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}/` : null;
4751
+ logger.clearScreen("info");
4752
+ const readyIn = Math.ceil(performance.now() - startTime);
4753
+ logger.info(
4754
+ `
4755
+ ${import_picocolors8.default.cyan(import_picocolors8.default.bold("NASTI"))} ${import_picocolors8.default.cyan(`v${"2.0.1"}`)} ${import_picocolors8.default.dim("ready in")} ${import_picocolors8.default.bold(readyIn)} ${import_picocolors8.default.dim("ms")}
4756
+ `
4757
+ );
4758
+ printServerUrls(
4759
+ { local: [localUrl], network: networkUrl ? [networkUrl] : [] },
4760
+ logger.info
4761
+ );
4762
+ logger.info("");
2161
4763
  resolve(server);
2162
4764
  };
2163
4765
  httpServer.on("listening", onListening);
2164
4766
  httpServer.on("error", (err) => {
2165
4767
  if (err.code === "EADDRINUSE") {
2166
4768
  currentPort++;
2167
- console.log(import_picocolors.default.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
4769
+ logger.info(import_picocolors8.default.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
2168
4770
  httpServer.listen(currentPort, host);
2169
4771
  } else {
2170
4772
  reject(err);
@@ -2177,8 +4779,13 @@ async function createServer(inlineConfig = {}) {
2177
4779
  const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
2178
4780
  return transformRequest2(url, { config: configWithPlugins, pluginContainer, moduleGraph });
2179
4781
  },
4782
+ async ssrLoadModule(url) {
4783
+ const runner = await getSsrRunner();
4784
+ return runner.import(url);
4785
+ },
2180
4786
  async close() {
2181
4787
  await pluginContainer.buildEnd();
4788
+ await bundledServer?.close();
2182
4789
  watcher.close();
2183
4790
  ws.close();
2184
4791
  httpServer.close();
@@ -2207,28 +4814,25 @@ function getNetworkAddress() {
2207
4814
  }
2208
4815
  return "localhost";
2209
4816
  }
2210
- var import_node_http, import_node_path10, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors;
4817
+ var import_node_http, import_node_path14, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors8;
2211
4818
  var init_server = __esm({
2212
4819
  "src/server/index.ts"() {
2213
4820
  "use strict";
2214
4821
  import_node_http = __toESM(require("http"), 1);
2215
- import_node_path10 = __toESM(require("path"), 1);
4822
+ import_node_path14 = __toESM(require("path"), 1);
2216
4823
  import_node_os = __toESM(require("os"), 1);
2217
4824
  import_connect = __toESM(require("connect"), 1);
2218
4825
  import_sirv = __toESM(require("sirv"), 1);
2219
4826
  import_chokidar = require("chokidar");
2220
- import_picocolors = __toESM(require("picocolors"), 1);
4827
+ import_picocolors8 = __toESM(require("picocolors"), 1);
2221
4828
  init_config();
2222
- init_plugin_container();
2223
- init_module_graph();
4829
+ init_environment();
4830
+ init_hot_channel();
4831
+ init_logger();
2224
4832
  init_ws();
2225
4833
  init_middleware();
2226
4834
  init_hmr();
2227
- init_resolve();
2228
- init_css();
2229
- init_assets();
2230
- init_vue();
2231
- init_html();
4835
+ init_builtins();
2232
4836
  }
2233
4837
  });
2234
4838
 
@@ -2236,7 +4840,7 @@ var init_server = __esm({
2236
4840
  function electronPlugin(config) {
2237
4841
  const external = /* @__PURE__ */ new Set([
2238
4842
  ...ELECTRON_MODULES,
2239
- ...NODE_BUILTINS,
4843
+ ...NODE_BUILTINS3,
2240
4844
  ...config.electron.external ?? []
2241
4845
  ]);
2242
4846
  return {
@@ -2253,14 +4857,14 @@ function electronPlugin(config) {
2253
4857
  }
2254
4858
  };
2255
4859
  }
2256
- var import_node_module4, NODE_BUILTINS, ELECTRON_MODULES;
4860
+ var import_node_module6, NODE_BUILTINS3, ELECTRON_MODULES;
2257
4861
  var init_electron = __esm({
2258
4862
  "src/plugins/electron.ts"() {
2259
4863
  "use strict";
2260
- import_node_module4 = require("module");
2261
- NODE_BUILTINS = /* @__PURE__ */ new Set([
2262
- ...import_node_module4.builtinModules,
2263
- ...import_node_module4.builtinModules.map((m) => `node:${m}`)
4864
+ import_node_module6 = require("module");
4865
+ NODE_BUILTINS3 = /* @__PURE__ */ new Set([
4866
+ ...import_node_module6.builtinModules,
4867
+ ...import_node_module6.builtinModules.map((m) => `node:${m}`)
2264
4868
  ]);
2265
4869
  ELECTRON_MODULES = /* @__PURE__ */ new Set([
2266
4870
  "electron",
@@ -2271,180 +4875,6 @@ var init_electron = __esm({
2271
4875
  }
2272
4876
  });
2273
4877
 
2274
- // src/build/index.ts
2275
- var build_exports = {};
2276
- __export(build_exports, {
2277
- build: () => build
2278
- });
2279
- async function build(inlineConfig = {}) {
2280
- const config = await resolveConfig(inlineConfig, "build");
2281
- const startTime = performance.now();
2282
- console.log(import_picocolors2.default.cyan("\n\u{1F528} nasti build") + import_picocolors2.default.dim(` v${"1.7.1"}`));
2283
- console.log(import_picocolors2.default.dim(` root: ${config.root}`));
2284
- console.log(import_picocolors2.default.dim(` mode: ${config.mode}`));
2285
- const outDir = import_node_path11.default.resolve(config.root, config.build.outDir);
2286
- if (config.build.emptyOutDir && import_node_fs8.default.existsSync(outDir)) {
2287
- import_node_fs8.default.rmSync(outDir, { recursive: true, force: true });
2288
- }
2289
- import_node_fs8.default.mkdirSync(outDir, { recursive: true });
2290
- const html = await readHtmlFile(config.root);
2291
- let entryPoints = [];
2292
- if (html) {
2293
- const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
2294
- for (const match of scriptMatches) {
2295
- const src = match[1];
2296
- if (src && !src.startsWith("http")) {
2297
- entryPoints.push(import_node_path11.default.resolve(config.root, src.replace(/^\//, "")));
2298
- }
2299
- }
2300
- }
2301
- if (entryPoints.length === 0) {
2302
- const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
2303
- for (const entry of fallbackEntries) {
2304
- const fullPath = import_node_path11.default.resolve(config.root, entry);
2305
- if (import_node_fs8.default.existsSync(fullPath)) {
2306
- entryPoints.push(fullPath);
2307
- break;
2308
- }
2309
- }
2310
- }
2311
- if (entryPoints.length === 0) {
2312
- throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
2313
- }
2314
- const builtinPlugins = [
2315
- ...config.framework === "vue" ? [vuePlugin(config)] : [],
2316
- resolvePlugin(config),
2317
- cssPlugin(config),
2318
- assetsPlugin(config)
2319
- ];
2320
- const allPlugins = [...builtinPlugins, ...config.plugins];
2321
- const pluginContainer = new PluginContainer(config);
2322
- await pluginContainer.buildStart();
2323
- const oxcTransformPlugin = {
2324
- name: "nasti:oxc-transform",
2325
- transform(code, id) {
2326
- if (!shouldTransform(id)) return null;
2327
- const result = transformCode(id, code, {
2328
- sourcemap: !!config.build.sourcemap,
2329
- jsxRuntime: "automatic",
2330
- jsxImportSource: config.framework === "vue" ? "vue" : "react"
2331
- });
2332
- return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2333
- }
2334
- };
2335
- const env = loadEnv(config.mode, config.root, config.envPrefix);
2336
- const envDefine = buildEnvDefine(env, config.mode);
2337
- const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2338
- const vueDefine = config.framework === "vue" ? {
2339
- __VUE_OPTIONS_API__: "true",
2340
- __VUE_PROD_DEVTOOLS__: "false",
2341
- __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false"
2342
- } : {};
2343
- const mergedDefine = { ...vueDefine, ...userTransform?.define ?? {}, ...envDefine };
2344
- const bundle = await (0, import_rolldown.rolldown)({
2345
- ...restInputOptions,
2346
- input: entryPoints,
2347
- transform: { ...userTransform, define: mergedDefine },
2348
- plugins: [
2349
- oxcTransformPlugin,
2350
- // 转换 Nasti 插件为 Rolldown 插件格式
2351
- ...allPlugins.map((p) => ({
2352
- name: p.name,
2353
- resolveId: p.resolveId,
2354
- load: p.load,
2355
- transform: p.transform,
2356
- buildStart: p.buildStart,
2357
- buildEnd: p.buildEnd,
2358
- // Forward `closeBundle` to Rolldown — it invokes the hook during
2359
- // `bundle.close()` below. This is the hook Vite plugins (e.g. PWA
2360
- // manifest/SW writers) rely on for final-stage artifact emission.
2361
- closeBundle: p.closeBundle
2362
- }))
2363
- ]
2364
- });
2365
- const { output } = await bundle.write({
2366
- format: "esm",
2367
- sourcemap: !!config.build.sourcemap,
2368
- minify: !!config.build.minify,
2369
- entryFileNames: "assets/[name].[hash].js",
2370
- chunkFileNames: "assets/[name].[hash].js",
2371
- assetFileNames: "assets/[name].[hash][extname]",
2372
- // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
2373
- ...userOutput,
2374
- // dir 始终由 Nasti 掌管 —— 下方 HTML 改写依赖固定的产物目录,故放在最后强制生效
2375
- dir: outDir
2376
- });
2377
- await bundle.close();
2378
- await pluginContainer.buildEnd();
2379
- for (const ef of pluginContainer.getEmittedFiles()) {
2380
- const dest = import_node_path11.default.resolve(outDir, ef.fileName);
2381
- import_node_fs8.default.mkdirSync(import_node_path11.default.dirname(dest), { recursive: true });
2382
- import_node_fs8.default.writeFileSync(dest, ef.source);
2383
- }
2384
- if (html) {
2385
- let processedHtml = html;
2386
- const htmlPlugin_ = htmlPlugin(config);
2387
- if (htmlPlugin_.transformIndexHtml) {
2388
- const result = await htmlPlugin_.transformIndexHtml(processedHtml);
2389
- if (typeof result === "string") {
2390
- processedHtml = result;
2391
- } else if (result && "html" in result) {
2392
- processedHtml = processHtml(result.html, result.tags);
2393
- } else if (Array.isArray(result)) {
2394
- processedHtml = processHtml(processedHtml, result);
2395
- }
2396
- }
2397
- for (const chunk of output) {
2398
- if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
2399
- const originalEntry = import_node_path11.default.relative(config.root, chunk.facadeModuleId);
2400
- processedHtml = processedHtml.replace(
2401
- new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
2402
- `$1${config.base}${chunk.fileName}$3`
2403
- );
2404
- }
2405
- }
2406
- import_node_fs8.default.writeFileSync(import_node_path11.default.resolve(outDir, "index.html"), processedHtml);
2407
- }
2408
- const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
2409
- const totalSize = output.reduce((sum, chunk) => {
2410
- if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
2411
- return sum;
2412
- }, 0);
2413
- console.log(import_picocolors2.default.green(`
2414
- \u2713 Built in ${elapsed}s`));
2415
- console.log(import_picocolors2.default.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
2416
- console.log(import_picocolors2.default.dim(` output: ${config.build.outDir}/
2417
- `));
2418
- return { output };
2419
- }
2420
- function formatSize(bytes) {
2421
- if (bytes < 1024) return `${bytes} B`;
2422
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;
2423
- return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
2424
- }
2425
- function escapeRegExp(string) {
2426
- return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2427
- }
2428
- var import_node_path11, import_node_fs8, import_rolldown, import_picocolors2;
2429
- var init_build = __esm({
2430
- "src/build/index.ts"() {
2431
- "use strict";
2432
- import_node_path11 = __toESM(require("path"), 1);
2433
- import_node_fs8 = __toESM(require("fs"), 1);
2434
- import_rolldown = require("rolldown");
2435
- init_config();
2436
- init_resolve();
2437
- init_css();
2438
- init_assets();
2439
- init_vue();
2440
- init_html();
2441
- init_transformer();
2442
- init_env();
2443
- init_plugin_container();
2444
- import_picocolors2 = __toESM(require("picocolors"), 1);
2445
- }
2446
- });
2447
-
2448
4878
  // src/build/electron.ts
2449
4879
  var electron_exports = {};
2450
4880
  __export(electron_exports, {
@@ -2456,16 +4886,16 @@ async function buildElectron(inlineConfig = {}) {
2456
4886
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
2457
4887
  const startTime = performance.now();
2458
4888
  assertElectronVersion(config);
2459
- console.log(import_picocolors3.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors3.default.dim(` v${"1.7.1"}`));
2460
- console.log(import_picocolors3.default.dim(` root: ${config.root}`));
2461
- console.log(import_picocolors3.default.dim(` mode: ${config.mode}`));
2462
- console.log(import_picocolors3.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
2463
- const outDir = import_node_path12.default.resolve(config.root, config.build.outDir);
2464
- if (config.build.emptyOutDir && import_node_fs9.default.existsSync(outDir)) {
2465
- import_node_fs9.default.rmSync(outDir, { recursive: true, force: true });
4889
+ console.log(import_picocolors9.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors9.default.dim(` v${"2.0.1"}`));
4890
+ console.log(import_picocolors9.default.dim(` root: ${config.root}`));
4891
+ console.log(import_picocolors9.default.dim(` mode: ${config.mode}`));
4892
+ console.log(import_picocolors9.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
4893
+ const outDir = import_node_path15.default.resolve(config.root, config.build.outDir);
4894
+ if (config.build.emptyOutDir && import_node_fs10.default.existsSync(outDir)) {
4895
+ import_node_fs10.default.rmSync(outDir, { recursive: true, force: true });
2466
4896
  }
2467
- import_node_fs9.default.mkdirSync(outDir, { recursive: true });
2468
- const rendererOutDir = import_node_path12.default.join(outDir, "renderer");
4897
+ import_node_fs10.default.mkdirSync(outDir, { recursive: true });
4898
+ const rendererOutDir = import_node_path15.default.join(outDir, "renderer");
2469
4899
  const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
2470
4900
  await build2({
2471
4901
  ...inlineConfig,
@@ -2476,8 +4906,8 @@ async function buildElectron(inlineConfig = {}) {
2476
4906
  emptyOutDir: false
2477
4907
  }
2478
4908
  });
2479
- const mainEntry = import_node_path12.default.resolve(config.root, config.electron.main);
2480
- if (!import_node_fs9.default.existsSync(mainEntry)) {
4909
+ const mainEntry = import_node_path15.default.resolve(config.root, config.electron.main);
4910
+ if (!import_node_fs10.default.existsSync(mainEntry)) {
2481
4911
  throw new Error(
2482
4912
  `Electron main entry not found: ${config.electron.main}
2483
4913
  \u5728 nasti.config.ts \u7684 electron.main \u6307\u5B9A\u4E3B\u8FDB\u7A0B\u5165\u53E3\u6587\u4EF6\u3002`
@@ -2491,11 +4921,11 @@ async function buildElectron(inlineConfig = {}) {
2491
4921
  const preloadEntries = normalizePreload(config.electron.preload, config.root);
2492
4922
  const preloadFiles = [];
2493
4923
  for (const entry of preloadEntries) {
2494
- if (!import_node_fs9.default.existsSync(entry)) {
2495
- console.warn(import_picocolors3.default.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
4924
+ if (!import_node_fs10.default.existsSync(entry)) {
4925
+ console.warn(import_picocolors9.default.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
2496
4926
  continue;
2497
4927
  }
2498
- const base = import_node_path12.default.basename(entry).replace(/\.[^.]+$/, "");
4928
+ const base = import_node_path15.default.basename(entry).replace(/\.[^.]+$/, "");
2499
4929
  const out = outFileName(outDir, base, config.electron.preloadFormat);
2500
4930
  await bundleNode(config, entry, {
2501
4931
  outFile: out,
@@ -2505,12 +4935,12 @@ async function buildElectron(inlineConfig = {}) {
2505
4935
  preloadFiles.push(out);
2506
4936
  }
2507
4937
  const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
2508
- console.log(import_picocolors3.default.green(`
4938
+ console.log(import_picocolors9.default.green(`
2509
4939
  \u2713 Electron build complete in ${elapsed}s`));
2510
- console.log(import_picocolors3.default.dim(` renderer: ${import_node_path12.default.relative(config.root, rendererOutDir)}/`));
2511
- console.log(import_picocolors3.default.dim(` main: ${import_node_path12.default.relative(config.root, mainFile)}`));
4940
+ console.log(import_picocolors9.default.dim(` renderer: ${import_node_path15.default.relative(config.root, rendererOutDir)}/`));
4941
+ console.log(import_picocolors9.default.dim(` main: ${import_node_path15.default.relative(config.root, mainFile)}`));
2512
4942
  for (const pf of preloadFiles) {
2513
- console.log(import_picocolors3.default.dim(` preload: ${import_node_path12.default.relative(config.root, pf)}`));
4943
+ console.log(import_picocolors9.default.dim(` preload: ${import_node_path15.default.relative(config.root, pf)}`));
2514
4944
  }
2515
4945
  console.log();
2516
4946
  return { rendererOutDir, mainFile, preloadFiles };
@@ -2536,15 +4966,15 @@ async function bundleNode(config, entry, opts) {
2536
4966
  };
2537
4967
  const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2538
4968
  const mergedDefine = { ...userTransform?.define ?? {}, ...envDefine };
2539
- const bundle = await (0, import_rolldown2.rolldown)({
4969
+ const bundle2 = await (0, import_rolldown2.rolldown)({
2540
4970
  ...restInputOptions,
2541
4971
  input: entry,
2542
4972
  platform: "node",
2543
4973
  transform: { ...userTransform, define: mergedDefine },
2544
4974
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2545
4975
  });
2546
- import_node_fs9.default.mkdirSync(import_node_path12.default.dirname(opts.outFile), { recursive: true });
2547
- await bundle.write({
4976
+ import_node_fs10.default.mkdirSync(import_node_path15.default.dirname(opts.outFile), { recursive: true });
4977
+ await bundle2.write({
2548
4978
  sourcemap: !!config.build.sourcemap,
2549
4979
  minify: !!config.build.minify,
2550
4980
  // 允许用户微调 output;但主进程 / preload 的单文件约束由下方键强制保证
@@ -2553,24 +4983,24 @@ async function bundleNode(config, entry, opts) {
2553
4983
  format: opts.format === "cjs" ? "cjs" : "esm",
2554
4984
  codeSplitting: false
2555
4985
  });
2556
- await bundle.close();
2557
- console.log(import_picocolors3.default.dim(` \u2713 ${opts.label} \u2192 ${import_node_path12.default.relative(config.root, opts.outFile)}`));
4986
+ await bundle2.close();
4987
+ console.log(import_picocolors9.default.dim(` \u2713 ${opts.label} \u2192 ${import_node_path15.default.relative(config.root, opts.outFile)}`));
2558
4988
  return opts.outFile;
2559
4989
  }
2560
4990
  function outFileName(outDir, base, format) {
2561
4991
  const ext = format === "cjs" ? ".cjs" : ".mjs";
2562
- return import_node_path12.default.join(outDir, base + ext);
4992
+ return import_node_path15.default.join(outDir, base + ext);
2563
4993
  }
2564
4994
  function normalizePreload(preload, root) {
2565
4995
  const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
2566
- return list.map((p) => import_node_path12.default.resolve(root, p));
4996
+ return list.map((p) => import_node_path15.default.resolve(root, p));
2567
4997
  }
2568
4998
  function assertElectronVersion(config) {
2569
4999
  const min = config.electron.minVersion;
2570
5000
  const installed = detectInstalledElectron(config.root);
2571
5001
  if (installed && installed < min) {
2572
5002
  console.warn(
2573
- import_picocolors3.default.yellow(
5003
+ import_picocolors9.default.yellow(
2574
5004
  ` \u26A0 \u68C0\u6D4B\u5230 Electron ${installed}\uFF0CNasti \u8981\u6C42 \u2265 ${min}\u3002\u65E7\u7248\u672C\u53EF\u80FD\u7F3A\u5C11 ESM \u4E3B\u8FDB\u7A0B\u652F\u6301\u3002`
2575
5005
  )
2576
5006
  );
@@ -2578,23 +5008,23 @@ function assertElectronVersion(config) {
2578
5008
  }
2579
5009
  function detectInstalledElectron(root) {
2580
5010
  try {
2581
- const pkgPath = import_node_path12.default.resolve(root, "node_modules/electron/package.json");
2582
- if (!import_node_fs9.default.existsSync(pkgPath)) return null;
2583
- const pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgPath, "utf-8"));
5011
+ const pkgPath = import_node_path15.default.resolve(root, "node_modules/electron/package.json");
5012
+ if (!import_node_fs10.default.existsSync(pkgPath)) return null;
5013
+ const pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgPath, "utf-8"));
2584
5014
  const major = parseInt(String(pkg.version).split(".")[0], 10);
2585
5015
  return Number.isFinite(major) ? major : null;
2586
5016
  } catch {
2587
5017
  return null;
2588
5018
  }
2589
5019
  }
2590
- var import_node_path12, import_node_fs9, import_rolldown2, import_picocolors3;
5020
+ var import_node_path15, import_node_fs10, import_rolldown2, import_picocolors9;
2591
5021
  var init_electron2 = __esm({
2592
5022
  "src/build/electron.ts"() {
2593
5023
  "use strict";
2594
- import_node_path12 = __toESM(require("path"), 1);
2595
- import_node_fs9 = __toESM(require("fs"), 1);
5024
+ import_node_path15 = __toESM(require("path"), 1);
5025
+ import_node_fs10 = __toESM(require("fs"), 1);
2596
5026
  import_rolldown2 = require("rolldown");
2597
- import_picocolors3 = __toESM(require("picocolors"), 1);
5027
+ import_picocolors9 = __toESM(require("picocolors"), 1);
2598
5028
  init_config();
2599
5029
  init_resolve();
2600
5030
  init_electron();
@@ -2612,17 +5042,17 @@ async function startElectronDev(inlineConfig = {}) {
2612
5042
  const { noSpawn, ...rest } = inlineConfig;
2613
5043
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
2614
5044
  warnElectronVersion(config);
2615
- console.log(import_picocolors4.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors4.default.dim(` v${"1.7.1"}`));
5045
+ console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.0.1"}`));
2616
5046
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2617
5047
  const server = await createServer2({ ...rest, target: "electron" });
2618
5048
  await server.listen();
2619
5049
  const devUrl = `http://localhost:${server.config.server.port}/`;
2620
- console.log(import_picocolors4.default.dim(` renderer: ${devUrl}`));
2621
- const stageDir = import_node_path13.default.resolve(config.root, ".nasti");
2622
- import_node_fs10.default.mkdirSync(stageDir, { recursive: true });
2623
- const mainEntry = import_node_path13.default.resolve(config.root, config.electron.main);
5050
+ console.log(import_picocolors10.default.dim(` renderer: ${devUrl}`));
5051
+ const stageDir = import_node_path16.default.resolve(config.root, ".nasti");
5052
+ import_node_fs11.default.mkdirSync(stageDir, { recursive: true });
5053
+ const mainEntry = import_node_path16.default.resolve(config.root, config.electron.main);
2624
5054
  const preloadEntries = normalizePreload(config.electron.preload, config.root);
2625
- const builtMainFile = import_node_path13.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
5055
+ const builtMainFile = import_node_path16.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
2626
5056
  const builtPreloadFiles = [];
2627
5057
  const compileAll = async () => {
2628
5058
  await compileNode(config, mainEntry, {
@@ -2632,9 +5062,9 @@ async function startElectronDev(inlineConfig = {}) {
2632
5062
  });
2633
5063
  builtPreloadFiles.length = 0;
2634
5064
  for (const entry of preloadEntries) {
2635
- if (!import_node_fs10.default.existsSync(entry)) continue;
2636
- const base = import_node_path13.default.basename(entry).replace(/\.[^.]+$/, "");
2637
- const out = import_node_path13.default.join(stageDir, base + extFor(config.electron.preloadFormat));
5065
+ if (!import_node_fs11.default.existsSync(entry)) continue;
5066
+ const base = import_node_path16.default.basename(entry).replace(/\.[^.]+$/, "");
5067
+ const out = import_node_path16.default.join(stageDir, base + extFor(config.electron.preloadFormat));
2638
5068
  await compileNode(config, entry, {
2639
5069
  outFile: out,
2640
5070
  format: config.electron.preloadFormat,
@@ -2645,13 +5075,13 @@ async function startElectronDev(inlineConfig = {}) {
2645
5075
  };
2646
5076
  await compileAll();
2647
5077
  if (noSpawn) {
2648
- console.log(import_picocolors4.default.dim(" (noSpawn) \u5DF2\u7F16\u8BD1\u4E3B/preload\uFF0C\u8DF3\u8FC7\u542F\u52A8 Electron\u3002"));
5078
+ console.log(import_picocolors10.default.dim(" (noSpawn) \u5DF2\u7F16\u8BD1\u4E3B/preload\uFF0C\u8DF3\u8FC7\u542F\u52A8 Electron\u3002"));
2649
5079
  return;
2650
5080
  }
2651
5081
  const electronBin = resolveElectronBinary(config);
2652
5082
  if (!electronBin) {
2653
5083
  console.warn(
2654
- import_picocolors4.default.yellow(
5084
+ import_picocolors10.default.yellow(
2655
5085
  " \u26A0 \u672A\u627E\u5230 Electron \u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u8BF7\u5148\u5B89\u88C5\uFF1Anpm install -D electron\n \u5DF2\u7F16\u8BD1\u4E3B/preload \u81F3 .nasti/\uFF0C\u53EF\u624B\u52A8\u8FD0\u884C\u3002"
2656
5086
  )
2657
5087
  );
@@ -2666,14 +5096,14 @@ async function startElectronDev(inlineConfig = {}) {
2666
5096
  });
2667
5097
  child.on("exit", (code) => {
2668
5098
  if (code !== null && child && child.__nastiKilled !== true) {
2669
- console.log(import_picocolors4.default.dim(` Electron exited (${code}).`));
5099
+ console.log(import_picocolors10.default.dim(` Electron exited (${code}).`));
2670
5100
  process.exit(code ?? 0);
2671
5101
  }
2672
5102
  });
2673
5103
  };
2674
5104
  spawnElectron();
2675
5105
  if (config.electron.autoRestart) {
2676
- const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs10.default.existsSync);
5106
+ const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs11.default.existsSync);
2677
5107
  const watcher = import_chokidar2.default.watch(watchTargets, { ignoreInitial: true });
2678
5108
  let restarting = null;
2679
5109
  let pending = false;
@@ -2685,7 +5115,7 @@ async function startElectronDev(inlineConfig = {}) {
2685
5115
  restarting = (async () => {
2686
5116
  do {
2687
5117
  pending = false;
2688
- console.log(import_picocolors4.default.cyan("\n \u267B \u4E3B/preload \u53D8\u66F4\uFF0C\u91CD\u542F Electron..."));
5118
+ console.log(import_picocolors10.default.cyan("\n \u267B \u4E3B/preload \u53D8\u66F4\uFF0C\u91CD\u542F Electron..."));
2689
5119
  if (child && !child.killed) {
2690
5120
  ;
2691
5121
  child.__nastiKilled = true;
@@ -2703,7 +5133,7 @@ async function startElectronDev(inlineConfig = {}) {
2703
5133
  await compileAll();
2704
5134
  spawnElectron();
2705
5135
  } catch (e) {
2706
- console.warn(import_picocolors4.default.yellow(` \u26A0 \u91CD\u542F\u7F16\u8BD1\u5931\u8D25\uFF0C\u4FDD\u7559\u4E0A\u4E00\u6B21\u8FDB\u7A0B: ${e.message}`));
5136
+ console.warn(import_picocolors10.default.yellow(` \u26A0 \u91CD\u542F\u7F16\u8BD1\u5931\u8D25\uFF0C\u4FDD\u7559\u4E0A\u4E00\u6B21\u8FDB\u7A0B: ${e.message}`));
2707
5137
  }
2708
5138
  } while (pending);
2709
5139
  restarting = null;
@@ -2743,14 +5173,14 @@ async function compileNode(config, entry, opts) {
2743
5173
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2744
5174
  }
2745
5175
  };
2746
- const bundle = await (0, import_rolldown3.rolldown)({
5176
+ const bundle2 = await (0, import_rolldown3.rolldown)({
2747
5177
  input: entry,
2748
5178
  transform: { define: envDefine },
2749
5179
  platform: "node",
2750
5180
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2751
5181
  });
2752
- import_node_fs10.default.mkdirSync(import_node_path13.default.dirname(opts.outFile), { recursive: true });
2753
- await bundle.write({
5182
+ import_node_fs11.default.mkdirSync(import_node_path16.default.dirname(opts.outFile), { recursive: true });
5183
+ await bundle2.write({
2754
5184
  file: opts.outFile,
2755
5185
  format: opts.format === "cjs" ? "cjs" : "esm",
2756
5186
  sourcemap: false,
@@ -2759,17 +5189,17 @@ async function compileNode(config, entry, opts) {
2759
5189
  // 同样语义(单 chunk、内联 dynamic import)
2760
5190
  codeSplitting: false
2761
5191
  });
2762
- await bundle.close();
5192
+ await bundle2.close();
2763
5193
  }
2764
5194
  function resolveElectronBinary(config) {
2765
- if (config.electron.electronPath && import_node_fs10.default.existsSync(config.electron.electronPath)) {
5195
+ if (config.electron.electronPath && import_node_fs11.default.existsSync(config.electron.electronPath)) {
2766
5196
  return config.electron.electronPath;
2767
5197
  }
2768
5198
  try {
2769
- const require2 = (0, import_node_module5.createRequire)(import_node_path13.default.resolve(config.root, "package.json"));
5199
+ const require2 = (0, import_node_module7.createRequire)(import_node_path16.default.resolve(config.root, "package.json"));
2770
5200
  const pathFile = require2.resolve("electron");
2771
5201
  const electronModule = require2(pathFile);
2772
- if (typeof electronModule === "string" && import_node_fs10.default.existsSync(electronModule)) {
5202
+ if (typeof electronModule === "string" && import_node_fs11.default.existsSync(electronModule)) {
2773
5203
  return electronModule;
2774
5204
  }
2775
5205
  } catch {
@@ -2780,7 +5210,7 @@ function warnElectronVersion(config) {
2780
5210
  const installed = detectInstalledElectron(config.root);
2781
5211
  if (installed === null) {
2782
5212
  console.warn(
2783
- import_picocolors4.default.yellow(
5213
+ import_picocolors10.default.yellow(
2784
5214
  ` \u26A0 \u672A\u68C0\u6D4B\u5230 Electron\uFF0C\u8BF7\u5B89\u88C5\uFF1Anpm install -D electron@^${config.electron.minVersion}`
2785
5215
  )
2786
5216
  );
@@ -2788,22 +5218,22 @@ function warnElectronVersion(config) {
2788
5218
  }
2789
5219
  if (installed < config.electron.minVersion) {
2790
5220
  console.warn(
2791
- import_picocolors4.default.yellow(
5221
+ import_picocolors10.default.yellow(
2792
5222
  ` \u26A0 Electron ${installed} \u4F4E\u4E8E Nasti \u8981\u6C42\u7684 ${config.electron.minVersion}\uFF0C\u67D0\u4E9B\u7279\u6027\uFF08\u5982 ESM \u4E3B\u8FDB\u7A0B\uFF09\u4E0D\u53EF\u7528\u3002`
2793
5223
  )
2794
5224
  );
2795
5225
  }
2796
5226
  }
2797
- var import_node_path13, import_node_fs10, import_node_module5, import_node_child_process, import_chokidar2, import_picocolors4, import_rolldown3;
5227
+ var import_node_path16, import_node_fs11, import_node_module7, import_node_child_process, import_chokidar2, import_picocolors10, import_rolldown3;
2798
5228
  var init_electron_dev = __esm({
2799
5229
  "src/server/electron-dev.ts"() {
2800
5230
  "use strict";
2801
- import_node_path13 = __toESM(require("path"), 1);
2802
- import_node_fs10 = __toESM(require("fs"), 1);
2803
- import_node_module5 = require("module");
5231
+ import_node_path16 = __toESM(require("path"), 1);
5232
+ import_node_fs11 = __toESM(require("fs"), 1);
5233
+ import_node_module7 = require("module");
2804
5234
  import_node_child_process = require("child_process");
2805
5235
  import_chokidar2 = __toESM(require("chokidar"), 1);
2806
- import_picocolors4 = __toESM(require("picocolors"), 1);
5236
+ import_picocolors10 = __toESM(require("picocolors"), 1);
2807
5237
  init_config();
2808
5238
  import_rolldown3 = require("rolldown");
2809
5239
  init_electron();
@@ -2816,14 +5246,47 @@ var init_electron_dev = __esm({
2816
5246
 
2817
5247
  // src/cli.ts
2818
5248
  var import_cac = require("cac");
2819
- var import_picocolors5 = __toESM(require("picocolors"), 1);
5249
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
5250
+ init_logger();
2820
5251
  var cli = (0, import_cac.cac)("nasti");
2821
- cli.command("[root]", "Start dev server").alias("dev").option("--port <port>", "Port number", { default: 3e3 }).option("--host [host]", "Hostname").option("--open [path]", "Open browser on startup").option("--mode <mode>", "Set env mode").action(async (root, options) => {
5252
+ function setupDebug(options) {
5253
+ if (options.debug || options.verbose) {
5254
+ const namespaces = typeof options.debug === "string" ? options.debug.split(",").map((s) => s.includes(":") ? s : `nasti:${s}`).join(",") : "nasti:*";
5255
+ process.env.DEBUG = process.env.DEBUG ? `${process.env.DEBUG},${namespaces}` : namespaces;
5256
+ }
5257
+ if (options.filter) {
5258
+ process.env.NASTI_DEBUG_FILTER = options.filter;
5259
+ }
5260
+ }
5261
+ function createCliLogger(options) {
5262
+ return createLogger(options.logLevel ?? "info", {
5263
+ allowClearScreen: options.clearScreen !== false
5264
+ });
5265
+ }
5266
+ function logCliError(logger, prefix, err) {
5267
+ const error = err instanceof Error ? err : new Error(typeof err === "string" ? err : String(err));
5268
+ if (!logger.hasErrorLogged(error)) {
5269
+ logger.error(import_picocolors11.default.red(`
5270
+ ${prefix}:
5271
+ ${error.message}
5272
+ `), { error });
5273
+ if (error.stack) logger.error(import_picocolors11.default.dim(error.stack));
5274
+ }
5275
+ process.exit(1);
5276
+ }
5277
+ cli.option("--logLevel <level>", "Log level: info | warn | error | silent").option("--clearScreen", "Allow/disable clear screen when logging", { default: true }).option("-d, --debug [namespaces]", "Show debug logs (e.g. -d build,hmr)").option("-f, --filter <filter>", "Filter debug logs by content").option("--verbose", "Shorthand for --debug (all nasti:* namespaces)");
5278
+ cli.command("[root]", "Start dev server").alias("dev").option("--port <port>", "Port number", { default: 3e3 }).option("--host [host]", "Hostname").option("--open [path]", "Open browser on startup").option("--mode <mode>", "Set env mode").option("--bundle", "Experimental: serve a full in-memory bundle via the Rolldown dev engine").action(async (root, options) => {
5279
+ setupDebug(options);
5280
+ const logger = createCliLogger(options);
2822
5281
  try {
2823
5282
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2824
5283
  const server = await createServer2({
2825
5284
  root: root ?? ".",
2826
5285
  mode: options.mode ?? "development",
5286
+ logLevel: options.logLevel,
5287
+ clearScreen: options.clearScreen,
5288
+ customLogger: logger,
5289
+ ...options.bundle ? { experimental: { bundledDev: true } } : {},
2827
5290
  server: {
2828
5291
  port: options.port,
2829
5292
  host: options.host,
@@ -2832,15 +5295,12 @@ cli.command("[root]", "Start dev server").alias("dev").option("--port <port>", "
2832
5295
  });
2833
5296
  await server.listen();
2834
5297
  } catch (err) {
2835
- console.error(import_picocolors5.default.red(`
2836
- Error starting dev server:
2837
- ${err.message}
2838
- `));
2839
- if (err.stack) console.error(import_picocolors5.default.dim(err.stack));
2840
- process.exit(1);
5298
+ logCliError(logger, "Error starting dev server", err);
2841
5299
  }
2842
5300
  });
2843
5301
  cli.command("build [root]", "Build for production").option("--outDir <dir>", "Output directory", { default: "dist" }).option("--sourcemap", "Generate source map").option("--minify", "Minify output", { default: true }).option("--mode <mode>", "Set env mode").option("--target <target>", "Build target: web | electron", { default: "web" }).action(async (root, options) => {
5302
+ setupDebug(options);
5303
+ const logger = createCliLogger(options);
2844
5304
  try {
2845
5305
  const target = options.target;
2846
5306
  if (target !== "web" && target !== "electron") {
@@ -2850,6 +5310,9 @@ cli.command("build [root]", "Build for production").option("--outDir <dir>", "Ou
2850
5310
  root: root ?? ".",
2851
5311
  mode: options.mode ?? "production",
2852
5312
  target,
5313
+ logLevel: options.logLevel,
5314
+ clearScreen: options.clearScreen,
5315
+ customLogger: logger,
2853
5316
  build: {
2854
5317
  outDir: options.outDir,
2855
5318
  sourcemap: options.sourcemap,
@@ -2864,21 +5327,21 @@ cli.command("build [root]", "Build for production").option("--outDir <dir>", "Ou
2864
5327
  await build2(inline);
2865
5328
  }
2866
5329
  } catch (err) {
2867
- console.error(import_picocolors5.default.red(`
2868
- Build failed:
2869
- ${err.message}
2870
- `));
2871
- if (err.stack) console.error(import_picocolors5.default.dim(err.stack));
2872
- process.exit(1);
5330
+ logCliError(logger, "Build failed", err);
2873
5331
  }
2874
5332
  });
2875
5333
  cli.command("electron [root]", "Start Electron dev mode (requires electron ^41)").alias("electron-dev").option("--port <port>", "Renderer dev server port", { default: 3e3 }).option("--host [host]", "Hostname").option("--mode <mode>", "Set env mode").option("--no-spawn", "Compile main/preload but do not spawn Electron").option("--no-restart", "Disable auto-restart on main/preload changes").action(async (root, options) => {
5334
+ setupDebug(options);
5335
+ const logger = createCliLogger(options);
2876
5336
  try {
2877
5337
  const { startElectronDev: startElectronDev2 } = await Promise.resolve().then(() => (init_electron_dev(), electron_dev_exports));
2878
5338
  await startElectronDev2({
2879
5339
  root: root ?? ".",
2880
5340
  mode: options.mode ?? "development",
2881
5341
  target: "electron",
5342
+ logLevel: options.logLevel,
5343
+ clearScreen: options.clearScreen,
5344
+ customLogger: logger,
2882
5345
  server: {
2883
5346
  port: options.port,
2884
5347
  host: options.host
@@ -2889,21 +5352,21 @@ cli.command("electron [root]", "Start Electron dev mode (requires electron ^41)"
2889
5352
  noSpawn: options.spawn === false
2890
5353
  });
2891
5354
  } catch (err) {
2892
- console.error(import_picocolors5.default.red(`
2893
- Electron dev failed:
2894
- ${err.message}
2895
- `));
2896
- if (err.stack) console.error(import_picocolors5.default.dim(err.stack));
2897
- process.exit(1);
5355
+ logCliError(logger, "Electron dev failed", err);
2898
5356
  }
2899
5357
  });
2900
5358
  cli.command("electron-build [root]", "Build Electron app for production").option("--outDir <dir>", "Output directory", { default: "dist" }).option("--sourcemap", "Generate source map").option("--minify", "Minify output", { default: true }).option("--mode <mode>", "Set env mode").action(async (root, options) => {
5359
+ setupDebug(options);
5360
+ const logger = createCliLogger(options);
2901
5361
  try {
2902
5362
  const { buildElectron: buildElectron2 } = await Promise.resolve().then(() => (init_electron2(), electron_exports));
2903
5363
  await buildElectron2({
2904
5364
  root: root ?? ".",
2905
5365
  mode: options.mode ?? "production",
2906
5366
  target: "electron",
5367
+ logLevel: options.logLevel,
5368
+ clearScreen: options.clearScreen,
5369
+ customLogger: logger,
2907
5370
  build: {
2908
5371
  outDir: options.outDir,
2909
5372
  sourcemap: options.sourcemap,
@@ -2911,42 +5374,44 @@ cli.command("electron-build [root]", "Build Electron app for production").option
2911
5374
  }
2912
5375
  });
2913
5376
  } catch (err) {
2914
- console.error(import_picocolors5.default.red(`
2915
- Electron build failed:
2916
- ${err.message}
2917
- `));
2918
- if (err.stack) console.error(import_picocolors5.default.dim(err.stack));
2919
- process.exit(1);
5377
+ logCliError(logger, "Electron build failed", err);
2920
5378
  }
2921
5379
  });
2922
5380
  cli.command("preview [root]", "Preview production build").option("--port <port>", "Port number", { default: 4173 }).option("--host [host]", "Hostname").option("--outDir <dir>", "Output directory to serve", { default: "dist" }).action(async (root, options) => {
5381
+ setupDebug(options);
5382
+ const logger = createCliLogger(options);
2923
5383
  try {
2924
5384
  const http2 = await import("http");
2925
- const path14 = await import("path");
5385
+ const path17 = await import("path");
5386
+ const os2 = await import("os");
2926
5387
  const sirv2 = (await import("sirv")).default;
2927
5388
  const connect2 = (await import("connect")).default;
2928
- const resolvedRoot = path14.resolve(root ?? ".");
2929
- const outDir = path14.resolve(resolvedRoot, options.outDir);
5389
+ const { printServerUrls: printServerUrls2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
5390
+ const resolvedRoot = path17.resolve(root ?? ".");
5391
+ const outDir = path17.resolve(resolvedRoot, options.outDir);
2930
5392
  const app = connect2();
2931
5393
  app.use(sirv2(outDir, { single: true, etag: true, gzip: true, brotli: true }));
2932
5394
  const port = options.port;
2933
5395
  const host = options.host === true ? "0.0.0.0" : options.host ?? "localhost";
2934
5396
  http2.createServer(app).listen(port, host, () => {
2935
- console.log();
2936
- console.log(import_picocolors5.default.cyan(" \u{1F50D} nasti preview"));
2937
- console.log();
2938
- console.log(` ${import_picocolors5.default.green("\u279C")} Local: ${import_picocolors5.default.cyan(`http://localhost:${port}`)}`);
2939
- console.log();
5397
+ logger.info(`
5398
+ ${import_picocolors11.default.cyan(import_picocolors11.default.bold("NASTI"))} ${import_picocolors11.default.cyan(`v${"2.0.1"}`)} ${import_picocolors11.default.dim("preview")}
5399
+ `);
5400
+ printServerUrls2(
5401
+ {
5402
+ local: [`http://localhost:${port}/`],
5403
+ // 0.0.0.0 本身不可访问:枚举真实网卡的非内网 IPv4 地址
5404
+ network: host === "0.0.0.0" ? Object.values(os2.networkInterfaces()).flat().filter((i) => i && i.family === "IPv4" && !i.internal).map((i) => `http://${i.address}:${port}/`) : []
5405
+ },
5406
+ logger.info
5407
+ );
5408
+ logger.info("");
2940
5409
  });
2941
5410
  } catch (err) {
2942
- console.error(import_picocolors5.default.red(`
2943
- Preview failed:
2944
- ${err.message}
2945
- `));
2946
- process.exit(1);
5411
+ logCliError(logger, "Preview failed", err);
2947
5412
  }
2948
5413
  });
2949
5414
  cli.help();
2950
- cli.version("1.7.1");
5415
+ cli.version("2.0.1");
2951
5416
  cli.parse();
2952
5417
  //# sourceMappingURL=cli.cjs.map