@nasti-toolchain/nasti 1.7.1 → 2.0.0

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