@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/index.js CHANGED
@@ -1,15 +1,49 @@
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) => (path18) => {
14
+ var fn = map[path18];
15
+ if (fn) return fn();
16
+ throw new Error("Module not found in bundle: " + path18);
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
+ ));
10
44
 
11
45
  // src/config/defaults.ts
12
- var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaults;
46
+ var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaults;
13
47
  var init_defaults = __esm({
14
48
  "src/config/defaults.ts"() {
15
49
  "use strict";
@@ -36,7 +70,12 @@ var init_defaults = __esm({
36
70
  target: "es2022",
37
71
  rolldownOptions: {},
38
72
  emptyOutDir: true,
39
- css: {}
73
+ css: {},
74
+ reportCompressedSize: true,
75
+ chunkSizeWarningLimit: 500,
76
+ cssCodeSplit: true,
77
+ // 默认跟随 build.minify(resolveConfig 中按 minify 取值填充)
78
+ cssMinify: true
40
79
  };
41
80
  defaultElectron = {
42
81
  main: "src/electron/main.ts",
@@ -51,6 +90,9 @@ var init_defaults = __esm({
51
90
  minVersion: 41,
52
91
  external: ["electron"]
53
92
  };
93
+ defaultExperimental = {
94
+ bundledDev: false
95
+ };
54
96
  defaults = {
55
97
  root: ".",
56
98
  base: "/",
@@ -63,8 +105,123 @@ var init_defaults = __esm({
63
105
  electron: defaultElectron,
64
106
  plugins: [],
65
107
  envPrefix: ["NASTI_", "VITE_"],
66
- logLevel: "info"
108
+ logLevel: "info",
109
+ clearScreen: true,
110
+ experimental: defaultExperimental
111
+ };
112
+ }
113
+ });
114
+
115
+ // src/core/logger.ts
116
+ import readline from "readline";
117
+ import pc from "picocolors";
118
+ function getTimeFormatter() {
119
+ return new Intl.DateTimeFormat(void 0, {
120
+ hour: "numeric",
121
+ minute: "numeric",
122
+ second: "numeric"
123
+ });
124
+ }
125
+ function createLogger(level = "info", options = {}) {
126
+ if (options.customLogger) {
127
+ return options.customLogger;
128
+ }
129
+ const timeFormatter = getTimeFormatter();
130
+ const loggedErrors = /* @__PURE__ */ new WeakSet();
131
+ const { prefix = "[nasti]", allowClearScreen = true, console: console_ = console } = options;
132
+ const thresh = LogLevels[level];
133
+ const canClearScreen = allowClearScreen && process.stdout.isTTY && !process.env.CI;
134
+ const clear = canClearScreen ? clearScreen : () => {
135
+ };
136
+ function format(type, msg, options2 = {}) {
137
+ if (options2.timestamp) {
138
+ const tag = type === "info" ? pc.cyan(pc.bold(prefix)) : type === "warn" ? pc.yellow(pc.bold(prefix)) : pc.red(pc.bold(prefix));
139
+ return `${pc.dim(timeFormatter.format(/* @__PURE__ */ new Date()))} ${tag} ${msg}`;
140
+ }
141
+ return msg;
142
+ }
143
+ function output(type, msg, options2 = {}) {
144
+ if (thresh < LogLevels[type]) return;
145
+ const method = type === "info" ? "log" : type;
146
+ if (options2.error) {
147
+ loggedErrors.add(options2.error);
148
+ }
149
+ if (canClearScreen) {
150
+ if (type === lastType && msg === lastMsg) {
151
+ sameCount++;
152
+ clear();
153
+ console_[method](format(type, msg, options2), pc.yellow(`(x${sameCount + 1})`));
154
+ } else {
155
+ sameCount = 0;
156
+ lastMsg = msg;
157
+ lastType = type;
158
+ if (options2.clear) clear();
159
+ console_[method](format(type, msg, options2));
160
+ }
161
+ } else {
162
+ console_[method](format(type, msg, options2));
163
+ }
164
+ }
165
+ const warnedMessages = /* @__PURE__ */ new Set();
166
+ const logger = {
167
+ hasWarned: false,
168
+ info(msg, opts) {
169
+ output("info", msg, opts);
170
+ },
171
+ warn(msg, opts) {
172
+ logger.hasWarned = true;
173
+ output("warn", msg, opts);
174
+ },
175
+ warnOnce(msg, opts) {
176
+ if (warnedMessages.has(msg)) return;
177
+ logger.hasWarned = true;
178
+ output("warn", msg, opts);
179
+ warnedMessages.add(msg);
180
+ },
181
+ error(msg, opts) {
182
+ output("error", msg, opts);
183
+ },
184
+ clearScreen(type) {
185
+ if (thresh >= LogLevels[type]) clear();
186
+ },
187
+ hasErrorLogged(error) {
188
+ return loggedErrors.has(error);
189
+ }
190
+ };
191
+ return logger;
192
+ }
193
+ function clearScreen() {
194
+ const repeatCount = process.stdout.rows - 2;
195
+ const blank = repeatCount > 0 ? "\n".repeat(repeatCount) : "";
196
+ console.log(blank);
197
+ readline.cursorTo(process.stdout, 0, 0);
198
+ readline.clearScreenDown(process.stdout);
199
+ }
200
+ function printServerUrls(urls, info) {
201
+ const colorUrl = (url) => pc.cyan(url.replace(/:(\d+)\//, (_, port) => `:${pc.bold(port)}/`));
202
+ for (const url of urls.local) {
203
+ info(` ${pc.green("\u279C")} ${pc.bold("Local")}: ${colorUrl(url)}`);
204
+ }
205
+ for (const url of urls.network) {
206
+ info(` ${pc.green("\u279C")} ${pc.bold("Network")}: ${colorUrl(url)}`);
207
+ }
208
+ if (urls.network.length === 0) {
209
+ info(
210
+ pc.dim(` ${pc.green("\u279C")} ${pc.bold("Network")}: use `) + pc.bold("--host") + pc.dim(" to expose")
211
+ );
212
+ }
213
+ }
214
+ var LogLevels, lastType, lastMsg, sameCount;
215
+ var init_logger = __esm({
216
+ "src/core/logger.ts"() {
217
+ "use strict";
218
+ LogLevels = {
219
+ silent: 0,
220
+ error: 1,
221
+ warn: 2,
222
+ info: 3
67
223
  };
224
+ sameCount = 0;
68
225
  }
69
226
  });
70
227
 
@@ -131,17 +288,28 @@ async function resolveConfig(inlineConfig = {}, command) {
131
288
  ...fileConfig.plugins ?? [],
132
289
  ...inlineConfig.plugins ?? []
133
290
  ];
134
- const env = { mode: merged.mode ?? defaults.mode, command };
291
+ const mode = merged.mode ?? (command === "build" ? "production" : "development");
292
+ const env = { mode, command };
135
293
  for (const plugin of rawPlugins) {
136
294
  if (plugin.config) {
137
295
  const result = await plugin.config(merged, env);
138
296
  if (result) Object.assign(merged, result);
139
297
  }
140
298
  }
299
+ const logLevel = merged.logLevel ?? defaults.logLevel;
300
+ const clearScreen2 = merged.clearScreen ?? defaults.clearScreen;
301
+ const logger = createLogger(logLevel, {
302
+ allowClearScreen: clearScreen2,
303
+ customLogger: merged.customLogger
304
+ });
305
+ const mergedBuild = { ...defaults.build, ...merged.build };
306
+ if (merged.build?.cssMinify === void 0) {
307
+ mergedBuild.cssMinify = !!mergedBuild.minify;
308
+ }
141
309
  const resolved = {
142
310
  root,
143
311
  base: merged.base ?? defaults.base,
144
- mode: command === "build" ? "production" : "development",
312
+ mode,
145
313
  target: merged.target ?? defaults.target,
146
314
  framework: merged.framework ?? defaults.framework,
147
315
  command,
@@ -154,11 +322,70 @@ async function resolveConfig(inlineConfig = {}, command) {
154
322
  },
155
323
  plugins: [],
156
324
  server: { ...defaults.server, ...merged.server },
157
- build: { ...defaults.build, ...merged.build },
325
+ build: mergedBuild,
158
326
  electron: { ...defaults.electron, ...merged.electron },
159
327
  envPrefix: Array.isArray(merged.envPrefix) ? merged.envPrefix : merged.envPrefix ? [merged.envPrefix] : [...defaults.envPrefix],
160
- logLevel: merged.logLevel ?? defaults.logLevel
328
+ logLevel,
329
+ clearScreen: clearScreen2,
330
+ logger,
331
+ environments: {},
332
+ experimental: {
333
+ bundledDev: merged.experimental?.bundledDev ?? defaults.experimental.bundledDev
334
+ }
335
+ };
336
+ const userEnvironments = {
337
+ client: {},
338
+ ssr: {},
339
+ ...merged.environments ?? {}
161
340
  };
341
+ for (const [name, envOptions] of Object.entries(userEnvironments)) {
342
+ for (const plugin of rawPlugins) {
343
+ if (plugin.configEnvironment) {
344
+ const result = await plugin.configEnvironment(name, envOptions, env);
345
+ if (result) Object.assign(envOptions, deepMerge(envOptions, result));
346
+ }
347
+ }
348
+ }
349
+ for (const [name, envOptions] of Object.entries(userEnvironments)) {
350
+ const consumer = envOptions.consumer ?? (name === "client" ? "client" : "server");
351
+ if (name === "client") {
352
+ if (envOptions.resolve) {
353
+ Object.assign(resolved.resolve, {
354
+ ...envOptions.resolve,
355
+ alias: { ...resolved.resolve.alias, ...envOptions.resolve.alias }
356
+ });
357
+ }
358
+ if (envOptions.build) Object.assign(resolved.build, envOptions.build);
359
+ resolved.environments.client = {
360
+ consumer,
361
+ entry: [],
362
+ // 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
363
+ resolve: resolved.resolve,
364
+ build: resolved.build
365
+ };
366
+ continue;
367
+ }
368
+ resolved.environments[name] = {
369
+ consumer,
370
+ entry: (Array.isArray(envOptions.entry) ? envOptions.entry : envOptions.entry ? [envOptions.entry] : []).map((e) => path.resolve(root, e)),
371
+ resolve: {
372
+ alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
373
+ extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
374
+ // server consumer:node conditions(去 'browser');client 非默认环境沿用 top-level
375
+ conditions: envOptions.resolve?.conditions ?? (consumer === "server" ? ["node", ...resolved.resolve.conditions.filter((c) => c !== "browser")] : [...resolved.resolve.conditions]),
376
+ mainFields: envOptions.resolve?.mainFields ?? (consumer === "server" ? ["module", "main"] : [...resolved.resolve.mainFields])
377
+ },
378
+ build: {
379
+ ...resolved.build,
380
+ ...envOptions.build,
381
+ // 非 client 环境默认产出到 <outDir>/<envName>(如 dist/ssr),可显式覆盖
382
+ outDir: envOptions.build?.outDir ?? path.join(resolved.build.outDir, name),
383
+ // server 产物默认不压缩(可调试性优先,与 Vite SSR 默认一致),可显式覆盖
384
+ minify: envOptions.build?.minify ?? (consumer === "server" ? false : resolved.build.minify)
385
+ }
386
+ };
387
+ }
388
+ assertClientEnvironmentMirror(resolved);
162
389
  const filteredPlugins = rawPlugins.filter((p) => {
163
390
  if (!p.apply) return true;
164
391
  if (typeof p.apply === "function") return p.apply(resolved, env);
@@ -247,11 +474,40 @@ function hasDotNodeFile(dir, depth = 0) {
247
474
  }
248
475
  return false;
249
476
  }
477
+ function assertClientEnvironmentMirror(config) {
478
+ if (process.env.NASTI_DISABLE_MIRROR_ASSERT) return;
479
+ const client = config.environments.client;
480
+ if (!client) {
481
+ throw new Error("[nasti] internal: environments.client missing after resolveConfig");
482
+ }
483
+ if (client.resolve === config.resolve && client.build === config.build) return;
484
+ const pairs = [
485
+ ["resolve", config.resolve, client.resolve],
486
+ ["build", config.build, client.build]
487
+ ];
488
+ for (const [field, top, env] of pairs) {
489
+ const a = JSON.stringify(top);
490
+ const b = JSON.stringify(env);
491
+ if (a !== b) {
492
+ throw new Error(
493
+ `[nasti] config mirror violation: top-level \`${field}\` and \`environments.client.${field}\` diverged.
494
+ top-level: ${a}
495
+ client: ${b}
496
+ 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`
497
+ );
498
+ }
499
+ }
500
+ }
501
+ function isPlainObject(val) {
502
+ if (val === null || typeof val !== "object") return false;
503
+ const proto = Object.getPrototypeOf(val);
504
+ return proto === Object.prototype || proto === null;
505
+ }
250
506
  function deepMerge(target, source) {
251
507
  const result = { ...target };
252
508
  for (const key of Object.keys(source)) {
253
509
  const val = source[key];
254
- if (val && typeof val === "object" && !Array.isArray(val)) {
510
+ if (isPlainObject(val)) {
255
511
  result[key] = deepMerge(
256
512
  result[key] ?? {},
257
513
  val
@@ -267,6 +523,7 @@ var init_config = __esm({
267
523
  "src/config/index.ts"() {
268
524
  "use strict";
269
525
  init_defaults();
526
+ init_logger();
270
527
  CONFIG_FILES = [
271
528
  "nasti.config.ts",
272
529
  "nasti.config.js",
@@ -381,199 +638,1243 @@ var init_resolve = __esm({
381
638
  }
382
639
  });
383
640
 
384
- // src/plugins/tailwind.ts
385
- import path3 from "path";
386
- import { createRequire as createRequire2 } from "module";
387
- import { pathToFileURL as pathToFileURL2 } from "url";
388
- function hasTailwindDirectives(css) {
389
- const withoutBlockComments = css.replace(/\/\*[\s\S]*?\*\//g, "");
390
- const withoutLineComments = withoutBlockComments.replace(/\/\/.*$/gm, "");
391
- return TAILWIND_DIRECTIVE_RE.test(withoutLineComments);
392
- }
393
- async function loadTailwind(projectRoot) {
394
- if (cached && cachedRoot === projectRoot) return cached;
395
- const req = createRequire2(path3.join(projectRoot, "package.json"));
396
- let nodePath;
397
- let oxidePath;
398
- try {
399
- nodePath = req.resolve("@tailwindcss/node");
400
- oxidePath = req.resolve("@tailwindcss/oxide");
401
- } catch {
402
- throw new Error(
403
- "[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"
404
- );
405
- }
406
- const node = await import(pathToFileURL2(nodePath).href);
407
- const oxide = await import(pathToFileURL2(oxidePath).href);
408
- cached = { node, oxide };
409
- cachedRoot = projectRoot;
410
- return cached;
411
- }
412
- async function compileTailwind(css, fromFile, projectRoot) {
413
- const { node, oxide } = await loadTailwind(projectRoot);
414
- const dependencies = [];
415
- const compiler2 = await node.compile(css, {
416
- base: path3.dirname(fromFile),
417
- from: fromFile,
418
- onDependency: (p) => dependencies.push(p)
641
+ // src/core/debug.ts
642
+ import pc2 from "picocolors";
643
+ function createDebugger(namespace, options = {}) {
644
+ if (!DEBUG) return void 0;
645
+ const patterns = DEBUG.split(",").map((p) => p.trim());
646
+ const enabled = patterns.some((p) => {
647
+ if (p === "*" || p === "nasti:*" || p === "vite:*") return true;
648
+ const normalized = p.startsWith("vite:") ? `nasti:${p.slice(5)}` : p;
649
+ return normalized === namespace;
419
650
  });
420
- const scanner = new oxide.Scanner({ sources: compiler2.sources });
421
- const candidates = scanner.scan();
422
- return {
423
- css: compiler2.build(candidates),
424
- dependencies: [...dependencies, ...scanner.files]
651
+ if (!enabled) return void 0;
652
+ if (options.onlyWhenFocused) {
653
+ const focus = typeof options.onlyWhenFocused === "string" ? options.onlyWhenFocused : namespace;
654
+ if (!patterns.includes(focus)) return void 0;
655
+ }
656
+ let lastTime = performance.now();
657
+ return (...args) => {
658
+ const now = performance.now();
659
+ const elapsed = now - lastTime;
660
+ lastTime = now;
661
+ const msg = args.map((a) => {
662
+ if (typeof a === "string") return a;
663
+ try {
664
+ return JSON.stringify(a);
665
+ } catch {
666
+ return String(a);
667
+ }
668
+ }).join(" ");
669
+ if (filter && !msg.includes(filter)) return;
670
+ console.debug(
671
+ `${pc2.magenta(namespace)} ${msg} ${pc2.dim(`+${Math.round(elapsed)}ms`)}`
672
+ );
425
673
  };
426
674
  }
427
- var TAILWIND_DIRECTIVE_RE, cached, cachedRoot;
428
- var init_tailwind = __esm({
429
- "src/plugins/tailwind.ts"() {
675
+ var DEBUG, filter;
676
+ var init_debug = __esm({
677
+ "src/core/debug.ts"() {
430
678
  "use strict";
431
- 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)/;
432
- cached = null;
433
- cachedRoot = null;
679
+ DEBUG = process.env.DEBUG;
680
+ filter = process.env.NASTI_DEBUG_FILTER || process.env.VITE_DEBUG_FILTER;
434
681
  }
435
682
  });
436
683
 
437
- // src/plugins/css.ts
438
- import path4 from "path";
439
- function cssPlugin(config) {
440
- return {
441
- name: "nasti:css",
442
- resolveId(source) {
443
- if (source.endsWith(".css")) return null;
444
- return null;
445
- },
446
- async transform(code, id) {
447
- if (!id.endsWith(".css")) return null;
448
- let cssSource = code;
449
- if (hasTailwindDirectives(code)) {
450
- const compiled = await compileTailwind(code, id, config.root);
451
- cssSource = compiled.css;
452
- }
453
- const rewritten = rewriteCssUrls(cssSource, id, config.root);
454
- const escaped = JSON.stringify(rewritten);
455
- if (config.command === "serve") {
456
- return {
457
- code: `
458
- const css = ${escaped};
459
- const __nasti_css_id__ = ${JSON.stringify(id)};
460
- const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
461
- if (__nasti_existing__) __nasti_existing__.remove();
462
- const style = document.createElement('style');
463
- style.setAttribute('data-nasti-css', __nasti_css_id__);
464
- style.textContent = css;
465
- document.head.appendChild(style);
466
-
467
- // HMR
468
- if (import.meta.hot) {
469
- import.meta.hot.accept();
470
- import.meta.hot.prune(() => {
471
- style.remove();
472
- });
473
- }
474
-
475
- export default css;
476
- `
477
- };
478
- }
479
- const cssConfig = config.build.css || {};
480
- const nonce = cssConfig.nonce;
481
- const emitCssFile = cssConfig.emitCssFile;
482
- if (emitCssFile) {
483
- const fileName = `assets/${path4.basename(id, ".css")}.css`;
484
- this.emitFile({
485
- type: "asset",
486
- fileName,
487
- source: rewritten
488
- });
489
- return {
490
- code: `
491
- const link = document.createElement('link');
492
- link.rel = 'stylesheet';
493
- link.href = ${JSON.stringify("/" + fileName)};
494
- document.head.appendChild(link);
684
+ // require("../lightningcss.*.node") in node_modules/lightningcss/node/index.js
685
+ var globRequire_lightningcss_node;
686
+ var init_ = __esm({
687
+ 'require("../lightningcss.*.node") in node_modules/lightningcss/node/index.js'() {
688
+ globRequire_lightningcss_node = __glob({});
689
+ }
690
+ });
495
691
 
496
- export default ${escaped};
497
- `,
498
- moduleType: "js"
499
- };
692
+ // node_modules/detect-libc/lib/process.js
693
+ var require_process = __commonJS({
694
+ "node_modules/detect-libc/lib/process.js"(exports, module) {
695
+ "use strict";
696
+ var isLinux = () => process.platform === "linux";
697
+ var report = null;
698
+ var getReport = () => {
699
+ if (!report) {
700
+ if (isLinux() && process.report) {
701
+ const orig = process.report.excludeNetwork;
702
+ process.report.excludeNetwork = true;
703
+ report = process.report.getReport();
704
+ process.report.excludeNetwork = orig;
705
+ } else {
706
+ report = {};
707
+ }
500
708
  }
501
- const nonceAttr = nonce ? `style.setAttribute('nonce', ${JSON.stringify(nonce)});` : "";
502
- return {
503
- code: `
504
- const css = ${escaped};
505
- const style = document.createElement('style');
506
- style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
507
- ${nonceAttr}
508
- style.textContent = css;
509
- document.head.appendChild(style);
709
+ return report;
710
+ };
711
+ module.exports = { isLinux, getReport };
712
+ }
713
+ });
510
714
 
511
- export default css;
512
- `,
513
- moduleType: "js"
514
- };
515
- }
516
- };
517
- }
518
- function rewriteCssUrls(css, from, root) {
519
- return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
520
- if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
521
- return match;
522
- }
523
- const resolved = path4.resolve(path4.dirname(from), url);
524
- const relative = "/" + path4.relative(root, resolved);
525
- return `url(${relative})`;
526
- });
527
- }
528
- var init_css = __esm({
529
- "src/plugins/css.ts"() {
715
+ // node_modules/detect-libc/lib/filesystem.js
716
+ var require_filesystem = __commonJS({
717
+ "node_modules/detect-libc/lib/filesystem.js"(exports, module) {
530
718
  "use strict";
531
- init_tailwind();
719
+ var fs13 = __require("fs");
720
+ var LDD_PATH = "/usr/bin/ldd";
721
+ var SELF_PATH = "/proc/self/exe";
722
+ var MAX_LENGTH = 2048;
723
+ var readFileSync = (path18) => {
724
+ const fd = fs13.openSync(path18, "r");
725
+ const buffer = Buffer.alloc(MAX_LENGTH);
726
+ const bytesRead = fs13.readSync(fd, buffer, 0, MAX_LENGTH, 0);
727
+ fs13.close(fd, () => {
728
+ });
729
+ return buffer.subarray(0, bytesRead);
730
+ };
731
+ var readFile = (path18) => new Promise((resolve, reject) => {
732
+ fs13.open(path18, "r", (err, fd) => {
733
+ if (err) {
734
+ reject(err);
735
+ } else {
736
+ const buffer = Buffer.alloc(MAX_LENGTH);
737
+ fs13.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
738
+ resolve(buffer.subarray(0, bytesRead));
739
+ fs13.close(fd, () => {
740
+ });
741
+ });
742
+ }
743
+ });
744
+ });
745
+ module.exports = {
746
+ LDD_PATH,
747
+ SELF_PATH,
748
+ readFileSync,
749
+ readFile
750
+ };
532
751
  }
533
752
  });
534
753
 
535
- // src/plugins/assets.ts
536
- import path5 from "path";
537
- import fs3 from "fs";
538
- import crypto from "crypto";
539
- function assetsPlugin(config) {
540
- return {
541
- name: "nasti:assets",
542
- resolveId(source) {
543
- if (source.endsWith("?url") || source.endsWith("?raw")) {
544
- return source;
754
+ // node_modules/detect-libc/lib/elf.js
755
+ var require_elf = __commonJS({
756
+ "node_modules/detect-libc/lib/elf.js"(exports, module) {
757
+ "use strict";
758
+ var interpreterPath = (elf) => {
759
+ if (elf.length < 64) {
760
+ return null;
761
+ }
762
+ if (elf.readUInt32BE(0) !== 2135247942) {
763
+ return null;
764
+ }
765
+ if (elf.readUInt8(4) !== 2) {
766
+ return null;
767
+ }
768
+ if (elf.readUInt8(5) !== 1) {
769
+ return null;
770
+ }
771
+ const offset = elf.readUInt32LE(32);
772
+ const size = elf.readUInt16LE(54);
773
+ const count = elf.readUInt16LE(56);
774
+ for (let i = 0; i < count; i++) {
775
+ const headerOffset = offset + i * size;
776
+ const type = elf.readUInt32LE(headerOffset);
777
+ if (type === 3) {
778
+ const fileOffset = elf.readUInt32LE(headerOffset + 8);
779
+ const fileSize = elf.readUInt32LE(headerOffset + 32);
780
+ return elf.subarray(fileOffset, fileOffset + fileSize).toString().replace(/\0.*$/g, "");
781
+ }
545
782
  }
546
783
  return null;
547
- },
548
- load(id) {
549
- const ext = path5.extname(id.replace(/\?.*$/, ""));
550
- if (id.endsWith("?raw")) {
551
- const file = id.slice(0, -4);
552
- if (fs3.existsSync(file)) {
553
- const content = fs3.readFileSync(file, "utf-8");
554
- return `export default ${JSON.stringify(content)}`;
784
+ };
785
+ module.exports = {
786
+ interpreterPath
787
+ };
788
+ }
789
+ });
790
+
791
+ // node_modules/detect-libc/lib/detect-libc.js
792
+ var require_detect_libc = __commonJS({
793
+ "node_modules/detect-libc/lib/detect-libc.js"(exports, module) {
794
+ "use strict";
795
+ var childProcess = __require("child_process");
796
+ var { isLinux, getReport } = require_process();
797
+ var { LDD_PATH, SELF_PATH, readFile, readFileSync } = require_filesystem();
798
+ var { interpreterPath } = require_elf();
799
+ var cachedFamilyInterpreter;
800
+ var cachedFamilyFilesystem;
801
+ var cachedVersionFilesystem;
802
+ var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true";
803
+ var commandOut = "";
804
+ var safeCommand = () => {
805
+ if (!commandOut) {
806
+ return new Promise((resolve) => {
807
+ childProcess.exec(command, (err, out) => {
808
+ commandOut = err ? " " : out;
809
+ resolve(commandOut);
810
+ });
811
+ });
812
+ }
813
+ return commandOut;
814
+ };
815
+ var safeCommandSync = () => {
816
+ if (!commandOut) {
817
+ try {
818
+ commandOut = childProcess.execSync(command, { encoding: "utf8" });
819
+ } catch (_err) {
820
+ commandOut = " ";
555
821
  }
556
822
  }
557
- if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
558
- const file = id.replace(/\?.*$/, "");
559
- if (!fs3.existsSync(file)) return null;
560
- if (config.command === "serve") {
561
- const url = "/" + path5.relative(config.root, file);
562
- return `export default ${JSON.stringify(url)}`;
823
+ return commandOut;
824
+ };
825
+ var GLIBC = "glibc";
826
+ var RE_GLIBC_VERSION = /LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i;
827
+ var MUSL = "musl";
828
+ var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-");
829
+ var familyFromReport = () => {
830
+ const report = getReport();
831
+ if (report.header && report.header.glibcVersionRuntime) {
832
+ return GLIBC;
833
+ }
834
+ if (Array.isArray(report.sharedObjects)) {
835
+ if (report.sharedObjects.some(isFileMusl)) {
836
+ return MUSL;
563
837
  }
564
- const content = fs3.readFileSync(file);
565
- const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
566
- const basename = path5.basename(file, ext);
567
- const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
568
- return `export default ${JSON.stringify(config.base + hashedName)}`;
569
838
  }
570
839
  return null;
571
- }
572
- };
573
- }
574
- var ASSET_EXTENSIONS;
575
- var init_assets = __esm({
576
- "src/plugins/assets.ts"() {
840
+ };
841
+ var familyFromCommand = (out) => {
842
+ const [getconf, ldd1] = out.split(/[\r\n]+/);
843
+ if (getconf && getconf.includes(GLIBC)) {
844
+ return GLIBC;
845
+ }
846
+ if (ldd1 && ldd1.includes(MUSL)) {
847
+ return MUSL;
848
+ }
849
+ return null;
850
+ };
851
+ var familyFromInterpreterPath = (path18) => {
852
+ if (path18) {
853
+ if (path18.includes("/ld-musl-")) {
854
+ return MUSL;
855
+ } else if (path18.includes("/ld-linux-")) {
856
+ return GLIBC;
857
+ }
858
+ }
859
+ return null;
860
+ };
861
+ var getFamilyFromLddContent = (content) => {
862
+ content = content.toString();
863
+ if (content.includes("musl")) {
864
+ return MUSL;
865
+ }
866
+ if (content.includes("GNU C Library")) {
867
+ return GLIBC;
868
+ }
869
+ return null;
870
+ };
871
+ var familyFromFilesystem = async () => {
872
+ if (cachedFamilyFilesystem !== void 0) {
873
+ return cachedFamilyFilesystem;
874
+ }
875
+ cachedFamilyFilesystem = null;
876
+ try {
877
+ const lddContent = await readFile(LDD_PATH);
878
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
879
+ } catch (e) {
880
+ }
881
+ return cachedFamilyFilesystem;
882
+ };
883
+ var familyFromFilesystemSync = () => {
884
+ if (cachedFamilyFilesystem !== void 0) {
885
+ return cachedFamilyFilesystem;
886
+ }
887
+ cachedFamilyFilesystem = null;
888
+ try {
889
+ const lddContent = readFileSync(LDD_PATH);
890
+ cachedFamilyFilesystem = getFamilyFromLddContent(lddContent);
891
+ } catch (e) {
892
+ }
893
+ return cachedFamilyFilesystem;
894
+ };
895
+ var familyFromInterpreter = async () => {
896
+ if (cachedFamilyInterpreter !== void 0) {
897
+ return cachedFamilyInterpreter;
898
+ }
899
+ cachedFamilyInterpreter = null;
900
+ try {
901
+ const selfContent = await readFile(SELF_PATH);
902
+ const path18 = interpreterPath(selfContent);
903
+ cachedFamilyInterpreter = familyFromInterpreterPath(path18);
904
+ } catch (e) {
905
+ }
906
+ return cachedFamilyInterpreter;
907
+ };
908
+ var familyFromInterpreterSync = () => {
909
+ if (cachedFamilyInterpreter !== void 0) {
910
+ return cachedFamilyInterpreter;
911
+ }
912
+ cachedFamilyInterpreter = null;
913
+ try {
914
+ const selfContent = readFileSync(SELF_PATH);
915
+ const path18 = interpreterPath(selfContent);
916
+ cachedFamilyInterpreter = familyFromInterpreterPath(path18);
917
+ } catch (e) {
918
+ }
919
+ return cachedFamilyInterpreter;
920
+ };
921
+ var family = async () => {
922
+ let family2 = null;
923
+ if (isLinux()) {
924
+ family2 = await familyFromInterpreter();
925
+ if (!family2) {
926
+ family2 = await familyFromFilesystem();
927
+ if (!family2) {
928
+ family2 = familyFromReport();
929
+ }
930
+ if (!family2) {
931
+ const out = await safeCommand();
932
+ family2 = familyFromCommand(out);
933
+ }
934
+ }
935
+ }
936
+ return family2;
937
+ };
938
+ var familySync = () => {
939
+ let family2 = null;
940
+ if (isLinux()) {
941
+ family2 = familyFromInterpreterSync();
942
+ if (!family2) {
943
+ family2 = familyFromFilesystemSync();
944
+ if (!family2) {
945
+ family2 = familyFromReport();
946
+ }
947
+ if (!family2) {
948
+ const out = safeCommandSync();
949
+ family2 = familyFromCommand(out);
950
+ }
951
+ }
952
+ }
953
+ return family2;
954
+ };
955
+ var isNonGlibcLinux = async () => isLinux() && await family() !== GLIBC;
956
+ var isNonGlibcLinuxSync = () => isLinux() && familySync() !== GLIBC;
957
+ var versionFromFilesystem = async () => {
958
+ if (cachedVersionFilesystem !== void 0) {
959
+ return cachedVersionFilesystem;
960
+ }
961
+ cachedVersionFilesystem = null;
962
+ try {
963
+ const lddContent = await readFile(LDD_PATH);
964
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
965
+ if (versionMatch) {
966
+ cachedVersionFilesystem = versionMatch[1];
967
+ }
968
+ } catch (e) {
969
+ }
970
+ return cachedVersionFilesystem;
971
+ };
972
+ var versionFromFilesystemSync = () => {
973
+ if (cachedVersionFilesystem !== void 0) {
974
+ return cachedVersionFilesystem;
975
+ }
976
+ cachedVersionFilesystem = null;
977
+ try {
978
+ const lddContent = readFileSync(LDD_PATH);
979
+ const versionMatch = lddContent.match(RE_GLIBC_VERSION);
980
+ if (versionMatch) {
981
+ cachedVersionFilesystem = versionMatch[1];
982
+ }
983
+ } catch (e) {
984
+ }
985
+ return cachedVersionFilesystem;
986
+ };
987
+ var versionFromReport = () => {
988
+ const report = getReport();
989
+ if (report.header && report.header.glibcVersionRuntime) {
990
+ return report.header.glibcVersionRuntime;
991
+ }
992
+ return null;
993
+ };
994
+ var versionSuffix = (s) => s.trim().split(/\s+/)[1];
995
+ var versionFromCommand = (out) => {
996
+ const [getconf, ldd1, ldd2] = out.split(/[\r\n]+/);
997
+ if (getconf && getconf.includes(GLIBC)) {
998
+ return versionSuffix(getconf);
999
+ }
1000
+ if (ldd1 && ldd2 && ldd1.includes(MUSL)) {
1001
+ return versionSuffix(ldd2);
1002
+ }
1003
+ return null;
1004
+ };
1005
+ var version = async () => {
1006
+ let version2 = null;
1007
+ if (isLinux()) {
1008
+ version2 = await versionFromFilesystem();
1009
+ if (!version2) {
1010
+ version2 = versionFromReport();
1011
+ }
1012
+ if (!version2) {
1013
+ const out = await safeCommand();
1014
+ version2 = versionFromCommand(out);
1015
+ }
1016
+ }
1017
+ return version2;
1018
+ };
1019
+ var versionSync = () => {
1020
+ let version2 = null;
1021
+ if (isLinux()) {
1022
+ version2 = versionFromFilesystemSync();
1023
+ if (!version2) {
1024
+ version2 = versionFromReport();
1025
+ }
1026
+ if (!version2) {
1027
+ const out = safeCommandSync();
1028
+ version2 = versionFromCommand(out);
1029
+ }
1030
+ }
1031
+ return version2;
1032
+ };
1033
+ module.exports = {
1034
+ GLIBC,
1035
+ MUSL,
1036
+ family,
1037
+ familySync,
1038
+ isNonGlibcLinux,
1039
+ isNonGlibcLinuxSync,
1040
+ version,
1041
+ versionSync
1042
+ };
1043
+ }
1044
+ });
1045
+
1046
+ // node_modules/lightningcss/node/browserslistToTargets.js
1047
+ var require_browserslistToTargets = __commonJS({
1048
+ "node_modules/lightningcss/node/browserslistToTargets.js"(exports, module) {
1049
+ "use strict";
1050
+ var BROWSER_MAPPING = {
1051
+ and_chr: "chrome",
1052
+ and_ff: "firefox",
1053
+ ie_mob: "ie",
1054
+ op_mob: "opera",
1055
+ and_qq: null,
1056
+ and_uc: null,
1057
+ baidu: null,
1058
+ bb: null,
1059
+ kaios: null,
1060
+ op_mini: null
1061
+ };
1062
+ function browserslistToTargets2(browserslist) {
1063
+ let targets = {};
1064
+ for (let browser of browserslist) {
1065
+ let [name, v] = browser.split(" ");
1066
+ if (BROWSER_MAPPING[name] === null) {
1067
+ continue;
1068
+ }
1069
+ let version = parseVersion(v);
1070
+ if (version == null) {
1071
+ continue;
1072
+ }
1073
+ if (targets[name] == null || version < targets[name]) {
1074
+ targets[name] = version;
1075
+ }
1076
+ }
1077
+ return targets;
1078
+ }
1079
+ function parseVersion(version) {
1080
+ let [major, minor = 0, patch = 0] = version.split("-")[0].split(".").map((v) => parseInt(v, 10));
1081
+ if (isNaN(major) || isNaN(minor) || isNaN(patch)) {
1082
+ return null;
1083
+ }
1084
+ return major << 16 | minor << 8 | patch;
1085
+ }
1086
+ module.exports = browserslistToTargets2;
1087
+ }
1088
+ });
1089
+
1090
+ // node_modules/lightningcss/node/composeVisitors.js
1091
+ var require_composeVisitors = __commonJS({
1092
+ "node_modules/lightningcss/node/composeVisitors.js"(exports, module) {
1093
+ "use strict";
1094
+ function composeVisitors2(visitors) {
1095
+ if (visitors.length === 1) {
1096
+ return visitors[0];
1097
+ }
1098
+ if (visitors.some((v) => typeof v === "function")) {
1099
+ return (opts) => {
1100
+ let v = visitors.map((v2) => typeof v2 === "function" ? v2(opts) : v2);
1101
+ return composeVisitors2(v);
1102
+ };
1103
+ }
1104
+ let res = {};
1105
+ composeSimpleVisitors(res, visitors, "StyleSheet");
1106
+ composeSimpleVisitors(res, visitors, "StyleSheetExit");
1107
+ composeObjectVisitors(res, visitors, "Rule", ruleVisitor, wrapCustomAndUnknownAtRule);
1108
+ composeObjectVisitors(res, visitors, "RuleExit", ruleVisitor, wrapCustomAndUnknownAtRule);
1109
+ composeObjectVisitors(res, visitors, "Declaration", declarationVisitor, wrapCustomProperty);
1110
+ composeObjectVisitors(res, visitors, "DeclarationExit", declarationVisitor, wrapCustomProperty);
1111
+ composeSimpleVisitors(res, visitors, "Url");
1112
+ composeSimpleVisitors(res, visitors, "Color");
1113
+ composeSimpleVisitors(res, visitors, "Image");
1114
+ composeSimpleVisitors(res, visitors, "ImageExit");
1115
+ composeSimpleVisitors(res, visitors, "Length");
1116
+ composeSimpleVisitors(res, visitors, "Angle");
1117
+ composeSimpleVisitors(res, visitors, "Ratio");
1118
+ composeSimpleVisitors(res, visitors, "Resolution");
1119
+ composeSimpleVisitors(res, visitors, "Time");
1120
+ composeSimpleVisitors(res, visitors, "CustomIdent");
1121
+ composeSimpleVisitors(res, visitors, "DashedIdent");
1122
+ composeArrayFunctions(res, visitors, "MediaQuery");
1123
+ composeArrayFunctions(res, visitors, "MediaQueryExit");
1124
+ composeSimpleVisitors(res, visitors, "SupportsCondition");
1125
+ composeSimpleVisitors(res, visitors, "SupportsConditionExit");
1126
+ composeArrayFunctions(res, visitors, "Selector");
1127
+ composeTokenVisitors(res, visitors, "Token", "token", false);
1128
+ composeTokenVisitors(res, visitors, "Function", "function", false);
1129
+ composeTokenVisitors(res, visitors, "FunctionExit", "function", true);
1130
+ composeTokenVisitors(res, visitors, "Variable", "var", false);
1131
+ composeTokenVisitors(res, visitors, "VariableExit", "var", true);
1132
+ composeTokenVisitors(res, visitors, "EnvironmentVariable", "env", false);
1133
+ composeTokenVisitors(res, visitors, "EnvironmentVariableExit", "env", true);
1134
+ return res;
1135
+ }
1136
+ module.exports = composeVisitors2;
1137
+ function wrapCustomAndUnknownAtRule(k, f) {
1138
+ if (k === "unknown") {
1139
+ return ((value) => f({ type: "unknown", value }));
1140
+ }
1141
+ if (k === "custom") {
1142
+ return ((value) => f({ type: "custom", value }));
1143
+ }
1144
+ return f;
1145
+ }
1146
+ function wrapCustomProperty(k, f) {
1147
+ return k === "custom" ? ((value) => f({ property: "custom", value })) : f;
1148
+ }
1149
+ function ruleVisitor(f, item) {
1150
+ if (typeof f === "object") {
1151
+ if (item.type === "unknown") {
1152
+ let v = f.unknown;
1153
+ if (typeof v === "object") {
1154
+ v = v[item.value.name];
1155
+ }
1156
+ return v?.(item.value);
1157
+ }
1158
+ if (item.type === "custom") {
1159
+ let v = f.custom;
1160
+ if (typeof v === "object") {
1161
+ v = v[item.value.name];
1162
+ }
1163
+ return v?.(item.value);
1164
+ }
1165
+ return f[item.type]?.(item);
1166
+ }
1167
+ return f?.(item);
1168
+ }
1169
+ function declarationVisitor(f, item) {
1170
+ if (typeof f === "object") {
1171
+ let name = item.property;
1172
+ if (item.property === "unparsed") {
1173
+ name = item.value.propertyId.property;
1174
+ } else if (item.property === "custom") {
1175
+ let v = f.custom;
1176
+ if (typeof v === "object") {
1177
+ v = v[item.value.name];
1178
+ }
1179
+ return v?.(item.value);
1180
+ }
1181
+ return f[name]?.(item);
1182
+ }
1183
+ return f?.(item);
1184
+ }
1185
+ function extractObjectsOrFunctions(visitors, key) {
1186
+ let values = [];
1187
+ let hasFunction = false;
1188
+ let allKeys = /* @__PURE__ */ new Set();
1189
+ for (let visitor of visitors) {
1190
+ let v = visitor[key];
1191
+ if (v) {
1192
+ if (typeof v === "function") {
1193
+ hasFunction = true;
1194
+ } else {
1195
+ for (let key2 in v) {
1196
+ allKeys.add(key2);
1197
+ }
1198
+ }
1199
+ values.push(v);
1200
+ }
1201
+ }
1202
+ return [values, hasFunction, allKeys];
1203
+ }
1204
+ function composeObjectVisitors(res, visitors, key, apply, wrapKey) {
1205
+ let [values, hasFunction, allKeys] = extractObjectsOrFunctions(visitors, key);
1206
+ if (values.length === 0) {
1207
+ return;
1208
+ }
1209
+ if (values.length === 1) {
1210
+ res[key] = values[0];
1211
+ return;
1212
+ }
1213
+ let f = createArrayVisitor(visitors, (visitor, item) => apply(visitor[key], item));
1214
+ if (hasFunction) {
1215
+ res[key] = f;
1216
+ } else {
1217
+ let v = {};
1218
+ for (let k of allKeys) {
1219
+ v[k] = wrapKey(k, f);
1220
+ }
1221
+ res[key] = v;
1222
+ }
1223
+ }
1224
+ function composeTokenVisitors(res, visitors, key, type, isExit) {
1225
+ let [values, hasFunction, allKeys] = extractObjectsOrFunctions(visitors, key);
1226
+ if (values.length === 0) {
1227
+ return;
1228
+ }
1229
+ if (values.length === 1) {
1230
+ res[key] = values[0];
1231
+ return;
1232
+ }
1233
+ let f = createTokenVisitor(visitors, type, isExit);
1234
+ if (hasFunction) {
1235
+ res[key] = f;
1236
+ } else {
1237
+ let v = {};
1238
+ for (let key2 of allKeys) {
1239
+ v[key2] = f;
1240
+ }
1241
+ res[key] = v;
1242
+ }
1243
+ }
1244
+ function createTokenVisitor(visitors, type, isExit) {
1245
+ let v = createArrayVisitor(visitors, (visitor, item) => {
1246
+ let f;
1247
+ switch (item.type) {
1248
+ case "token":
1249
+ f = visitor.Token;
1250
+ if (typeof f === "object") {
1251
+ f = f[item.value.type];
1252
+ }
1253
+ break;
1254
+ case "function":
1255
+ f = isExit ? visitor.FunctionExit : visitor.Function;
1256
+ if (typeof f === "object") {
1257
+ f = f[item.value.name];
1258
+ }
1259
+ break;
1260
+ case "var":
1261
+ f = isExit ? visitor.VariableExit : visitor.Variable;
1262
+ break;
1263
+ case "env":
1264
+ f = isExit ? visitor.EnvironmentVariableExit : visitor.EnvironmentVariable;
1265
+ if (typeof f === "object") {
1266
+ let name;
1267
+ switch (item.value.name.type) {
1268
+ case "ua":
1269
+ case "unknown":
1270
+ name = item.value.name.value;
1271
+ break;
1272
+ case "custom":
1273
+ name = item.value.name.ident;
1274
+ break;
1275
+ }
1276
+ f = f[name];
1277
+ }
1278
+ break;
1279
+ case "color":
1280
+ f = visitor.Color;
1281
+ break;
1282
+ case "url":
1283
+ f = visitor.Url;
1284
+ break;
1285
+ case "length":
1286
+ f = visitor.Length;
1287
+ break;
1288
+ case "angle":
1289
+ f = visitor.Angle;
1290
+ break;
1291
+ case "time":
1292
+ f = visitor.Time;
1293
+ break;
1294
+ case "resolution":
1295
+ f = visitor.Resolution;
1296
+ break;
1297
+ case "dashed-ident":
1298
+ f = visitor.DashedIdent;
1299
+ break;
1300
+ }
1301
+ if (!f) {
1302
+ return;
1303
+ }
1304
+ let res = f(item.value);
1305
+ switch (item.type) {
1306
+ case "color":
1307
+ case "url":
1308
+ case "length":
1309
+ case "angle":
1310
+ case "time":
1311
+ case "resolution":
1312
+ case "dashed-ident":
1313
+ if (Array.isArray(res)) {
1314
+ res = res.map((value) => ({ type: item.type, value }));
1315
+ } else if (res) {
1316
+ res = { type: item.type, value: res };
1317
+ }
1318
+ break;
1319
+ }
1320
+ return res;
1321
+ });
1322
+ return (value) => v({ type, value });
1323
+ }
1324
+ function extractFunctions(visitors, key) {
1325
+ let functions = [];
1326
+ for (let visitor of visitors) {
1327
+ let f = visitor[key];
1328
+ if (f) {
1329
+ functions.push(f);
1330
+ }
1331
+ }
1332
+ return functions;
1333
+ }
1334
+ function composeSimpleVisitors(res, visitors, key) {
1335
+ let functions = extractFunctions(visitors, key);
1336
+ if (functions.length === 0) {
1337
+ return;
1338
+ }
1339
+ if (functions.length === 1) {
1340
+ res[key] = functions[0];
1341
+ return;
1342
+ }
1343
+ res[key] = (arg) => {
1344
+ let mutated = false;
1345
+ for (let f of functions) {
1346
+ let res2 = f(arg);
1347
+ if (res2) {
1348
+ arg = res2;
1349
+ mutated = true;
1350
+ }
1351
+ }
1352
+ return mutated ? arg : void 0;
1353
+ };
1354
+ }
1355
+ function composeArrayFunctions(res, visitors, key) {
1356
+ let functions = extractFunctions(visitors, key);
1357
+ if (functions.length === 0) {
1358
+ return;
1359
+ }
1360
+ if (functions.length === 1) {
1361
+ res[key] = functions[0];
1362
+ return;
1363
+ }
1364
+ res[key] = createArrayVisitor(functions, (f, item) => f(item));
1365
+ }
1366
+ function createArrayVisitor(visitors, apply) {
1367
+ let seen = new Bitset(visitors.length);
1368
+ return (arg) => {
1369
+ let arr = [arg];
1370
+ let mutated = false;
1371
+ seen.clear();
1372
+ for (let i = 0; i < arr.length; i++) {
1373
+ for (let v = 0; v < visitors.length && i < arr.length; ) {
1374
+ if (seen.get(v)) {
1375
+ v++;
1376
+ continue;
1377
+ }
1378
+ let item = arr[i];
1379
+ let visitor = visitors[v];
1380
+ let res = apply(visitor, item);
1381
+ if (Array.isArray(res)) {
1382
+ if (res.length === 0) {
1383
+ arr.splice(i, 1);
1384
+ } else if (res.length === 1) {
1385
+ arr[i] = res[0];
1386
+ } else {
1387
+ arr.splice(i, 1, ...res);
1388
+ }
1389
+ mutated = true;
1390
+ seen.set(v);
1391
+ v = 0;
1392
+ } else if (res) {
1393
+ arr[i] = res;
1394
+ mutated = true;
1395
+ seen.set(v);
1396
+ v = 0;
1397
+ } else {
1398
+ v++;
1399
+ }
1400
+ }
1401
+ }
1402
+ if (!mutated) {
1403
+ return;
1404
+ }
1405
+ return arr.length === 1 ? arr[0] : arr;
1406
+ };
1407
+ }
1408
+ var Bitset = class {
1409
+ constructor(maxBits = 32) {
1410
+ this.bits = 0;
1411
+ this.more = maxBits > 32 ? new Uint32Array(Math.ceil((maxBits - 32) / 32)) : null;
1412
+ }
1413
+ /** @param {number} bit */
1414
+ get(bit) {
1415
+ if (bit >= 32 && this.more) {
1416
+ let i = Math.floor((bit - 32) / 32);
1417
+ let b = bit % 32;
1418
+ return Boolean(this.more[i] & 1 << b);
1419
+ } else {
1420
+ return Boolean(this.bits & 1 << bit);
1421
+ }
1422
+ }
1423
+ /** @param {number} bit */
1424
+ set(bit) {
1425
+ if (bit >= 32 && this.more) {
1426
+ let i = Math.floor((bit - 32) / 32);
1427
+ let b = bit % 32;
1428
+ this.more[i] |= 1 << b;
1429
+ } else {
1430
+ this.bits |= 1 << bit;
1431
+ }
1432
+ }
1433
+ clear() {
1434
+ this.bits = 0;
1435
+ if (this.more) {
1436
+ this.more.fill(0);
1437
+ }
1438
+ }
1439
+ };
1440
+ }
1441
+ });
1442
+
1443
+ // node_modules/lightningcss/node/flags.js
1444
+ var require_flags = __commonJS({
1445
+ "node_modules/lightningcss/node/flags.js"(exports) {
1446
+ "use strict";
1447
+ exports.Features = {
1448
+ Nesting: 1,
1449
+ NotSelectorList: 2,
1450
+ DirSelector: 4,
1451
+ LangSelectorList: 8,
1452
+ IsSelector: 16,
1453
+ TextDecorationThicknessPercent: 32,
1454
+ MediaIntervalSyntax: 64,
1455
+ MediaRangeSyntax: 128,
1456
+ CustomMediaQueries: 256,
1457
+ ClampFunction: 512,
1458
+ ColorFunction: 1024,
1459
+ OklabColors: 2048,
1460
+ LabColors: 4096,
1461
+ P3Colors: 8192,
1462
+ HexAlphaColors: 16384,
1463
+ SpaceSeparatedColorNotation: 32768,
1464
+ FontFamilySystemUi: 65536,
1465
+ DoublePositionGradients: 131072,
1466
+ VendorPrefixes: 262144,
1467
+ LogicalProperties: 524288,
1468
+ LightDark: 1048576,
1469
+ Selectors: 31,
1470
+ MediaQueries: 448,
1471
+ Colors: 1113088
1472
+ };
1473
+ }
1474
+ });
1475
+
1476
+ // node_modules/lightningcss/node/index.js
1477
+ var require_node = __commonJS({
1478
+ "node_modules/lightningcss/node/index.js"(exports, module) {
1479
+ "use strict";
1480
+ init_();
1481
+ var parts = [process.platform, process.arch];
1482
+ if (process.platform === "linux") {
1483
+ const { MUSL, familySync } = require_detect_libc();
1484
+ const family = familySync();
1485
+ if (family === MUSL) {
1486
+ parts.push("musl");
1487
+ } else if (process.arch === "arm") {
1488
+ parts.push("gnueabihf");
1489
+ } else {
1490
+ parts.push("gnu");
1491
+ }
1492
+ } else if (process.platform === "win32") {
1493
+ parts.push("msvc");
1494
+ }
1495
+ var native;
1496
+ try {
1497
+ native = __require(`lightningcss-${parts.join("-")}`);
1498
+ } catch (err) {
1499
+ native = globRequire_lightningcss_node(`../lightningcss.${parts.join("-")}.node`);
1500
+ }
1501
+ module.exports.transform = wrap(native.transform);
1502
+ module.exports.transformStyleAttribute = wrap(native.transformStyleAttribute);
1503
+ module.exports.bundle = wrap(native.bundle);
1504
+ module.exports.bundleAsync = wrap(native.bundleAsync);
1505
+ module.exports.browserslistToTargets = require_browserslistToTargets();
1506
+ module.exports.composeVisitors = require_composeVisitors();
1507
+ module.exports.Features = require_flags().Features;
1508
+ function wrap(call) {
1509
+ return (options) => {
1510
+ if (typeof options.visitor === "function") {
1511
+ let deps = [];
1512
+ options.visitor = options.visitor({
1513
+ addDependency(dep) {
1514
+ deps.push(dep);
1515
+ }
1516
+ });
1517
+ let result = call(options);
1518
+ if (result instanceof Promise) {
1519
+ result = result.then((res) => {
1520
+ if (deps.length) {
1521
+ res.dependencies ??= [];
1522
+ res.dependencies.push(...deps);
1523
+ }
1524
+ return res;
1525
+ });
1526
+ } else if (deps.length) {
1527
+ result.dependencies ??= [];
1528
+ result.dependencies.push(...deps);
1529
+ }
1530
+ return result;
1531
+ } else {
1532
+ return call(options);
1533
+ }
1534
+ };
1535
+ }
1536
+ }
1537
+ });
1538
+
1539
+ // node_modules/lightningcss/node/index.mjs
1540
+ var node_exports = {};
1541
+ __export(node_exports, {
1542
+ Features: () => Features,
1543
+ browserslistToTargets: () => browserslistToTargets,
1544
+ bundle: () => bundle,
1545
+ bundleAsync: () => bundleAsync,
1546
+ composeVisitors: () => composeVisitors,
1547
+ transform: () => transform,
1548
+ transformStyleAttribute: () => transformStyleAttribute
1549
+ });
1550
+ var import_index, transform, transformStyleAttribute, bundle, bundleAsync, browserslistToTargets, composeVisitors, Features;
1551
+ var init_node = __esm({
1552
+ "node_modules/lightningcss/node/index.mjs"() {
1553
+ "use strict";
1554
+ import_index = __toESM(require_node(), 1);
1555
+ ({ transform, transformStyleAttribute, bundle, bundleAsync, browserslistToTargets, composeVisitors, Features } = import_index.default);
1556
+ }
1557
+ });
1558
+
1559
+ // src/core/css-engine.ts
1560
+ function createCssEngine() {
1561
+ return {
1562
+ styles: /* @__PURE__ */ new Map(),
1563
+ entryCss: /* @__PURE__ */ new Map(),
1564
+ allCss: [],
1565
+ pendingSingle: [],
1566
+ singleFileName: null
1567
+ };
1568
+ }
1569
+ function normalizeCssModuleId(id) {
1570
+ return id.startsWith("\0") ? id.slice(1) : id;
1571
+ }
1572
+ async function minifyCss(css, config) {
1573
+ if (lightningCss === void 0) {
1574
+ try {
1575
+ lightningCss = await Promise.resolve().then(() => (init_node(), node_exports));
1576
+ } catch {
1577
+ lightningCss = null;
1578
+ debug?.("lightningcss unavailable, falling back to regex minifier");
1579
+ }
1580
+ }
1581
+ if (lightningCss) {
1582
+ try {
1583
+ const result = lightningCss.transform({
1584
+ filename: "bundle.css",
1585
+ code: Buffer.from(css),
1586
+ minify: true,
1587
+ // 不展开 @import(Tailwind 已 flatten;裸 @import 保留原样交给浏览器)
1588
+ errorRecovery: true
1589
+ });
1590
+ for (const w of result.warnings ?? []) {
1591
+ config.logger.warnOnce(`[nasti:css] ${w.message}`);
1592
+ }
1593
+ return result.code.toString();
1594
+ } catch (err) {
1595
+ config.logger.warnOnce(
1596
+ `[nasti:css] Lightning CSS minify failed (${err.message}), emitting unminified CSS`
1597
+ );
1598
+ return css;
1599
+ }
1600
+ }
1601
+ return fallbackMinify(css);
1602
+ }
1603
+ function fallbackMinify(css) {
1604
+ return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s*([{}:;,])\s*/g, "$1").replace(/;}/g, "}").replace(/\s+/g, " ").trim();
1605
+ }
1606
+ var debug, lightningCss;
1607
+ var init_css_engine = __esm({
1608
+ "src/core/css-engine.ts"() {
1609
+ "use strict";
1610
+ init_debug();
1611
+ debug = createDebugger("nasti:css");
1612
+ }
1613
+ });
1614
+
1615
+ // src/plugins/tailwind.ts
1616
+ import path3 from "path";
1617
+ import { createRequire as createRequire2 } from "module";
1618
+ import { pathToFileURL as pathToFileURL2 } from "url";
1619
+ function hasTailwindDirectives(css) {
1620
+ const withoutBlockComments = css.replace(/\/\*[\s\S]*?\*\//g, "");
1621
+ const withoutLineComments = withoutBlockComments.replace(/\/\/.*$/gm, "");
1622
+ return TAILWIND_DIRECTIVE_RE.test(withoutLineComments);
1623
+ }
1624
+ async function loadTailwind(projectRoot) {
1625
+ if (cached && cachedRoot === projectRoot) return cached;
1626
+ const req = createRequire2(path3.join(projectRoot, "package.json"));
1627
+ let nodePath;
1628
+ let oxidePath;
1629
+ try {
1630
+ nodePath = req.resolve("@tailwindcss/node");
1631
+ oxidePath = req.resolve("@tailwindcss/oxide");
1632
+ } catch {
1633
+ throw new Error(
1634
+ "[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"
1635
+ );
1636
+ }
1637
+ const node = await import(pathToFileURL2(nodePath).href);
1638
+ const oxide = await import(pathToFileURL2(oxidePath).href);
1639
+ cached = { node, oxide };
1640
+ cachedRoot = projectRoot;
1641
+ return cached;
1642
+ }
1643
+ async function compileTailwind(css, fromFile, projectRoot) {
1644
+ const { node, oxide } = await loadTailwind(projectRoot);
1645
+ const dependencies = [];
1646
+ const compiler2 = await node.compile(css, {
1647
+ base: path3.dirname(fromFile),
1648
+ from: fromFile,
1649
+ onDependency: (p) => dependencies.push(p)
1650
+ });
1651
+ const scanner = new oxide.Scanner({ sources: compiler2.sources });
1652
+ const candidates = scanner.scan();
1653
+ return {
1654
+ css: compiler2.build(candidates),
1655
+ dependencies: [...dependencies, ...scanner.files]
1656
+ };
1657
+ }
1658
+ var TAILWIND_DIRECTIVE_RE, cached, cachedRoot;
1659
+ var init_tailwind = __esm({
1660
+ "src/plugins/tailwind.ts"() {
1661
+ "use strict";
1662
+ 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)/;
1663
+ cached = null;
1664
+ cachedRoot = null;
1665
+ }
1666
+ });
1667
+
1668
+ // src/plugins/css.ts
1669
+ import path4 from "path";
1670
+ function cssPlugin(config, engine, consumer = "client") {
1671
+ return {
1672
+ name: "nasti:css",
1673
+ resolveId(source) {
1674
+ if (source.endsWith(".css")) return null;
1675
+ return null;
1676
+ },
1677
+ async transform(code, id) {
1678
+ const [file, query = ""] = id.split("?", 2);
1679
+ const isCssRequest = file.endsWith(".css") || /\.css$/.test(id);
1680
+ if (!isCssRequest) return null;
1681
+ if (query === "raw" || query === "url") return null;
1682
+ let cssSource = code;
1683
+ if (hasTailwindDirectives(code)) {
1684
+ const compiled = await compileTailwind(code, id, config.root);
1685
+ cssSource = compiled.css;
1686
+ }
1687
+ const rewritten = rewriteCssUrls(cssSource, file, config.root);
1688
+ const escaped = JSON.stringify(rewritten);
1689
+ if (query === "inline") {
1690
+ return { code: `export default ${escaped};
1691
+ `, moduleType: "js" };
1692
+ }
1693
+ if (consumer === "server") {
1694
+ return { code: `export default ${escaped};
1695
+ `, moduleType: "js" };
1696
+ }
1697
+ if (config.command === "serve") {
1698
+ return {
1699
+ code: `
1700
+ const css = ${escaped};
1701
+ const __nasti_css_id__ = ${JSON.stringify(id)};
1702
+ const __nasti_existing__ = document.querySelector('style[data-nasti-css=' + JSON.stringify(__nasti_css_id__) + ']');
1703
+ if (__nasti_existing__) __nasti_existing__.remove();
1704
+ const style = document.createElement('style');
1705
+ style.setAttribute('data-nasti-css', __nasti_css_id__);
1706
+ style.textContent = css;
1707
+ document.head.appendChild(style);
1708
+
1709
+ // HMR\uFF08prune \u5728 bundled \u6A21\u5F0F\u7684 rolldown hot context \u4E0A\u4E0D\u5B58\u5728\uFF0C\u987B\u5B88\u536B\uFF09
1710
+ if (import.meta.hot) {
1711
+ import.meta.hot.accept();
1712
+ if (import.meta.hot.prune) {
1713
+ import.meta.hot.prune(() => {
1714
+ style.remove();
1715
+ });
1716
+ }
1717
+ }
1718
+
1719
+ export default css;
1720
+ `,
1721
+ // bundled dev(DevEngine)下该模块会进 Rolldown:不标 js 会按 .css
1722
+ // 扩展名走 CSS 管线触发 #4271 报错;unbundled 中间件忽略此字段
1723
+ moduleType: "js"
1724
+ };
1725
+ }
1726
+ if (engine) {
1727
+ engine.styles.set(normalizeCssModuleId(id), rewritten);
1728
+ return {
1729
+ code: `export default '';
1730
+ `,
1731
+ moduleType: "js",
1732
+ // 防止空 stub 被 tree-shake 出 chunk.moduleIds(css-post 靠它定位)
1733
+ moduleSideEffects: "no-treeshake"
1734
+ };
1735
+ }
1736
+ const cssConfig = config.build.css || {};
1737
+ const nonce = cssConfig.nonce;
1738
+ const nonceAttr = nonce ? `style.setAttribute('nonce', ${JSON.stringify(nonce)});` : "";
1739
+ return {
1740
+ code: `
1741
+ const css = ${escaped};
1742
+ const style = document.createElement('style');
1743
+ style.setAttribute('data-nasti-css', ${JSON.stringify(id)});
1744
+ ${nonceAttr}
1745
+ style.textContent = css;
1746
+ document.head.appendChild(style);
1747
+
1748
+ export default css;
1749
+ `,
1750
+ moduleType: "js"
1751
+ };
1752
+ }
1753
+ };
1754
+ }
1755
+ function rewriteCssUrls(css, from, root) {
1756
+ return css.replace(/url\(\s*['"]?([^'")\s]+)['"]?\s*\)/g, (match, url) => {
1757
+ if (url.startsWith("/") || url.startsWith("data:") || url.startsWith("http")) {
1758
+ return match;
1759
+ }
1760
+ const resolved = path4.resolve(path4.dirname(from), url);
1761
+ const relative = "/" + path4.relative(root, resolved).replace(/\\/g, "/");
1762
+ return `url(${relative})`;
1763
+ });
1764
+ }
1765
+ var init_css = __esm({
1766
+ "src/plugins/css.ts"() {
1767
+ "use strict";
1768
+ init_css_engine();
1769
+ init_tailwind();
1770
+ }
1771
+ });
1772
+
1773
+ // src/plugins/css-post.ts
1774
+ function collectChunkCss(chunk, engine) {
1775
+ const ids = chunk.moduleIds ?? Object.keys(chunk.modules);
1776
+ let css = "";
1777
+ for (const id of ids) {
1778
+ const styles = engine.styles.get(normalizeCssModuleId(id));
1779
+ if (styles) css += styles + "\n";
1780
+ }
1781
+ return css;
1782
+ }
1783
+ function cssPostPlugin(config, engine) {
1784
+ return {
1785
+ name: "nasti:css-post",
1786
+ enforce: "post",
1787
+ async renderChunk(code, chunk) {
1788
+ const css = collectChunkCss(chunk, engine);
1789
+ if (!css) return null;
1790
+ if (!config.build.cssCodeSplit) {
1791
+ engine.pendingSingle.push(css);
1792
+ return null;
1793
+ }
1794
+ const finalCss = config.build.cssMinify ? await minifyCss(css, config) : css;
1795
+ const ref = this.emitFile({
1796
+ type: "asset",
1797
+ name: `${chunk.name}.css`,
1798
+ source: finalCss
1799
+ });
1800
+ const fileName = this.getFileName(ref);
1801
+ engine.allCss.push(fileName);
1802
+ if (chunk.isEntry) {
1803
+ const key = chunk.facadeModuleId ?? chunk.name;
1804
+ const existing = engine.entryCss.get(key) ?? [];
1805
+ existing.push(fileName);
1806
+ engine.entryCss.set(key, existing);
1807
+ return null;
1808
+ }
1809
+ const href = JSON.stringify(config.base + fileName);
1810
+ const snippet = `
1811
+ ;(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){}})();`;
1812
+ return { code: code + snippet, map: null };
1813
+ },
1814
+ augmentChunkHash(chunk) {
1815
+ const css = collectChunkCss(chunk, engine);
1816
+ return css || void 0;
1817
+ },
1818
+ async generateBundle() {
1819
+ if (config.build.cssCodeSplit || engine.pendingSingle.length === 0) return;
1820
+ const merged = engine.pendingSingle.join("\n");
1821
+ const finalCss = config.build.cssMinify ? await minifyCss(merged, config) : merged;
1822
+ const ref = this.emitFile({ type: "asset", name: "style.css", source: finalCss });
1823
+ const fileName = this.getFileName(ref);
1824
+ engine.singleFileName = fileName;
1825
+ engine.allCss.push(fileName);
1826
+ }
1827
+ };
1828
+ }
1829
+ var init_css_post = __esm({
1830
+ "src/plugins/css-post.ts"() {
1831
+ "use strict";
1832
+ init_css_engine();
1833
+ }
1834
+ });
1835
+
1836
+ // src/plugins/assets.ts
1837
+ import path5 from "path";
1838
+ import fs3 from "fs";
1839
+ import crypto from "crypto";
1840
+ function assetsPlugin(config) {
1841
+ return {
1842
+ name: "nasti:assets",
1843
+ resolveId(source) {
1844
+ if (source.endsWith("?url") || source.endsWith("?raw")) {
1845
+ return source;
1846
+ }
1847
+ return null;
1848
+ },
1849
+ load(id) {
1850
+ const ext = path5.extname(id.replace(/\?.*$/, ""));
1851
+ if (id.endsWith("?raw")) {
1852
+ const file = id.slice(0, -4);
1853
+ if (fs3.existsSync(file)) {
1854
+ const content = fs3.readFileSync(file, "utf-8");
1855
+ return `export default ${JSON.stringify(content)}`;
1856
+ }
1857
+ }
1858
+ if (id.endsWith("?url") || ASSET_EXTENSIONS.has(ext)) {
1859
+ const file = id.replace(/\?.*$/, "");
1860
+ if (!fs3.existsSync(file)) return null;
1861
+ if (config.command === "serve") {
1862
+ const url = "/" + path5.relative(config.root, file);
1863
+ return `export default ${JSON.stringify(url)}`;
1864
+ }
1865
+ const content = fs3.readFileSync(file);
1866
+ const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
1867
+ const basename = path5.basename(file, ext);
1868
+ const hashedName = `${config.build.assetsDir}/${basename}.${hash}${ext}`;
1869
+ return `export default ${JSON.stringify(config.base + hashedName)}`;
1870
+ }
1871
+ return null;
1872
+ }
1873
+ };
1874
+ }
1875
+ var ASSET_EXTENSIONS;
1876
+ var init_assets = __esm({
1877
+ "src/plugins/assets.ts"() {
577
1878
  "use strict";
578
1879
  ASSET_EXTENSIONS = /* @__PURE__ */ new Set([
579
1880
  ".png",
@@ -662,6 +1963,43 @@ function vuePlugin(config) {
662
1963
  }
663
1964
  return null;
664
1965
  },
1966
+ // 虚拟子模块必须有 load 钩子:build 下 Rolldown 否则会按字面路径读盘,
1967
+ // 抛 UNLOADABLE_DEPENDENCY(1.x Vue 生产构建因此直接失败)。
1968
+ // style 子块在这里编译成 CSS 字符串,交给 css 插件统一处理
1969
+ // (dev = <style> 注入 + HMR;build = CssEngine 抽取成 hashed .css)。
1970
+ async load(id) {
1971
+ const match = id.match(/(.+\.vue)\?vue&type=style(?:&index=(\d+))?/);
1972
+ if (!match) return null;
1973
+ const sfc = await loadVueCompiler();
1974
+ if (!sfc) return null;
1975
+ const [, filePath, indexStr] = match;
1976
+ let descriptor = descriptorCache.get(filePath);
1977
+ if (!descriptor) {
1978
+ try {
1979
+ const fs13 = await import("fs");
1980
+ const source = fs13.readFileSync(filePath, "utf-8");
1981
+ const parsed = sfc.parse(source, { filename: filePath });
1982
+ if (parsed.errors.length) return null;
1983
+ descriptor = parsed.descriptor;
1984
+ descriptorCache.set(filePath, descriptor);
1985
+ } catch {
1986
+ return null;
1987
+ }
1988
+ }
1989
+ const index2 = parseInt(indexStr ?? "0", 10);
1990
+ const style = descriptor.styles[index2];
1991
+ if (!style) return null;
1992
+ const scopeId = hashId(filePath);
1993
+ const result = await sfc.compileStyleAsync({
1994
+ source: style.content,
1995
+ filename: filePath,
1996
+ id: `data-v-${scopeId}`,
1997
+ scoped: style.scoped ?? false,
1998
+ // <style lang="scss|less|stylus"> 需经对应预处理器(缺省 undefined = 纯 CSS)
1999
+ preprocessLang: style.lang
2000
+ });
2001
+ return result.code;
2002
+ },
665
2003
  async transform(code, id) {
666
2004
  if (!VUE_FILE_RE.test(id) && !VUE_QUERY_RE.test(id)) return null;
667
2005
  const sfc = await loadVueCompiler();
@@ -670,7 +2008,7 @@ function vuePlugin(config) {
670
2008
  return null;
671
2009
  }
672
2010
  if (VUE_QUERY_RE.test(id)) {
673
- return handleVueSubBlock(id, sfc, descriptorCache, config);
2011
+ return null;
674
2012
  }
675
2013
  const { descriptor, errors } = sfc.parse(code, { filename: id });
676
2014
  if (errors.length) {
@@ -713,10 +2051,8 @@ __sfc__.render = render
713
2051
  }
714
2052
  if (descriptor.styles.length > 0) {
715
2053
  for (let i = 0; i < descriptor.styles.length; i++) {
716
- const style = descriptor.styles[i];
717
- const lang2 = style.lang ?? "css";
718
2054
  output += `
719
- import "${id}?vue&type=style&index=${i}&lang=${lang2}"
2055
+ import "${id}?vue&type=style&index=${i}&lang.css"
720
2056
  `;
721
2057
  }
722
2058
  }
@@ -762,41 +2098,6 @@ export default __sfc__
762
2098
  }
763
2099
  };
764
2100
  }
765
- async function handleVueSubBlock(id, sfc, cache, config) {
766
- const match = id.match(/(.+\.vue)\?vue&type=(\w+)(?:&index=(\d+))?(?:&lang=(\w+))?/);
767
- if (!match) return null;
768
- const [, filePath, type, indexStr, lang] = match;
769
- const descriptor = cache.get(filePath);
770
- if (!descriptor) return null;
771
- if (type === "style") {
772
- const index = parseInt(indexStr ?? "0", 10);
773
- const style = descriptor.styles[index];
774
- if (!style) return null;
775
- const scopeId = hashId(filePath);
776
- const result = await sfc.compileStyleAsync({
777
- source: style.content,
778
- filename: filePath,
779
- id: `data-v-${scopeId}`,
780
- scoped: style.scoped ?? false
781
- });
782
- const cssCode = JSON.stringify(result.code);
783
- return {
784
- code: `
785
- const css = ${cssCode};
786
- const style = document.createElement('style');
787
- style.setAttribute('data-v-${scopeId}', '');
788
- style.textContent = css;
789
- document.head.appendChild(style);
790
-
791
- if (import.meta.hot) {
792
- import.meta.hot.accept();
793
- import.meta.hot.prune(() => style.remove());
794
- }
795
- `
796
- };
797
- }
798
- return null;
799
- }
800
2101
  function hashId(filename) {
801
2102
  return crypto2.createHash("sha256").update(filename).digest("hex").slice(0, 8);
802
2103
  }
@@ -806,7 +2107,7 @@ var init_vue = __esm({
806
2107
  "use strict";
807
2108
  init_transformer();
808
2109
  VUE_FILE_RE = /\.vue$/;
809
- VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang=\w+)?/;
2110
+ VUE_QUERY_RE = /\.vue\?vue&type=(script|template|style)(&index=\d+)?(&lang[.=]\w+)?/;
810
2111
  compiler = null;
811
2112
  }
812
2113
  });
@@ -892,66 +2193,32 @@ window.$RefreshSig$ = () => (type) => type;
892
2193
  window.__vite_plugin_react_preamble_installed__ = true;
893
2194
  `.trim();
894
2195
  }
895
- });
896
-
897
- // src/core/env.ts
898
- import path7 from "path";
899
- import fs5 from "fs";
900
- function loadEnv(mode, root, prefixes) {
901
- const envFiles = [
902
- ".env",
903
- `.env.${mode}`,
904
- ".env.local",
905
- `.env.${mode}.local`
906
- ];
907
- const raw = {};
908
- for (const file of envFiles) {
909
- const filePath = path7.resolve(root, file);
910
- if (!fs5.existsSync(filePath)) continue;
911
- const content = fs5.readFileSync(filePath, "utf-8");
912
- for (const line of content.split("\n")) {
913
- const trimmed = line.trim();
914
- if (!trimmed || trimmed.startsWith("#")) continue;
915
- const eqIdx = trimmed.indexOf("=");
916
- if (eqIdx === -1) continue;
917
- const key = trimmed.slice(0, eqIdx).trim();
918
- let value = trimmed.slice(eqIdx + 1).trim();
919
- if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
920
- value = value.slice(1, -1);
921
- }
922
- raw[key] = value;
923
- }
924
- }
925
- const filtered = {};
926
- for (const [key, value] of Object.entries(raw)) {
927
- if (prefixes.some((prefix) => key.startsWith(prefix))) {
928
- filtered[key] = value;
929
- }
930
- }
931
- return filtered;
932
- }
933
- function buildEnvDefine(env, mode) {
934
- const define = {};
935
- for (const [key, value] of Object.entries(env)) {
936
- define[`import.meta.env.${key}`] = JSON.stringify(value);
937
- }
938
- define["import.meta.env.MODE"] = JSON.stringify(mode);
939
- define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
940
- define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
941
- define["import.meta.env.SSR"] = "false";
942
- return define;
943
- }
944
- function replaceEnvInCode(code, define) {
945
- let result = code;
946
- for (const [key, value] of Object.entries(define)) {
947
- const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
948
- result = result.replace(new RegExp(escaped, "g"), value);
949
- }
950
- return result;
2196
+ });
2197
+
2198
+ // src/plugins/builtins.ts
2199
+ function resolvePluginList(config, userPlugins, opts = {}) {
2200
+ const isServe = config.command === "serve";
2201
+ return [
2202
+ // vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
2203
+ ...config.framework === "vue" ? [vuePlugin(config)] : [],
2204
+ resolvePlugin(config),
2205
+ cssPlugin(config, opts.cssEngine, opts.consumer),
2206
+ assetsPlugin(config),
2207
+ ...isServe ? [htmlPlugin(config)] : [],
2208
+ ...userPlugins,
2209
+ // cssPostPlugin 最后(enforce: 'post' 语义):renderChunk 聚合抽取
2210
+ ...!isServe && opts.cssEngine ? [cssPostPlugin(config, opts.cssEngine)] : []
2211
+ ];
951
2212
  }
952
- var init_env = __esm({
953
- "src/core/env.ts"() {
2213
+ var init_builtins = __esm({
2214
+ "src/plugins/builtins.ts"() {
954
2215
  "use strict";
2216
+ init_resolve();
2217
+ init_css();
2218
+ init_css_post();
2219
+ init_assets();
2220
+ init_vue();
2221
+ init_html();
955
2222
  }
956
2223
  });
957
2224
 
@@ -976,8 +2243,11 @@ var init_plugin_container = __esm({
976
2243
  config;
977
2244
  ctx;
978
2245
  emittedFiles = /* @__PURE__ */ new Map();
979
- constructor(config) {
2246
+ /** Environment API:容器所属环境(未传时为 undefined,行为同 1.x client) */
2247
+ environment;
2248
+ constructor(config, environment) {
980
2249
  this.config = config;
2250
+ this.environment = environment;
981
2251
  this.plugins = sortPlugins(config.plugins);
982
2252
  this.ctx = this.createContext();
983
2253
  }
@@ -998,7 +2268,8 @@ var init_plugin_container = __esm({
998
2268
  },
999
2269
  getModuleInfo(_id) {
1000
2270
  return null;
1001
- }
2271
+ },
2272
+ environment: container.environment
1002
2273
  };
1003
2274
  }
1004
2275
  /** 返回所有通过 emitFile() 输出的文件 */
@@ -1020,13 +2291,14 @@ var init_plugin_container = __esm({
1020
2291
  }
1021
2292
  }
1022
2293
  async resolveId(source, importer, options = {}) {
2294
+ const ssr = this.environment?.consumer === "server";
1023
2295
  for (const plugin of this.plugins) {
1024
2296
  if (!plugin.resolveId) continue;
1025
2297
  const result = await plugin.resolveId.call(
1026
2298
  this.ctx,
1027
2299
  source,
1028
2300
  importer ?? void 0,
1029
- { isEntry: options.isEntry ?? false, ssr: false }
2301
+ { isEntry: options.isEntry ?? false, ssr }
1030
2302
  );
1031
2303
  if (result != null) return result;
1032
2304
  }
@@ -1075,125 +2347,600 @@ var init_plugin_container = __esm({
1075
2347
  }
1076
2348
  });
1077
2349
 
2350
+ // src/core/module-graph.ts
2351
+ var ModuleGraph;
2352
+ var init_module_graph = __esm({
2353
+ "src/core/module-graph.ts"() {
2354
+ "use strict";
2355
+ ModuleGraph = class {
2356
+ urlToModuleMap = /* @__PURE__ */ new Map();
2357
+ idToModuleMap = /* @__PURE__ */ new Map();
2358
+ fileToModulesMap = /* @__PURE__ */ new Map();
2359
+ getModuleByUrl(url) {
2360
+ return this.urlToModuleMap.get(url);
2361
+ }
2362
+ getModuleById(id) {
2363
+ return this.idToModuleMap.get(id);
2364
+ }
2365
+ getModulesByFile(file) {
2366
+ return this.fileToModulesMap.get(file);
2367
+ }
2368
+ async ensureEntryFromUrl(url) {
2369
+ let mod = this.urlToModuleMap.get(url);
2370
+ if (mod) return mod;
2371
+ mod = this.createModule(url);
2372
+ this.urlToModuleMap.set(url, mod);
2373
+ return mod;
2374
+ }
2375
+ createModule(url, id) {
2376
+ const mod = {
2377
+ id: id ?? url,
2378
+ file: null,
2379
+ url,
2380
+ type: url.endsWith(".css") ? "css" : "js",
2381
+ importers: /* @__PURE__ */ new Set(),
2382
+ importedModules: /* @__PURE__ */ new Set(),
2383
+ acceptedHmrDeps: /* @__PURE__ */ new Set(),
2384
+ transformResult: null,
2385
+ lastHMRTimestamp: 0,
2386
+ isSelfAccepting: false
2387
+ };
2388
+ this.idToModuleMap.set(mod.id, mod);
2389
+ return mod;
2390
+ }
2391
+ /** 注册文件路径到模块的映射 */
2392
+ registerModule(mod, file) {
2393
+ mod.file = file;
2394
+ let mods = this.fileToModulesMap.get(file);
2395
+ if (!mods) {
2396
+ mods = /* @__PURE__ */ new Set();
2397
+ this.fileToModulesMap.set(file, mods);
2398
+ }
2399
+ mods.add(mod);
2400
+ }
2401
+ /**
2402
+ * Reindex a module under a plugin-provided canonical id (e.g. a `\0virtual:foo`
2403
+ * id returned from `resolveId`). Plugins look up their own virtual modules via
2404
+ * `getModuleById(RESOLVED_ID)` to invalidate them on watcher events; without
2405
+ * this remap they'd never find the node because `ensureEntryFromUrl` keys by
2406
+ * the public URL only.
2407
+ */
2408
+ setModuleId(mod, id) {
2409
+ if (mod.id === id) return;
2410
+ this.idToModuleMap.delete(mod.id);
2411
+ mod.id = id;
2412
+ this.idToModuleMap.set(id, mod);
2413
+ }
2414
+ /** 更新模块依赖关系 */
2415
+ updateModuleImports(mod, importedIds) {
2416
+ for (const imported of mod.importedModules) {
2417
+ imported.importers.delete(mod);
2418
+ }
2419
+ mod.importedModules.clear();
2420
+ for (const id of importedIds) {
2421
+ const importedMod = this.idToModuleMap.get(id);
2422
+ if (importedMod) {
2423
+ mod.importedModules.add(importedMod);
2424
+ importedMod.importers.add(mod);
2425
+ }
2426
+ }
2427
+ }
2428
+ /** 使模块的转换缓存失效 */
2429
+ invalidateModule(mod) {
2430
+ mod.transformResult = null;
2431
+ mod.lastHMRTimestamp = Date.now();
2432
+ }
2433
+ /** 使所有模块缓存失效 */
2434
+ invalidateAll() {
2435
+ for (const mod of this.idToModuleMap.values()) {
2436
+ this.invalidateModule(mod);
2437
+ }
2438
+ }
2439
+ /** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
2440
+ getHmrBoundaries(mod) {
2441
+ const boundaries = [];
2442
+ const visited = /* @__PURE__ */ new Set();
2443
+ const propagate = (node, via) => {
2444
+ if (visited.has(node)) return true;
2445
+ visited.add(node);
2446
+ if (node.isSelfAccepting) {
2447
+ boundaries.push({ boundary: node, acceptedVia: via });
2448
+ return true;
2449
+ }
2450
+ if (node.acceptedHmrDeps.has(via)) {
2451
+ boundaries.push({ boundary: node, acceptedVia: via });
2452
+ return true;
2453
+ }
2454
+ if (node.importers.size === 0) return false;
2455
+ for (const importer of node.importers) {
2456
+ if (!propagate(importer, node)) return false;
2457
+ }
2458
+ return true;
2459
+ };
2460
+ if (mod.isSelfAccepting) {
2461
+ boundaries.push({ boundary: mod, acceptedVia: mod });
2462
+ return boundaries;
2463
+ }
2464
+ for (const importer of mod.importers) {
2465
+ if (!propagate(importer, mod)) {
2466
+ return [];
2467
+ }
2468
+ }
2469
+ return boundaries;
2470
+ }
2471
+ };
2472
+ }
2473
+ });
2474
+
2475
+ // src/core/hot-channel.ts
2476
+ function createNoopHotChannel() {
2477
+ return {
2478
+ send() {
2479
+ },
2480
+ on() {
2481
+ },
2482
+ off() {
2483
+ },
2484
+ listen() {
2485
+ },
2486
+ close() {
2487
+ },
2488
+ setInvokeHandler() {
2489
+ }
2490
+ };
2491
+ }
2492
+ function createWsHotChannel(ws) {
2493
+ const listeners = /* @__PURE__ */ new Map();
2494
+ let invokeHandlers;
2495
+ return {
2496
+ send(payload) {
2497
+ ws.send(payload);
2498
+ },
2499
+ on(event, listener) {
2500
+ let set = listeners.get(event);
2501
+ if (!set) listeners.set(event, set = /* @__PURE__ */ new Set());
2502
+ set.add(listener);
2503
+ },
2504
+ off(event, listener) {
2505
+ listeners.get(event)?.delete(listener);
2506
+ },
2507
+ listen() {
2508
+ },
2509
+ close() {
2510
+ ws.close();
2511
+ },
2512
+ setInvokeHandler(handlers) {
2513
+ invokeHandlers = handlers;
2514
+ void invokeHandlers;
2515
+ }
2516
+ };
2517
+ }
2518
+ var init_hot_channel = __esm({
2519
+ "src/core/hot-channel.ts"() {
2520
+ "use strict";
2521
+ }
2522
+ });
2523
+
2524
+ // src/core/environment.ts
2525
+ function resolveEnvironmentPlugins(environment, plugins) {
2526
+ return plugins.filter((p) => {
2527
+ if (!p.applyToEnvironment) return true;
2528
+ try {
2529
+ return p.applyToEnvironment(environment);
2530
+ } catch (err) {
2531
+ environment.config.logger.error(
2532
+ `[nasti] plugin "${p.name}" applyToEnvironment threw: ${err.message}`,
2533
+ { error: err }
2534
+ );
2535
+ return false;
2536
+ }
2537
+ });
2538
+ }
2539
+ var debug2, NastiEnvironment;
2540
+ var init_environment = __esm({
2541
+ "src/core/environment.ts"() {
2542
+ "use strict";
2543
+ init_plugin_container();
2544
+ init_module_graph();
2545
+ init_hot_channel();
2546
+ init_debug();
2547
+ debug2 = createDebugger("nasti:environment");
2548
+ NastiEnvironment = class {
2549
+ name;
2550
+ consumer;
2551
+ mode;
2552
+ config;
2553
+ options;
2554
+ hot;
2555
+ /** applyToEnvironment 过滤后的插件(init() 后可用) */
2556
+ plugins = [];
2557
+ /** per-env 插件容器(init() 后可用;dev 管线使用) */
2558
+ pluginContainer = null;
2559
+ /** per-env 模块图(dev 管线使用) */
2560
+ moduleGraph;
2561
+ candidatePlugins;
2562
+ initialized = false;
2563
+ constructor(name, config, init = {}) {
2564
+ const options = config.environments[name];
2565
+ if (!options) {
2566
+ throw new Error(
2567
+ `[nasti] unknown environment "${name}" \u2014 declare it in config.environments`
2568
+ );
2569
+ }
2570
+ this.name = name;
2571
+ this.consumer = options.consumer;
2572
+ this.mode = init.mode ?? (config.command === "build" ? "build" : "dev");
2573
+ this.config = config;
2574
+ this.options = options;
2575
+ this.hot = init.hot ?? createNoopHotChannel();
2576
+ this.moduleGraph = new ModuleGraph();
2577
+ this.candidatePlugins = init.plugins ?? config.plugins;
2578
+ }
2579
+ /** 过滤插件并建 per-env PluginContainer */
2580
+ async init() {
2581
+ if (this.initialized) return;
2582
+ this.initialized = true;
2583
+ this.plugins = resolveEnvironmentPlugins(this, this.candidatePlugins);
2584
+ this.pluginContainer = new PluginContainer(
2585
+ { ...this.config, plugins: this.plugins },
2586
+ this
2587
+ );
2588
+ debug2?.(`env "${this.name}" initialized (${this.plugins.length} plugins)`);
2589
+ }
2590
+ async close() {
2591
+ await this.hot.close?.();
2592
+ }
2593
+ };
2594
+ }
2595
+ });
2596
+
2597
+ // src/core/env.ts
2598
+ import path7 from "path";
2599
+ import fs5 from "fs";
2600
+ function loadEnv(mode, root, prefixes) {
2601
+ const envFiles = [
2602
+ ".env",
2603
+ `.env.${mode}`,
2604
+ ".env.local",
2605
+ `.env.${mode}.local`
2606
+ ];
2607
+ const raw = {};
2608
+ for (const file of envFiles) {
2609
+ const filePath = path7.resolve(root, file);
2610
+ if (!fs5.existsSync(filePath)) continue;
2611
+ const content = fs5.readFileSync(filePath, "utf-8");
2612
+ for (const line of content.split("\n")) {
2613
+ const trimmed = line.trim();
2614
+ if (!trimmed || trimmed.startsWith("#")) continue;
2615
+ const eqIdx = trimmed.indexOf("=");
2616
+ if (eqIdx === -1) continue;
2617
+ const key = trimmed.slice(0, eqIdx).trim();
2618
+ let value = trimmed.slice(eqIdx + 1).trim();
2619
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2620
+ value = value.slice(1, -1);
2621
+ }
2622
+ raw[key] = value;
2623
+ }
2624
+ }
2625
+ const filtered = {};
2626
+ for (const [key, value] of Object.entries(raw)) {
2627
+ if (prefixes.some((prefix) => key.startsWith(prefix))) {
2628
+ filtered[key] = value;
2629
+ }
2630
+ }
2631
+ return filtered;
2632
+ }
2633
+ function buildEnvDefine(env, mode, overrides = {}) {
2634
+ const define = {};
2635
+ for (const [key, value] of Object.entries(env)) {
2636
+ define[`import.meta.env.${key}`] = JSON.stringify(value);
2637
+ }
2638
+ define["import.meta.env.MODE"] = JSON.stringify(mode);
2639
+ define["import.meta.env.DEV"] = mode !== "production" ? "true" : "false";
2640
+ define["import.meta.env.PROD"] = mode === "production" ? "true" : "false";
2641
+ define["import.meta.env.SSR"] = "false";
2642
+ return { ...define, ...overrides };
2643
+ }
2644
+ function ssrDefineOverrides(consumer) {
2645
+ return { "import.meta.env.SSR": consumer === "server" ? "true" : "false" };
2646
+ }
2647
+ function replaceEnvInCode(code, define) {
2648
+ let result = code;
2649
+ for (const [key, value] of Object.entries(define)) {
2650
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2651
+ result = result.replace(new RegExp(escaped, "g"), value);
2652
+ }
2653
+ return result;
2654
+ }
2655
+ var init_env = __esm({
2656
+ "src/core/env.ts"() {
2657
+ "use strict";
2658
+ }
2659
+ });
2660
+
2661
+ // src/build/reporter.ts
2662
+ import path8 from "path";
2663
+ import { gzipSync } from "zlib";
2664
+ import pc3 from "picocolors";
2665
+ async function tryNativeReporterPlugin(config, logger) {
2666
+ try {
2667
+ const { viteReporterPlugin } = await import("rolldown/experimental");
2668
+ if (typeof viteReporterPlugin !== "function") return null;
2669
+ return viteReporterPlugin({
2670
+ root: config.root,
2671
+ isTty: process.stdout.isTTY ?? false,
2672
+ isLib: false,
2673
+ assetsDir: config.build.assetsDir,
2674
+ chunkLimit: config.build.chunkSizeWarningLimit,
2675
+ // 大 chunk 警告由 JS 侧 warnLargeChunks() 经 logger.warn 输出,
2676
+ // 原生侧只产 info 级表格,避免警告被 logLevel 过滤吞掉
2677
+ warnLargeChunks: false,
2678
+ reportCompressedSize: config.build.reportCompressedSize,
2679
+ logInfo: (msg) => logger.info(msg)
2680
+ });
2681
+ } catch (err) {
2682
+ debug3?.(`native viteReporterPlugin unavailable, falling back to JS table: ${err}`);
2683
+ return null;
2684
+ }
2685
+ }
2686
+ function displaySize(bytes) {
2687
+ return `${numberFormatter.format(bytes / 1e3)} kB`;
2688
+ }
2689
+ function byteLength(content) {
2690
+ if (content == null) return 0;
2691
+ return typeof content === "string" ? Buffer.byteLength(content) : content.byteLength;
2692
+ }
2693
+ function reportBuildOutput(output, config, logger) {
2694
+ const entries = [];
2695
+ const compressed = config.build.reportCompressedSize;
2696
+ for (const file of output) {
2697
+ const content = file.type === "chunk" ? file.code : file.source;
2698
+ const size = byteLength(content);
2699
+ let gzip = null;
2700
+ if (compressed && content != null) {
2701
+ gzip = gzipSync(typeof content === "string" ? Buffer.from(content) : content).byteLength;
2702
+ }
2703
+ const ext = path8.extname(file.fileName);
2704
+ const group = file.type === "chunk" ? "js" : ext === ".css" ? "css" : "assets";
2705
+ entries.push({ name: file.fileName, size, gzip, group });
2706
+ }
2707
+ const groupOrder = { assets: 0, css: 1, js: 2 };
2708
+ entries.sort((a, b) => groupOrder[a.group] - groupOrder[b.group] || a.size - b.size);
2709
+ const outDirPrefix = `${config.build.outDir.replace(/\/$/, "")}/`;
2710
+ const maxNameLen = Math.max(...entries.map((e) => (outDirPrefix + e.name).length), 0);
2711
+ const maxSizeLen = Math.max(...entries.map((e) => displaySize(e.size).length), 0);
2712
+ const groupColor = { assets: pc3.green, css: pc3.magenta, js: pc3.cyan };
2713
+ for (const e of entries) {
2714
+ const color = groupColor[e.group];
2715
+ const namePart = pc3.dim(outDirPrefix) + color(e.name.padEnd(maxNameLen - outDirPrefix.length));
2716
+ const sizePart = pc3.dim(pc3.bold(displaySize(e.size).padStart(maxSizeLen)));
2717
+ const gzipPart = e.gzip != null ? pc3.dim(` \u2502 gzip: ${displaySize(e.gzip)}`) : "";
2718
+ logger.info(`${namePart} ${sizePart}${gzipPart}`);
2719
+ }
2720
+ }
2721
+ function warnLargeChunks(output, config, logger) {
2722
+ const limit = config.build.chunkSizeWarningLimit;
2723
+ const large = output.filter(
2724
+ (f) => f.type === "chunk" && byteLength(f.code) / 1e3 > limit
2725
+ );
2726
+ if (large.length === 0) return;
2727
+ logger.warn(
2728
+ pc3.yellow(
2729
+ `
2730
+ (!) Some chunks are larger than ${limit} kB after minification. Consider:
2731
+ - Using dynamic import() to code-split the application
2732
+ - Configuring build.rolldownOptions.output.advancedChunks to isolate large dependencies
2733
+ - Adjusting build.chunkSizeWarningLimit to silence this warning`
2734
+ )
2735
+ );
2736
+ }
2737
+ var debug3, numberFormatter;
2738
+ var init_reporter = __esm({
2739
+ "src/build/reporter.ts"() {
2740
+ "use strict";
2741
+ init_debug();
2742
+ debug3 = createDebugger("nasti:reporter");
2743
+ numberFormatter = new Intl.NumberFormat("en", {
2744
+ maximumFractionDigits: 2,
2745
+ minimumFractionDigits: 2
2746
+ });
2747
+ }
2748
+ });
2749
+
1078
2750
  // src/build/index.ts
1079
2751
  var build_exports = {};
1080
2752
  __export(build_exports, {
1081
- build: () => build
2753
+ build: () => build,
2754
+ getRolldownOptions: () => getRolldownOptions,
2755
+ resolveClientEntries: () => resolveClientEntries,
2756
+ toRolldownPlugins: () => toRolldownPlugins
1082
2757
  });
1083
- import path8 from "path";
2758
+ import path9 from "path";
1084
2759
  import fs6 from "fs";
2760
+ import { builtinModules } from "module";
1085
2761
  import { rolldown } from "rolldown";
1086
- import pc from "picocolors";
1087
- async function build(inlineConfig = {}) {
1088
- const config = await resolveConfig(inlineConfig, "build");
1089
- const startTime = performance.now();
1090
- console.log(pc.cyan("\n\u{1F528} nasti build") + pc.dim(` v${"1.7.1"}`));
1091
- console.log(pc.dim(` root: ${config.root}`));
1092
- console.log(pc.dim(` mode: ${config.mode}`));
1093
- const outDir = path8.resolve(config.root, config.build.outDir);
1094
- if (config.build.emptyOutDir && fs6.existsSync(outDir)) {
1095
- fs6.rmSync(outDir, { recursive: true, force: true });
1096
- }
1097
- fs6.mkdirSync(outDir, { recursive: true });
1098
- const html = await readHtmlFile(config.root);
1099
- let entryPoints = [];
2762
+ import pc4 from "picocolors";
2763
+ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
2764
+ const config = environment.config;
2765
+ const envOptions = environment.options;
2766
+ const isServer = environment.consumer === "server";
2767
+ const outDir = path9.resolve(config.root, envOptions.build.outDir);
2768
+ const assetsDir = envOptions.build.assetsDir;
2769
+ const { output: userOutput, transform: userTransform, ...restInputOptions } = envOptions.build.rolldownOptions;
2770
+ const vueDefine = config.framework === "vue" ? {
2771
+ __VUE_OPTIONS_API__: "true",
2772
+ __VUE_PROD_DEVTOOLS__: "false",
2773
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false"
2774
+ } : {};
2775
+ const env = loadEnv(config.mode, config.root, config.envPrefix);
2776
+ const envDefine = buildEnvDefine(env, config.mode, ssrDefineOverrides(environment.consumer));
2777
+ const mergedDefine = { ...vueDefine, ...userTransform?.define ?? {}, ...envDefine };
2778
+ const inputOptions = {
2779
+ ...restInputOptions,
2780
+ input: entryPoints,
2781
+ transform: { ...userTransform, define: mergedDefine },
2782
+ plugins: rolldownPlugins,
2783
+ ...isServer ? {
2784
+ platform: restInputOptions.platform ?? "node",
2785
+ resolve: {
2786
+ conditionNames: envOptions.resolve.conditions,
2787
+ mainFields: envOptions.resolve.mainFields,
2788
+ ...restInputOptions.resolve
2789
+ },
2790
+ // server 产物:node 内建恒外部化;bare specifier 默认外部化
2791
+ //(同 Vite ssr.external 默认 —— 依赖由 node_modules 运行时解析),
2792
+ // 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
2793
+ external: restInputOptions.external ?? ((id) => {
2794
+ if (NODE_BUILTINS.has(id)) return true;
2795
+ return !id.startsWith(".") && !path9.isAbsolute(id) && !id.startsWith("\0");
2796
+ })
2797
+ } : {}
2798
+ };
2799
+ const outputOptions = isServer ? {
2800
+ format: "esm",
2801
+ sourcemap: !!envOptions.build.sourcemap,
2802
+ minify: !!envOptions.build.minify,
2803
+ entryFileNames: "[name].js",
2804
+ chunkFileNames: "chunks/[name]-[hash].js",
2805
+ assetFileNames: `${assetsDir}/[name].[hash][extname]`,
2806
+ ...userOutput,
2807
+ dir: outDir
2808
+ } : {
2809
+ format: "esm",
2810
+ sourcemap: !!envOptions.build.sourcemap,
2811
+ minify: !!envOptions.build.minify,
2812
+ entryFileNames: `${assetsDir}/[name].[hash].js`,
2813
+ chunkFileNames: `${assetsDir}/[name].[hash].js`,
2814
+ assetFileNames: `${assetsDir}/[name].[hash][extname]`,
2815
+ // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
2816
+ ...userOutput,
2817
+ // dir 始终由 Nasti 掌管 —— HTML 改写依赖固定的产物目录,故放在最后强制生效
2818
+ dir: outDir
2819
+ };
2820
+ return { inputOptions, outputOptions, outDir };
2821
+ }
2822
+ function toRolldownPlugins(plugins) {
2823
+ return plugins.map((p) => ({
2824
+ name: p.name,
2825
+ resolveId: p.resolveId,
2826
+ load: p.load,
2827
+ transform: p.transform,
2828
+ buildStart: p.buildStart,
2829
+ buildEnd: p.buildEnd,
2830
+ // closeBundle 在 bundle.close() 时触发 —— PWA manifest/SW 等终态产物依赖
2831
+ closeBundle: p.closeBundle,
2832
+ renderChunk: p.renderChunk,
2833
+ augmentChunkHash: p.augmentChunkHash,
2834
+ generateBundle: p.generateBundle
2835
+ }));
2836
+ }
2837
+ function resolveClientEntries(config, html) {
2838
+ const entryPoints = [];
1100
2839
  if (html) {
1101
2840
  const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
1102
2841
  for (const match of scriptMatches) {
1103
2842
  const src = match[1];
1104
2843
  if (src && !src.startsWith("http")) {
1105
- entryPoints.push(path8.resolve(config.root, src.replace(/^\//, "")));
2844
+ entryPoints.push(path9.resolve(config.root, src.replace(/^\//, "")));
1106
2845
  }
1107
2846
  }
1108
2847
  }
1109
2848
  if (entryPoints.length === 0) {
1110
2849
  const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
1111
2850
  for (const entry of fallbackEntries) {
1112
- const fullPath = path8.resolve(config.root, entry);
2851
+ const fullPath = path9.resolve(config.root, entry);
1113
2852
  if (fs6.existsSync(fullPath)) {
1114
2853
  entryPoints.push(fullPath);
1115
2854
  break;
1116
2855
  }
1117
2856
  }
1118
2857
  }
1119
- if (entryPoints.length === 0) {
1120
- throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
1121
- }
1122
- const builtinPlugins = [
1123
- ...config.framework === "vue" ? [vuePlugin(config)] : [],
1124
- resolvePlugin(config),
1125
- cssPlugin(config),
1126
- assetsPlugin(config)
1127
- ];
1128
- const allPlugins = [...builtinPlugins, ...config.plugins];
1129
- const pluginContainer = new PluginContainer(config);
1130
- await pluginContainer.buildStart();
1131
- const oxcTransformPlugin = {
2858
+ return entryPoints;
2859
+ }
2860
+ function createOxcTransformPlugin(config, environment) {
2861
+ return {
1132
2862
  name: "nasti:oxc-transform",
1133
2863
  transform(code, id) {
1134
2864
  if (!shouldTransform(id)) return null;
1135
2865
  const result = transformCode(id, code, {
1136
- sourcemap: !!config.build.sourcemap,
2866
+ sourcemap: !!environment.options.build.sourcemap,
1137
2867
  jsxRuntime: "automatic",
1138
2868
  jsxImportSource: config.framework === "vue" ? "vue" : "react"
1139
2869
  });
1140
2870
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
1141
2871
  }
1142
2872
  };
1143
- const env = loadEnv(config.mode, config.root, config.envPrefix);
1144
- const envDefine = buildEnvDefine(env, config.mode);
1145
- const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
1146
- const vueDefine = config.framework === "vue" ? {
1147
- __VUE_OPTIONS_API__: "true",
1148
- __VUE_PROD_DEVTOOLS__: "false",
1149
- __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false"
1150
- } : {};
1151
- const mergedDefine = { ...vueDefine, ...userTransform?.define ?? {}, ...envDefine };
1152
- const bundle = await rolldown({
1153
- ...restInputOptions,
1154
- input: entryPoints,
1155
- transform: { ...userTransform, define: mergedDefine },
1156
- plugins: [
1157
- oxcTransformPlugin,
1158
- // 转换 Nasti 插件为 Rolldown 插件格式
1159
- ...allPlugins.map((p) => ({
1160
- name: p.name,
1161
- resolveId: p.resolveId,
1162
- load: p.load,
1163
- transform: p.transform,
1164
- buildStart: p.buildStart,
1165
- buildEnd: p.buildEnd,
1166
- // Forward `closeBundle` to Rolldown — it invokes the hook during
1167
- // `bundle.close()` below. This is the hook Vite plugins (e.g. PWA
1168
- // manifest/SW writers) rely on for final-stage artifact emission.
1169
- closeBundle: p.closeBundle
1170
- }))
1171
- ]
1172
- });
1173
- const { output } = await bundle.write({
1174
- format: "esm",
1175
- sourcemap: !!config.build.sourcemap,
1176
- minify: !!config.build.minify,
1177
- entryFileNames: "assets/[name].[hash].js",
1178
- chunkFileNames: "assets/[name].[hash].js",
1179
- assetFileNames: "assets/[name].[hash][extname]",
1180
- // 用户可覆盖默认输出:代码拆分(advancedChunks / codeSplitting)、chunk 命名等
1181
- ...userOutput,
1182
- // dir 始终由 Nasti 掌管 —— 下方 HTML 改写依赖固定的产物目录,故放在最后强制生效
1183
- dir: outDir
1184
- });
1185
- await bundle.close();
1186
- await pluginContainer.buildEnd();
1187
- for (const ef of pluginContainer.getEmittedFiles()) {
1188
- const dest = path8.resolve(outDir, ef.fileName);
1189
- fs6.mkdirSync(path8.dirname(dest), { recursive: true });
1190
- fs6.writeFileSync(dest, ef.source);
2873
+ }
2874
+ async function build(inlineConfig = {}) {
2875
+ const config = await resolveConfig(inlineConfig, "build");
2876
+ const logger = config.logger;
2877
+ const startTime = performance.now();
2878
+ logger.info(
2879
+ pc4.cyan(`
2880
+ nasti v${"2.0.0"} `) + pc4.green(`building for ${config.mode}...`)
2881
+ );
2882
+ debug4?.(`root: ${config.root}`);
2883
+ const buildableNames = Object.keys(config.environments).filter(
2884
+ (name) => name === "client" || config.environments[name].entry.length > 0
2885
+ );
2886
+ buildableNames.sort((a, b) => a === "client" ? -1 : b === "client" ? 1 : 0);
2887
+ const environments = {};
2888
+ let clientOutput = [];
2889
+ for (const name of buildableNames) {
2890
+ const output = name === "client" ? await buildClientEnvironment(config) : await buildServerEnvironment(config, name);
2891
+ environments[name] = output;
2892
+ if (name === "client") clientOutput = output;
2893
+ if (buildableNames.length > 1) {
2894
+ debug4?.(`environment "${name}" built (${output.length} files)`);
2895
+ }
2896
+ }
2897
+ const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
2898
+ const totalSize = Object.values(environments).flat().reduce((sum, chunk) => {
2899
+ const content = chunk.type === "chunk" ? chunk.code : chunk.source;
2900
+ if (content == null) return sum;
2901
+ return sum + (typeof content === "string" ? Buffer.byteLength(content) : content.byteLength);
2902
+ }, 0);
2903
+ const fileCount = Object.values(environments).flat().length;
2904
+ const envSuffix = buildableNames.length > 1 ? ` (${buildableNames.join(" + ")})` : "";
2905
+ logger.info(pc4.green(`\u2713 built in ${elapsed}s`) + pc4.dim(envSuffix));
2906
+ logger.info(pc4.dim(` ${fileCount} files, ${displaySize(totalSize)} total \u2192 ${config.build.outDir}/`));
2907
+ return { output: clientOutput, environments };
2908
+ }
2909
+ async function buildClientEnvironment(config) {
2910
+ const logger = config.logger;
2911
+ const outDir = path9.resolve(config.root, config.build.outDir);
2912
+ if (config.build.emptyOutDir && fs6.existsSync(outDir)) {
2913
+ fs6.rmSync(outDir, { recursive: true, force: true });
2914
+ }
2915
+ fs6.mkdirSync(outDir, { recursive: true });
2916
+ const html = await readHtmlFile(config.root);
2917
+ const entryPoints = resolveClientEntries(config, html);
2918
+ if (entryPoints.length === 0) {
2919
+ throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
1191
2920
  }
2921
+ const cssEngine = createCssEngine();
2922
+ const pluginList = resolvePluginList(config, config.plugins, { cssEngine });
2923
+ const clientEnv = new NastiEnvironment("client", { ...config, plugins: pluginList }, {
2924
+ mode: "build",
2925
+ plugins: pluginList
2926
+ });
2927
+ await clientEnv.init();
2928
+ const allPlugins = clientEnv.plugins;
2929
+ const nativeReporter = config.logLevel === "silent" ? null : await tryNativeReporterPlugin(config, logger);
2930
+ const rolldownPlugins = [
2931
+ createOxcTransformPlugin(config, clientEnv),
2932
+ ...toRolldownPlugins(allPlugins),
2933
+ ...nativeReporter ? [nativeReporter] : []
2934
+ ];
2935
+ const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
2936
+ const bundle2 = await rolldown(inputOptions);
2937
+ const { output } = await bundle2.write(outputOptions);
2938
+ await bundle2.close();
1192
2939
  if (html) {
1193
2940
  let processedHtml = html;
1194
- const htmlPlugin_ = htmlPlugin(config);
1195
- if (htmlPlugin_.transformIndexHtml) {
1196
- const result = await htmlPlugin_.transformIndexHtml(processedHtml);
2941
+ const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
2942
+ for (const p of htmlPlugins) {
2943
+ const result = await p.transformIndexHtml(processedHtml);
1197
2944
  if (typeof result === "string") {
1198
2945
  processedHtml = result;
1199
2946
  } else if (result && "html" in result) {
@@ -1202,174 +2949,98 @@ async function build(inlineConfig = {}) {
1202
2949
  processedHtml = processHtml(processedHtml, result);
1203
2950
  }
1204
2951
  }
2952
+ processedHtml = injectCssLinks(processedHtml, cssEngine, config);
1205
2953
  for (const chunk of output) {
1206
2954
  if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
1207
- const originalEntry = path8.relative(config.root, chunk.facadeModuleId);
2955
+ const originalEntry = path9.relative(config.root, chunk.facadeModuleId);
1208
2956
  processedHtml = processedHtml.replace(
1209
2957
  new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
1210
2958
  `$1${config.base}${chunk.fileName}$3`
1211
2959
  );
1212
2960
  }
1213
2961
  }
1214
- fs6.writeFileSync(path8.resolve(outDir, "index.html"), processedHtml);
2962
+ fs6.writeFileSync(path9.resolve(outDir, "index.html"), processedHtml);
1215
2963
  }
1216
- const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
1217
- const totalSize = output.reduce((sum, chunk) => {
1218
- if (chunk.type === "chunk" && chunk.code) return sum + chunk.code.length;
1219
- return sum;
1220
- }, 0);
1221
- console.log(pc.green(`
1222
- \u2713 Built in ${elapsed}s`));
1223
- console.log(pc.dim(` ${output.length} files, ${formatSize(totalSize)} total`));
1224
- console.log(pc.dim(` output: ${config.build.outDir}/
1225
- `));
1226
- return { output };
1227
- }
1228
- function formatSize(bytes) {
1229
- if (bytes < 1024) return `${bytes} B`;
1230
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} kB`;
1231
- return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
2964
+ if (!nativeReporter && config.logLevel !== "silent") {
2965
+ reportBuildOutput(output, config, logger);
2966
+ }
2967
+ warnLargeChunks(output, config, logger);
2968
+ return output;
2969
+ }
2970
+ async function buildServerEnvironment(config, name) {
2971
+ const envOptions = config.environments[name];
2972
+ const logger = config.logger;
2973
+ for (const entry of envOptions.entry) {
2974
+ if (!fs6.existsSync(entry)) {
2975
+ throw new Error(`[nasti] environment "${name}" entry not found: ${entry}`);
2976
+ }
2977
+ }
2978
+ const pluginList = resolvePluginList(config, config.plugins, { consumer: envOptions.consumer });
2979
+ const environment = new NastiEnvironment(name, { ...config, plugins: pluginList }, {
2980
+ mode: "build",
2981
+ plugins: pluginList
2982
+ });
2983
+ await environment.init();
2984
+ const rolldownPlugins = [
2985
+ createOxcTransformPlugin(config, environment),
2986
+ ...toRolldownPlugins(environment.plugins)
2987
+ ];
2988
+ const { inputOptions, outputOptions, outDir } = getRolldownOptions(
2989
+ environment,
2990
+ envOptions.entry,
2991
+ rolldownPlugins
2992
+ );
2993
+ if (envOptions.build.emptyOutDir && fs6.existsSync(outDir)) {
2994
+ fs6.rmSync(outDir, { recursive: true, force: true });
2995
+ }
2996
+ fs6.mkdirSync(outDir, { recursive: true });
2997
+ const bundle2 = await rolldown(inputOptions);
2998
+ const { output } = await bundle2.write(outputOptions);
2999
+ await bundle2.close();
3000
+ logger.info(
3001
+ pc4.dim(` [${name}] `) + output.map((o) => path9.join(envOptions.build.outDir, o.fileName)).join(pc4.dim(", "))
3002
+ );
3003
+ return output;
3004
+ }
3005
+ function injectCssLinks(html, cssEngine, config) {
3006
+ const cssLinkTags = [];
3007
+ if (cssEngine.singleFileName) {
3008
+ cssLinkTags.push({
3009
+ tag: "link",
3010
+ attrs: { rel: "stylesheet", href: config.base + cssEngine.singleFileName },
3011
+ injectTo: "head"
3012
+ });
3013
+ } else {
3014
+ for (const files of cssEngine.entryCss.values()) {
3015
+ for (const file of files) {
3016
+ cssLinkTags.push({
3017
+ tag: "link",
3018
+ attrs: { rel: "stylesheet", href: config.base + file },
3019
+ injectTo: "head"
3020
+ });
3021
+ }
3022
+ }
3023
+ }
3024
+ return cssLinkTags.length > 0 ? processHtml(html, cssLinkTags) : html;
1232
3025
  }
1233
3026
  function escapeRegExp(string) {
1234
3027
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1235
3028
  }
3029
+ var debug4, NODE_BUILTINS;
1236
3030
  var init_build = __esm({
1237
- "src/build/index.ts"() {
1238
- "use strict";
1239
- init_config();
1240
- init_resolve();
1241
- init_css();
1242
- init_assets();
1243
- init_vue();
1244
- init_html();
1245
- init_transformer();
1246
- init_env();
1247
- init_plugin_container();
1248
- }
1249
- });
1250
-
1251
- // src/core/module-graph.ts
1252
- var ModuleGraph;
1253
- var init_module_graph = __esm({
1254
- "src/core/module-graph.ts"() {
1255
- "use strict";
1256
- ModuleGraph = class {
1257
- urlToModuleMap = /* @__PURE__ */ new Map();
1258
- idToModuleMap = /* @__PURE__ */ new Map();
1259
- fileToModulesMap = /* @__PURE__ */ new Map();
1260
- getModuleByUrl(url) {
1261
- return this.urlToModuleMap.get(url);
1262
- }
1263
- getModuleById(id) {
1264
- return this.idToModuleMap.get(id);
1265
- }
1266
- getModulesByFile(file) {
1267
- return this.fileToModulesMap.get(file);
1268
- }
1269
- async ensureEntryFromUrl(url) {
1270
- let mod = this.urlToModuleMap.get(url);
1271
- if (mod) return mod;
1272
- mod = this.createModule(url);
1273
- this.urlToModuleMap.set(url, mod);
1274
- return mod;
1275
- }
1276
- createModule(url, id) {
1277
- const mod = {
1278
- id: id ?? url,
1279
- file: null,
1280
- url,
1281
- type: url.endsWith(".css") ? "css" : "js",
1282
- importers: /* @__PURE__ */ new Set(),
1283
- importedModules: /* @__PURE__ */ new Set(),
1284
- acceptedHmrDeps: /* @__PURE__ */ new Set(),
1285
- transformResult: null,
1286
- lastHMRTimestamp: 0,
1287
- isSelfAccepting: false
1288
- };
1289
- this.idToModuleMap.set(mod.id, mod);
1290
- return mod;
1291
- }
1292
- /** 注册文件路径到模块的映射 */
1293
- registerModule(mod, file) {
1294
- mod.file = file;
1295
- let mods = this.fileToModulesMap.get(file);
1296
- if (!mods) {
1297
- mods = /* @__PURE__ */ new Set();
1298
- this.fileToModulesMap.set(file, mods);
1299
- }
1300
- mods.add(mod);
1301
- }
1302
- /**
1303
- * Reindex a module under a plugin-provided canonical id (e.g. a `\0virtual:foo`
1304
- * id returned from `resolveId`). Plugins look up their own virtual modules via
1305
- * `getModuleById(RESOLVED_ID)` to invalidate them on watcher events; without
1306
- * this remap they'd never find the node because `ensureEntryFromUrl` keys by
1307
- * the public URL only.
1308
- */
1309
- setModuleId(mod, id) {
1310
- if (mod.id === id) return;
1311
- this.idToModuleMap.delete(mod.id);
1312
- mod.id = id;
1313
- this.idToModuleMap.set(id, mod);
1314
- }
1315
- /** 更新模块依赖关系 */
1316
- updateModuleImports(mod, importedIds) {
1317
- for (const imported of mod.importedModules) {
1318
- imported.importers.delete(mod);
1319
- }
1320
- mod.importedModules.clear();
1321
- for (const id of importedIds) {
1322
- const importedMod = this.idToModuleMap.get(id);
1323
- if (importedMod) {
1324
- mod.importedModules.add(importedMod);
1325
- importedMod.importers.add(mod);
1326
- }
1327
- }
1328
- }
1329
- /** 使模块的转换缓存失效 */
1330
- invalidateModule(mod) {
1331
- mod.transformResult = null;
1332
- mod.lastHMRTimestamp = Date.now();
1333
- }
1334
- /** 使所有模块缓存失效 */
1335
- invalidateAll() {
1336
- for (const mod of this.idToModuleMap.values()) {
1337
- this.invalidateModule(mod);
1338
- }
1339
- }
1340
- /** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
1341
- getHmrBoundaries(mod) {
1342
- const boundaries = [];
1343
- const visited = /* @__PURE__ */ new Set();
1344
- const propagate = (node, via) => {
1345
- if (visited.has(node)) return true;
1346
- visited.add(node);
1347
- if (node.isSelfAccepting) {
1348
- boundaries.push({ boundary: node, acceptedVia: via });
1349
- return true;
1350
- }
1351
- if (node.acceptedHmrDeps.has(via)) {
1352
- boundaries.push({ boundary: node, acceptedVia: via });
1353
- return true;
1354
- }
1355
- if (node.importers.size === 0) return false;
1356
- for (const importer of node.importers) {
1357
- if (!propagate(importer, node)) return false;
1358
- }
1359
- return true;
1360
- };
1361
- if (mod.isSelfAccepting) {
1362
- boundaries.push({ boundary: mod, acceptedVia: mod });
1363
- return boundaries;
1364
- }
1365
- for (const importer of mod.importers) {
1366
- if (!propagate(importer, mod)) {
1367
- return [];
1368
- }
1369
- }
1370
- return boundaries;
1371
- }
1372
- };
3031
+ "src/build/index.ts"() {
3032
+ "use strict";
3033
+ init_config();
3034
+ init_builtins();
3035
+ init_environment();
3036
+ init_css_engine();
3037
+ init_html();
3038
+ init_transformer();
3039
+ init_env();
3040
+ init_reporter();
3041
+ init_debug();
3042
+ debug4 = createDebugger("nasti:build");
3043
+ NODE_BUILTINS = /* @__PURE__ */ new Set([...builtinModules, ...builtinModules.map((m) => `node:${m}`)]);
1373
3044
  }
1374
3045
  });
1375
3046
 
@@ -1421,21 +3092,23 @@ var init_ws = __esm({
1421
3092
  var middleware_exports = {};
1422
3093
  __export(middleware_exports, {
1423
3094
  REACT_REFRESH_GLOBAL_PREAMBLE: () => REACT_REFRESH_GLOBAL_PREAMBLE,
3095
+ getReactRefreshRuntimeEsm: () => getReactRefreshRuntimeEsm,
1424
3096
  transformMiddleware: () => transformMiddleware,
1425
3097
  transformRequest: () => transformRequest
1426
3098
  });
1427
- import path10 from "path";
3099
+ import path11 from "path";
1428
3100
  import fs8 from "fs";
1429
3101
  import { createRequire as createRequire3 } from "module";
1430
3102
  import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "url";
3103
+ import pc6 from "picocolors";
1431
3104
  function getReactRefreshRuntimeEsm() {
1432
3105
  if (__refreshRuntimeCache) return __refreshRuntimeCache;
1433
3106
  let cjsPath;
1434
3107
  try {
1435
- const pkgPath = __require.resolve("react-refresh/package.json");
1436
- cjsPath = path10.join(path10.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
3108
+ const pkgPath = __require2.resolve("react-refresh/package.json");
3109
+ cjsPath = path11.join(path11.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
1437
3110
  } catch (err) {
1438
- cjsPath = path10.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
3111
+ cjsPath = path11.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
1439
3112
  if (!fs8.existsSync(cjsPath)) {
1440
3113
  const origMsg = err instanceof Error ? err.message : String(err);
1441
3114
  throw new Error(
@@ -1563,7 +3236,11 @@ function transformMiddleware(ctx) {
1563
3236
  return;
1564
3237
  }
1565
3238
  } catch (err) {
1566
- console.error(`[nasti] Transform error: ${url}`, err.message);
3239
+ ctx.config.logger.error(
3240
+ pc6.red(`Transform error: ${url}
3241
+ `) + (err.stack ?? err.message),
3242
+ { timestamp: true, error: err }
3243
+ );
1567
3244
  res.statusCode = 500;
1568
3245
  res.end(`Transform error: ${err.message}`);
1569
3246
  return;
@@ -1592,6 +3269,28 @@ async function transformRequest(url, ctx) {
1592
3269
  return virtual.result;
1593
3270
  }
1594
3271
  }
3272
+ const rawQuery = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
3273
+ if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
3274
+ const loaded = await pluginContainer.load(url);
3275
+ if (loaded != null) {
3276
+ let code2 = typeof loaded === "string" ? loaded : loaded.code;
3277
+ const transformed = await pluginContainer.transform(code2, url);
3278
+ if (transformed != null) {
3279
+ code2 = typeof transformed === "string" ? transformed : transformed.code;
3280
+ }
3281
+ const mod2 = await moduleGraph.ensureEntryFromUrl(url);
3282
+ moduleGraph.registerModule(mod2, cleanReqUrl);
3283
+ code2 = injectImportMetaHot(code2, url);
3284
+ code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
3285
+ loadEnv(config.mode, config.root, config.envPrefix),
3286
+ config.mode
3287
+ ));
3288
+ code2 = rewriteImports(code2, config, cleanReqUrl);
3289
+ const transformResult2 = { code: code2 };
3290
+ mod2.transformResult = transformResult2;
3291
+ return transformResult2;
3292
+ }
3293
+ }
1595
3294
  const filePath = resolveUrlToFile(url, config.root);
1596
3295
  if (!filePath || !fs8.existsSync(filePath)) return null;
1597
3296
  const mod = await moduleGraph.ensureEntryFromUrl(url);
@@ -1656,7 +3355,7 @@ async function loadVirtualModule(spec, ctx) {
1656
3355
  loadEnv(config.mode, config.root, config.envPrefix),
1657
3356
  config.mode
1658
3357
  ));
1659
- const anchor = path10.join(config.root, "__nasti_virtual__.ts");
3358
+ const anchor = path11.join(config.root, "__nasti_virtual__.ts");
1660
3359
  code = rewriteImports(code, config, anchor);
1661
3360
  return { id: resolvedId, result: { code } };
1662
3361
  }
@@ -1670,7 +3369,7 @@ async function doBundlePackage(entryFile) {
1670
3369
  const shim = await tryGenerateSubpathShim(entryFile);
1671
3370
  if (shim != null) return shim;
1672
3371
  const { rolldown: rolldown4 } = await import("rolldown");
1673
- const bundle = await rolldown4({
3372
+ const bundle2 = await rolldown4({
1674
3373
  input: entryFile,
1675
3374
  // 仅将其他 npm 包外部化;相对路径(包内部文件)全部内联打包
1676
3375
  external: (id) => {
@@ -1678,8 +3377,8 @@ async function doBundlePackage(entryFile) {
1678
3377
  return true;
1679
3378
  }
1680
3379
  });
1681
- const result = await bundle.generate({ format: "esm", exports: "named" });
1682
- await bundle.close();
3380
+ const result = await bundle2.generate({ format: "esm", exports: "named" });
3381
+ await bundle2.close();
1683
3382
  let code = result.output[0].code;
1684
3383
  code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
1685
3384
  code = code.replace(
@@ -1699,13 +3398,13 @@ async function doBundlePackage(entryFile) {
1699
3398
  return code;
1700
3399
  }
1701
3400
  async function tryGenerateSubpathShim(entryFile) {
1702
- const NM = `${path10.sep}node_modules${path10.sep}`;
3401
+ const NM = `${path11.sep}node_modules${path11.sep}`;
1703
3402
  if (!entryFile.includes(NM)) return null;
1704
3403
  let pkgDir = null;
1705
3404
  let pkgName = null;
1706
- let dir = path10.dirname(entryFile);
3405
+ let dir = path11.dirname(entryFile);
1707
3406
  while (true) {
1708
- const pkgJsonPath = path10.join(dir, "package.json");
3407
+ const pkgJsonPath = path11.join(dir, "package.json");
1709
3408
  if (fs8.existsSync(pkgJsonPath)) {
1710
3409
  try {
1711
3410
  const pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
@@ -1717,16 +3416,16 @@ async function tryGenerateSubpathShim(entryFile) {
1717
3416
  } catch {
1718
3417
  }
1719
3418
  }
1720
- const parent = path10.dirname(dir);
3419
+ const parent = path11.dirname(dir);
1721
3420
  if (parent === dir) return null;
1722
3421
  dir = parent;
1723
3422
  if (!dir.includes(NM)) return null;
1724
3423
  }
1725
3424
  if (!pkgDir || !pkgName) return null;
1726
- const entryExt = path10.extname(entryFile);
3425
+ const entryExt = path11.extname(entryFile);
1727
3426
  const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
1728
3427
  if (!mainEntry) return null;
1729
- if (path10.resolve(mainEntry) === path10.resolve(entryFile)) return null;
3428
+ if (path11.resolve(mainEntry) === path11.resolve(entryFile)) return null;
1730
3429
  let mainNs;
1731
3430
  let subNs;
1732
3431
  try {
@@ -1762,7 +3461,7 @@ async function tryGenerateSubpathShim(entryFile) {
1762
3461
  return lines.join("\n") + "\n";
1763
3462
  }
1764
3463
  function pickMainEntryByExtension(pkgDir, preferredExt) {
1765
- const pkgJsonPath = path10.join(pkgDir, "package.json");
3464
+ const pkgJsonPath = path11.join(pkgDir, "package.json");
1766
3465
  let pkg;
1767
3466
  try {
1768
3467
  pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
@@ -1784,13 +3483,13 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
1784
3483
  if (typeof pkg.module === "string") candidates.push(pkg.module);
1785
3484
  if (typeof pkg.main === "string") candidates.push(pkg.main);
1786
3485
  for (const cand of candidates) {
1787
- if (path10.extname(cand) === preferredExt) {
1788
- const full = path10.resolve(pkgDir, cand);
3486
+ if (path11.extname(cand) === preferredExt) {
3487
+ const full = path11.resolve(pkgDir, cand);
1789
3488
  if (fs8.existsSync(full)) return full;
1790
3489
  }
1791
3490
  }
1792
3491
  for (const cand of candidates) {
1793
- const full = path10.resolve(pkgDir, cand);
3492
+ const full = path11.resolve(pkgDir, cand);
1794
3493
  if (fs8.existsSync(full)) return full;
1795
3494
  }
1796
3495
  return null;
@@ -1816,8 +3515,8 @@ function rewriteExternalRequires(code) {
1816
3515
  }
1817
3516
  async function injectCjsNamedExports(code, entryFile) {
1818
3517
  try {
1819
- const { createRequire: createRequire6 } = await import("module");
1820
- const req = createRequire6(entryFile);
3518
+ const { createRequire: createRequire7 } = await import("module");
3519
+ const req = createRequire7(entryFile);
1821
3520
  const cjsExports = req(entryFile);
1822
3521
  if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
1823
3522
  const namedKeys = Object.keys(cjsExports).filter(
@@ -1839,11 +3538,11 @@ async function injectCjsNamedExports(code, entryFile) {
1839
3538
  }
1840
3539
  function rewriteImports(code, config, filePath) {
1841
3540
  const root = config.root;
1842
- const fileDir = path10.dirname(filePath);
3541
+ const fileDir = path11.dirname(filePath);
1843
3542
  const aliasEntries = Object.entries(config.resolve.alias).sort(
1844
3543
  ([a], [b]) => b.length - a.length
1845
3544
  );
1846
- const toRootUrl = (abs) => "/" + path10.relative(root, abs).replace(/\\/g, "/");
3545
+ const toRootUrl = (abs) => "/" + path11.relative(root, abs).replace(/\\/g, "/");
1847
3546
  const transformSpec = (spec) => {
1848
3547
  const suffixMatch = spec.match(/[?#].*$/);
1849
3548
  const suffix = suffixMatch ? suffixMatch[0] : "";
@@ -1852,18 +3551,18 @@ function rewriteImports(code, config, filePath) {
1852
3551
  if (baseSpec === key || baseSpec.startsWith(key + "/")) {
1853
3552
  const aliasBase = resolveAliasTarget2(value, root);
1854
3553
  const sub = baseSpec.slice(key.length).replace(/^\//, "");
1855
- const target = sub ? path10.join(aliasBase, sub) : aliasBase;
3554
+ const target = sub ? path11.join(aliasBase, sub) : aliasBase;
1856
3555
  const resolved = tryResolveDiskPath(target);
1857
3556
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
1858
3557
  }
1859
3558
  }
1860
3559
  if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
1861
- const target = path10.resolve(fileDir, baseSpec);
3560
+ const target = path11.resolve(fileDir, baseSpec);
1862
3561
  const resolved = tryResolveDiskPath(target);
1863
3562
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
1864
3563
  }
1865
3564
  if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
1866
- const target = path10.join(root, baseSpec.replace(/^\//, ""));
3565
+ const target = path11.join(root, baseSpec.replace(/^\//, ""));
1867
3566
  const resolved = tryResolveDiskPath(target);
1868
3567
  return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
1869
3568
  }
@@ -1882,9 +3581,9 @@ function rewriteImports(code, config, filePath) {
1882
3581
  );
1883
3582
  }
1884
3583
  function resolveAliasTarget2(value, root) {
1885
- if (path10.isAbsolute(value) && fs8.existsSync(value)) return value;
1886
- if (value.startsWith("/")) return path10.join(root, value.slice(1));
1887
- return path10.resolve(root, value);
3584
+ if (path11.isAbsolute(value) && fs8.existsSync(value)) return value;
3585
+ if (value.startsWith("/")) return path11.join(root, value.slice(1));
3586
+ return path11.resolve(root, value);
1888
3587
  }
1889
3588
  function tryResolveDiskPath(target) {
1890
3589
  if (fs8.existsSync(target) && fs8.statSync(target).isFile()) return target;
@@ -1894,15 +3593,15 @@ function tryResolveDiskPath(target) {
1894
3593
  }
1895
3594
  if (fs8.existsSync(target) && fs8.statSync(target).isDirectory()) {
1896
3595
  for (const ext of RESOLVE_EXTENSIONS) {
1897
- const idx = path10.join(target, "index" + ext);
3596
+ const idx = path11.join(target, "index" + ext);
1898
3597
  if (fs8.existsSync(idx) && fs8.statSync(idx).isFile()) return idx;
1899
3598
  }
1900
3599
  }
1901
3600
  return null;
1902
3601
  }
1903
3602
  function isUnderRoot(abs, root) {
1904
- const rel = path10.relative(root, abs);
1905
- return !!rel && !rel.startsWith("..") && !path10.isAbsolute(rel);
3603
+ const rel = path11.relative(root, abs);
3604
+ return !!rel && !rel.startsWith("..") && !path11.isAbsolute(rel);
1906
3605
  }
1907
3606
  function resolveNodeModule(root, moduleName) {
1908
3607
  let pkgName;
@@ -1919,17 +3618,17 @@ function resolveNodeModule(root, moduleName) {
1919
3618
  let pkgDir = null;
1920
3619
  let dir = root;
1921
3620
  for (; ; ) {
1922
- const candidate = path10.join(dir, "node_modules", pkgName);
3621
+ const candidate = path11.join(dir, "node_modules", pkgName);
1923
3622
  if (fs8.existsSync(candidate)) {
1924
3623
  pkgDir = candidate;
1925
3624
  break;
1926
3625
  }
1927
- const parent = path10.dirname(dir);
3626
+ const parent = path11.dirname(dir);
1928
3627
  if (parent === dir) break;
1929
3628
  dir = parent;
1930
3629
  }
1931
3630
  if (!pkgDir) return null;
1932
- const pkgJsonPath = path10.join(pkgDir, "package.json");
3631
+ const pkgJsonPath = path11.join(pkgDir, "package.json");
1933
3632
  if (!fs8.existsSync(pkgJsonPath)) return null;
1934
3633
  let pkg;
1935
3634
  try {
@@ -1946,12 +3645,12 @@ function resolveNodeModule(root, moduleName) {
1946
3645
  const subDirs = [""];
1947
3646
  for (const field of ["module", "main"]) {
1948
3647
  if (typeof pkg[field] === "string") {
1949
- const dir2 = path10.dirname(pkg[field]);
3648
+ const dir2 = path11.dirname(pkg[field]);
1950
3649
  if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
1951
3650
  }
1952
3651
  }
1953
3652
  for (const dir2 of subDirs) {
1954
- const direct = path10.join(pkgDir, dir2, subpath);
3653
+ const direct = path11.join(pkgDir, dir2, subpath);
1955
3654
  if (fs8.existsSync(direct) && fs8.statSync(direct).isFile()) return direct;
1956
3655
  for (const ext of RESOLVE_EXTENSIONS) {
1957
3656
  if (fs8.existsSync(direct + ext)) return direct + ext;
@@ -1961,24 +3660,24 @@ function resolveNodeModule(root, moduleName) {
1961
3660
  }
1962
3661
  for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
1963
3662
  if (typeof pkg[field] === "string") {
1964
- const entry = path10.join(pkgDir, pkg[field]);
3663
+ const entry = path11.join(pkgDir, pkg[field]);
1965
3664
  if (fs8.existsSync(entry)) return entry;
1966
3665
  }
1967
3666
  }
1968
- const indexFallback = path10.join(pkgDir, "index.js");
3667
+ const indexFallback = path11.join(pkgDir, "index.js");
1969
3668
  if (fs8.existsSync(indexFallback)) return indexFallback;
1970
3669
  return null;
1971
3670
  }
1972
3671
  function resolvePackageExports(exports, key, pkgDir) {
1973
3672
  if (typeof exports === "string") {
1974
- return key === "." ? path10.join(pkgDir, exports) : null;
3673
+ return key === "." ? path11.join(pkgDir, exports) : null;
1975
3674
  }
1976
3675
  const entry = exports[key];
1977
3676
  if (entry === void 0) return null;
1978
3677
  return resolveExportValue(entry, pkgDir);
1979
3678
  }
1980
3679
  function resolveExportValue(value, pkgDir) {
1981
- if (typeof value === "string") return path10.join(pkgDir, value);
3680
+ if (typeof value === "string") return path11.join(pkgDir, value);
1982
3681
  if (Array.isArray(value)) {
1983
3682
  for (const item of value) {
1984
3683
  const r = resolveExportValue(item, pkgDir);
@@ -2002,7 +3701,7 @@ function resolveUrlToFile(url, root) {
2002
3701
  const moduleName = cleanUrl.slice("/@modules/".length);
2003
3702
  return resolveNodeModule(root, moduleName);
2004
3703
  }
2005
- const filePath = path10.resolve(root, cleanUrl.replace(/^\//, ""));
3704
+ const filePath = path11.resolve(root, cleanUrl.replace(/^\//, ""));
2006
3705
  if (fs8.existsSync(filePath) && fs8.statSync(filePath).isFile()) {
2007
3706
  return filePath;
2008
3707
  }
@@ -2011,7 +3710,7 @@ function resolveUrlToFile(url, root) {
2011
3710
  if (fs8.existsSync(withExt)) return withExt;
2012
3711
  }
2013
3712
  for (const ext of RESOLVE_EXTENSIONS) {
2014
- const indexFile = path10.join(filePath, "index" + ext);
3713
+ const indexFile = path11.join(filePath, "index" + ext);
2015
3714
  if (fs8.existsSync(indexFile)) return indexFile;
2016
3715
  }
2017
3716
  return null;
@@ -2020,7 +3719,7 @@ function isModuleRequest(url) {
2020
3719
  const cleanUrl = url.split("?")[0];
2021
3720
  if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
2022
3721
  if (cleanUrl.startsWith("/@modules/")) return true;
2023
- if (!path10.extname(cleanUrl)) return true;
3722
+ if (!path11.extname(cleanUrl)) return true;
2024
3723
  return false;
2025
3724
  }
2026
3725
  function getHmrClientCode() {
@@ -2151,15 +3850,15 @@ export function createHotContext(ownerPath) {
2151
3850
  }
2152
3851
  `;
2153
3852
  }
2154
- var __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
3853
+ var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
2155
3854
  var init_middleware = __esm({
2156
3855
  "src/server/middleware.ts"() {
2157
3856
  "use strict";
2158
3857
  init_transformer();
2159
3858
  init_html();
2160
3859
  init_env();
2161
- __dirname_esm = path10.dirname(fileURLToPath(import.meta.url));
2162
- __require = createRequire3(import.meta.url);
3860
+ __dirname_esm = path11.dirname(fileURLToPath(import.meta.url));
3861
+ __require2 = createRequire3(import.meta.url);
2163
3862
  __refreshRuntimeCache = null;
2164
3863
  REACT_REFRESH_GLOBAL_PREAMBLE = `
2165
3864
  import RefreshRuntime from "/@react-refresh";
@@ -2176,11 +3875,14 @@ window.__vite_plugin_react_preamble_installed__ = true;
2176
3875
  });
2177
3876
 
2178
3877
  // src/server/hmr.ts
2179
- import path11 from "path";
3878
+ import path12 from "path";
2180
3879
  import fs9 from "fs";
3880
+ import pc7 from "picocolors";
2181
3881
  async function handleFileChange(file, server) {
2182
3882
  const { moduleGraph, ws, config } = server;
2183
- const relativePath = "/" + path11.relative(config.root, file);
3883
+ const logger = config.logger;
3884
+ const relativePath = "/" + path12.relative(config.root, file);
3885
+ const shortFile = path12.relative(config.root, file);
2184
3886
  const mods = moduleGraph.getModulesByFile(file);
2185
3887
  if (!mods || mods.size === 0) {
2186
3888
  return;
@@ -2208,6 +3910,7 @@ async function handleFileChange(file, server) {
2208
3910
  for (const affected of affectedModules) {
2209
3911
  const boundaries = moduleGraph.getHmrBoundaries(affected);
2210
3912
  if (boundaries.length === 0) {
3913
+ logger.info(pc7.green("page reload ") + pc7.dim(shortFile), { timestamp: true });
2211
3914
  ws.send({ type: "full-reload", path: relativePath });
2212
3915
  return;
2213
3916
  }
@@ -2222,6 +3925,10 @@ async function handleFileChange(file, server) {
2222
3925
  }
2223
3926
  }
2224
3927
  if (updates.length > 0) {
3928
+ logger.info(
3929
+ updates.map((u) => pc7.green("hmr update ") + pc7.dim(u.path)).join("\n"),
3930
+ { timestamp: true }
3931
+ );
2225
3932
  ws.send({ type: "update", updates });
2226
3933
  }
2227
3934
  }
@@ -2231,51 +3938,743 @@ var init_hmr = __esm({
2231
3938
  }
2232
3939
  });
2233
3940
 
3941
+ // src/server/runnable-environment.ts
3942
+ var runnable_environment_exports = {};
3943
+ __export(runnable_environment_exports, {
3944
+ NastiModuleRunner: () => NastiModuleRunner,
3945
+ createModuleRunner: () => createModuleRunner
3946
+ });
3947
+ import path13 from "path";
3948
+ import fs10 from "fs";
3949
+ import { builtinModules as builtinModules3, createRequire as createRequire4 } from "module";
3950
+ import { pathToFileURL as pathToFileURL4 } from "url";
3951
+ function createModuleRunner(environment) {
3952
+ if (environment.consumer !== "server") {
3953
+ throw new Error(
3954
+ `[nasti] module runner requires a server-consumer environment (got "${environment.name}" / ${environment.consumer})`
3955
+ );
3956
+ }
3957
+ return new NastiModuleRunner(environment);
3958
+ }
3959
+ var debug5, NODE_BUILTINS3, NastiModuleRunner, AsyncFunction;
3960
+ var init_runnable_environment = __esm({
3961
+ "src/server/runnable-environment.ts"() {
3962
+ "use strict";
3963
+ init_transformer();
3964
+ init_env();
3965
+ init_debug();
3966
+ debug5 = createDebugger("nasti:ssr");
3967
+ NODE_BUILTINS3 = /* @__PURE__ */ new Set([...builtinModules3, ...builtinModules3.map((m) => `node:${m}`)]);
3968
+ NastiModuleRunner = class {
3969
+ environment;
3970
+ config;
3971
+ cache = /* @__PURE__ */ new Map();
3972
+ envDefine;
3973
+ require;
3974
+ constructor(environment) {
3975
+ this.environment = environment;
3976
+ this.config = environment.config;
3977
+ this.envDefine = buildEnvDefine(
3978
+ loadEnv(this.config.mode, this.config.root, this.config.envPrefix),
3979
+ this.config.mode,
3980
+ ssrDefineOverrides(environment.consumer)
3981
+ );
3982
+ this.require = createRequire4(path13.join(this.config.root, "package.json"));
3983
+ const handlers = {
3984
+ fetchModule: async (id, importer) => this.fetchModule(id, importer),
3985
+ getBuiltins: () => [/^node:/, ...builtinModules3]
3986
+ };
3987
+ environment.hot.setInvokeHandler?.(handlers);
3988
+ }
3989
+ /** 入口:加载并执行一个模块(url 为根相对或绝对路径) */
3990
+ async import(rawUrl) {
3991
+ const id = this.resolveToId(rawUrl);
3992
+ return this.instantiate(id);
3993
+ }
3994
+ /** 文件变更时按文件失效(含其所属的虚拟子模块) */
3995
+ invalidateFile(file) {
3996
+ for (const key of [...this.cache.keys()]) {
3997
+ if (key === file || key.startsWith(file + "?")) {
3998
+ this.cache.delete(key);
3999
+ }
4000
+ }
4001
+ }
4002
+ invalidateAll() {
4003
+ this.cache.clear();
4004
+ }
4005
+ resolveToId(rawUrl) {
4006
+ if (path13.isAbsolute(rawUrl) && fs10.existsSync(rawUrl.split("?")[0])) return rawUrl;
4007
+ const clean = rawUrl.replace(/^\//, "");
4008
+ return path13.resolve(this.config.root, clean);
4009
+ }
4010
+ /**
4011
+ * fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
4012
+ * resolve(插件 resolveId → 文件系统)→ load/读盘 → 插件 transform →
4013
+ * oxc(TS/JSX)→ moduleRunnerTransform。
4014
+ */
4015
+ async fetchModule(id, importer) {
4016
+ if (NODE_BUILTINS3.has(id)) return { externalize: id };
4017
+ if (!id.startsWith(".") && !path13.isAbsolute(id) && !id.startsWith("\0")) {
4018
+ return { externalize: id };
4019
+ }
4020
+ const container = this.environment.pluginContainer;
4021
+ let resolvedId = id;
4022
+ if (id.startsWith(".") && importer) {
4023
+ const resolved = await container.resolveId(id, importer);
4024
+ resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : path13.resolve(path13.dirname(importer.split("?")[0]), id);
4025
+ }
4026
+ resolvedId = this.completeExtension(resolvedId);
4027
+ const cleanId = resolvedId.split("?")[0];
4028
+ let code;
4029
+ const loaded = await container.load(resolvedId);
4030
+ if (loaded != null) {
4031
+ code = typeof loaded === "string" ? loaded : loaded.code;
4032
+ } else if (fs10.existsSync(cleanId)) {
4033
+ code = fs10.readFileSync(cleanId, "utf-8");
4034
+ } else {
4035
+ throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
4036
+ }
4037
+ const transformed = await container.transform(code, resolvedId);
4038
+ if (transformed != null) {
4039
+ code = typeof transformed === "string" ? transformed : transformed.code;
4040
+ }
4041
+ if (shouldTransform(cleanId)) {
4042
+ const result = transformCode(cleanId, code, {
4043
+ sourcemap: false,
4044
+ jsxRuntime: "automatic",
4045
+ jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
4046
+ });
4047
+ code = result.code;
4048
+ }
4049
+ code = replaceEnvInCode(code, this.envDefine);
4050
+ let moduleRunnerTransform;
4051
+ try {
4052
+ ;
4053
+ ({ moduleRunnerTransform } = await import("rolldown/experimental"));
4054
+ } catch (err) {
4055
+ throw new Error(
4056
+ `[nasti:ssr] rolldown/experimental moduleRunnerTransform unavailable (installed rolldown incompatible?): ${err.message}`
4057
+ );
4058
+ }
4059
+ const runnerResult = await moduleRunnerTransform(resolvedId, code);
4060
+ debug5?.(`fetchModule ${resolvedId} (${runnerResult.deps?.length ?? 0} deps)`);
4061
+ return { id: resolvedId, code: runnerResult.code };
4062
+ }
4063
+ completeExtension(id) {
4064
+ const clean = id.split("?")[0];
4065
+ const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
4066
+ if (fs10.existsSync(clean) && fs10.statSync(clean).isFile()) return id;
4067
+ const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
4068
+ if (jsMatch) {
4069
+ for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
4070
+ if (fs10.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
4071
+ }
4072
+ }
4073
+ for (const ext of this.config.resolve.extensions) {
4074
+ if (fs10.existsSync(clean + ext)) return clean + ext + query;
4075
+ }
4076
+ for (const ext of this.config.resolve.extensions) {
4077
+ const indexPath = path13.join(clean, `index${ext}`);
4078
+ if (fs10.existsSync(indexPath)) return indexPath;
4079
+ }
4080
+ return id;
4081
+ }
4082
+ async instantiate(id) {
4083
+ const cached2 = this.cache.get(id);
4084
+ if (cached2) return cached2.promise ?? Promise.resolve(cached2.exports);
4085
+ const entry = { exports: {}, promise: null };
4086
+ this.cache.set(id, entry);
4087
+ entry.promise = this.evaluate(id, entry).then(() => {
4088
+ entry.promise = null;
4089
+ return entry.exports;
4090
+ }).catch((err) => {
4091
+ this.cache.delete(id);
4092
+ throw err;
4093
+ });
4094
+ return entry.promise;
4095
+ }
4096
+ async evaluate(id, entry) {
4097
+ const fetched = await this.fetchModule(id);
4098
+ if ("externalize" in fetched) {
4099
+ const spec = fetched.externalize;
4100
+ const mod = await this.importExternal(spec);
4101
+ entry.exports = mod;
4102
+ return;
4103
+ }
4104
+ const ssrImport = async (dep) => {
4105
+ if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !path13.isAbsolute(dep) && !dep.startsWith("\0")) {
4106
+ return this.importExternal(dep);
4107
+ }
4108
+ const depId = dep.startsWith(".") ? this.completeExtension(path13.resolve(path13.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
4109
+ return this.instantiate(depId);
4110
+ };
4111
+ const ssrExportAll = (sourceModule) => {
4112
+ for (const key of Object.keys(sourceModule)) {
4113
+ if (key !== "default" && !(key in entry.exports)) {
4114
+ Object.defineProperty(entry.exports, key, {
4115
+ enumerable: true,
4116
+ configurable: true,
4117
+ get: () => sourceModule[key]
4118
+ });
4119
+ }
4120
+ }
4121
+ };
4122
+ const importMeta = {
4123
+ url: pathToFileURL4(fetched.id.split("?")[0]).href,
4124
+ env: { SSR: true, MODE: this.config.mode, DEV: this.config.mode !== "production", PROD: this.config.mode === "production" },
4125
+ hot: void 0
4126
+ };
4127
+ const fn = new AsyncFunction(
4128
+ "__vite_ssr_exports__",
4129
+ "__vite_ssr_import__",
4130
+ "__vite_ssr_dynamic_import__",
4131
+ "__vite_ssr_exportAll__",
4132
+ "__vite_ssr_import_meta__",
4133
+ `"use strict";${fetched.code}
4134
+ //# sourceURL=${fetched.id}`
4135
+ );
4136
+ await fn(entry.exports, ssrImport, ssrImport, ssrExportAll, importMeta);
4137
+ }
4138
+ async importExternal(spec) {
4139
+ try {
4140
+ return await (spec.startsWith("node:") || !path13.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import(pathToFileURL4(spec).href));
4141
+ } catch (err) {
4142
+ throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
4143
+ }
4144
+ }
4145
+ /** bare specifier → 项目 node_modules 的绝对 URL(避免相对 Nasti 自身解析) */
4146
+ resolveExternalSpecifier(spec) {
4147
+ if (spec.startsWith("node:")) return spec;
4148
+ if (NODE_BUILTINS3.has(spec)) return `node:${spec}`;
4149
+ try {
4150
+ return pathToFileURL4(this.require.resolve(spec)).href;
4151
+ } catch {
4152
+ return spec;
4153
+ }
4154
+ }
4155
+ };
4156
+ AsyncFunction = Object.getPrototypeOf(async function() {
4157
+ }).constructor;
4158
+ }
4159
+ });
4160
+
4161
+ // src/server/bundled/dev-engine.ts
4162
+ var dev_engine_exports = {};
4163
+ __export(dev_engine_exports, {
4164
+ createBundledDevServer: () => createBundledDevServer
4165
+ });
4166
+ import path14 from "path";
4167
+ import crypto3 from "crypto";
4168
+ import { WebSocketServer as WsServer2 } from "ws";
4169
+ import pc8 from "picocolors";
4170
+ async function createBundledDevServer(opts) {
4171
+ const { config, clientEnv, httpServer } = opts;
4172
+ const logger = config.logger;
4173
+ let devFn;
4174
+ let refreshWrapperFn = null;
4175
+ try {
4176
+ const experimental = await import("rolldown/experimental");
4177
+ devFn = experimental.dev;
4178
+ if (typeof devFn !== "function") throw new Error("dev() export missing");
4179
+ if (typeof experimental.viteReactRefreshWrapperPlugin === "function") {
4180
+ refreshWrapperFn = experimental.viteReactRefreshWrapperPlugin;
4181
+ }
4182
+ } catch (err) {
4183
+ throw new Error(
4184
+ `[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.`
4185
+ );
4186
+ }
4187
+ const html = await readHtmlFile(config.root);
4188
+ const entryPoints = resolveClientEntries(config, html);
4189
+ if (entryPoints.length === 0) {
4190
+ throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
4191
+ }
4192
+ const memoryFiles = new MemoryFiles();
4193
+ const patches = new MemoryFiles();
4194
+ const entryFileNames = /* @__PURE__ */ new Map();
4195
+ const bundledClients = /* @__PURE__ */ new Map();
4196
+ const useReactRefresh = config.framework !== "vue" && refreshWrapperFn != null;
4197
+ const rolldownPlugins = [
4198
+ ...useReactRefresh ? [
4199
+ createReactRefreshRuntimePlugin(entryPoints),
4200
+ createBundledOxcRefreshPlugin()
4201
+ ] : [],
4202
+ ...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins)),
4203
+ ...useReactRefresh ? [
4204
+ refreshWrapperFn({
4205
+ cwd: config.root,
4206
+ include: [/\.[jt]sx(\?.*)?$/],
4207
+ exclude: [/node_modules/],
4208
+ jsxImportSource: "react",
4209
+ reactRefreshHost: ""
4210
+ })
4211
+ ] : []
4212
+ ];
4213
+ const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
4214
+ let fullReloadTimer = null;
4215
+ const scheduleFullReload = () => {
4216
+ if (fullReloadTimer) clearTimeout(fullReloadTimer);
4217
+ fullReloadTimer = setTimeout(() => {
4218
+ logger.info(pc8.green("page reload ") + pc8.dim("(bundled)"), { timestamp: true });
4219
+ broadcast({ type: "hmr:reload" });
4220
+ }, 30);
4221
+ };
4222
+ const broadcast = (payload) => {
4223
+ const data = JSON.stringify(payload);
4224
+ for (const ws of bundledClients.values()) {
4225
+ if (ws.readyState === 1) ws.send(data);
4226
+ }
4227
+ };
4228
+ const sendTo = (clientId, payload) => {
4229
+ const ws = bundledClients.get(clientId);
4230
+ if (ws && ws.readyState === 1) ws.send(JSON.stringify(payload));
4231
+ };
4232
+ async function processUpdates(updates, changedFiles) {
4233
+ let needsLatestOutput = false;
4234
+ for (const { clientId, update } of updates) {
4235
+ if (update.type === "Noop") continue;
4236
+ if (update.type === "FullReload") {
4237
+ debug6?.(`full reload for ${clientId}: ${update.reason ?? ""}`);
4238
+ needsLatestOutput = true;
4239
+ continue;
4240
+ }
4241
+ const patchPath = `__nasti_patch/${update.filename}`;
4242
+ patches.set(patchPath, update.code + "\n;export {}");
4243
+ if (update.sourcemap && update.sourcemapFilename) {
4244
+ patches.set(`__nasti_patch/${update.sourcemapFilename}`, update.sourcemap);
4245
+ }
4246
+ const url = `/${patchPath}`;
4247
+ logger.info(
4248
+ pc8.green("hmr update ") + pc8.dim(changedFiles.map((f) => path14.relative(config.root, f)).join(", ")),
4249
+ { timestamp: true }
4250
+ );
4251
+ sendTo(clientId, { type: "hmr:update", path: url, url });
4252
+ }
4253
+ if (needsLatestOutput) {
4254
+ await engine.ensureLatestBuildOutput();
4255
+ scheduleFullReload();
4256
+ }
4257
+ }
4258
+ const engine = await devFn(
4259
+ {
4260
+ ...inputOptions,
4261
+ cwd: config.root,
4262
+ // Rolldown bug 规避:inlineConst 与 dev patch 机制冲突(vitejs/vite#21843)
4263
+ optimization: { ...inputOptions.optimization, inlineConst: false },
4264
+ experimental: {
4265
+ ...inputOptions.experimental,
4266
+ devMode: {
4267
+ lazy: true,
4268
+ // 默认 DevRuntime 把 ws 地址烤进 bundle:指向 Nasti dev server 本身
4269
+ //(端口被占自动 +1 时 HMR ws 会失联 —— 已知限制,产物仍可服务)
4270
+ host: config.server.host === true ? "localhost" : config.server.host || "localhost",
4271
+ port: config.server.port
4272
+ }
4273
+ }
4274
+ },
4275
+ {
4276
+ ...outputOptions,
4277
+ entryFileNames: "assets/[name].js",
4278
+ chunkFileNames: "assets/[name]-[hash].js",
4279
+ minify: false,
4280
+ sourcemap: true
4281
+ },
4282
+ {
4283
+ watch: { skipWrite: true },
4284
+ rebuildStrategy: "auto",
4285
+ onOutput(result) {
4286
+ if (result instanceof Error) {
4287
+ logger.error(pc8.red(`[bundled] build error: ${result.message}`), { error: result });
4288
+ return;
4289
+ }
4290
+ for (const file of result.output) {
4291
+ const content = file.type === "chunk" ? file.code : file.source;
4292
+ if (content != null) memoryFiles.set(file.fileName, content);
4293
+ if (file.type === "chunk" && file.isEntry && file.facadeModuleId) {
4294
+ entryFileNames.set(file.facadeModuleId, file.fileName);
4295
+ }
4296
+ if (file.type === "chunk" && file.map) {
4297
+ memoryFiles.set(`${file.fileName}.map`, JSON.stringify(file.map));
4298
+ }
4299
+ }
4300
+ debug6?.(`bundle output refreshed (${result.output.length} files)`);
4301
+ },
4302
+ async onHmrUpdates(result) {
4303
+ if (result instanceof Error) {
4304
+ logger.error(pc8.red(`[bundled] hmr error: ${result.message}`), { error: result });
4305
+ broadcast({ type: "error", err: { message: result.message, stack: result.stack } });
4306
+ return;
4307
+ }
4308
+ const { updates, changedFiles } = result;
4309
+ debug6?.(
4310
+ `onHmrUpdates(engine watcher): ${changedFiles.length} changed, ${updates.length} updates`
4311
+ );
4312
+ if (changedFiles.length === 0) return;
4313
+ await processUpdates(updates, changedFiles);
4314
+ }
4315
+ }
4316
+ );
4317
+ await engine.run();
4318
+ await engine.ensureCurrentBuildFinish();
4319
+ logger.info(pc8.dim(` bundled dev engine ready (${entryPoints.length} entries, in-memory)`));
4320
+ const wss = new WsServer2({ noServer: true });
4321
+ httpServer.on("upgrade", (req, socket, head) => {
4322
+ if (req.headers["sec-websocket-protocol"] === "nasti-hmr") return;
4323
+ const url = new URL(req.url ?? "/", "http://localhost");
4324
+ const clientId = url.searchParams.get("clientId");
4325
+ if (!clientId) return;
4326
+ wss.handleUpgrade(req, socket, head, (ws) => {
4327
+ bundledClients.set(clientId, ws);
4328
+ debug6?.(`bundled client connected: ${clientId}`);
4329
+ ws.send(JSON.stringify({ type: "connected" }));
4330
+ ws.on("message", async (raw) => {
4331
+ try {
4332
+ const msg = JSON.parse(String(raw));
4333
+ if (msg.type === "hmr:module-registered" && Array.isArray(msg.modules)) {
4334
+ await engine.registerModules(clientId, msg.modules);
4335
+ debug6?.(`registered ${msg.modules.length} modules for ${clientId}`);
4336
+ } else if (msg.type === "hmr:invalidate") {
4337
+ scheduleFullReload();
4338
+ }
4339
+ } catch (err) {
4340
+ debug6?.(`bundled ws message error: ${err.message}`);
4341
+ }
4342
+ });
4343
+ ws.on("close", () => {
4344
+ bundledClients.delete(clientId);
4345
+ engine.removeClient(clientId).catch((err) => debug6?.(`removeClient failed for ${clientId}: ${err?.message ?? err}`));
4346
+ });
4347
+ });
4348
+ });
4349
+ const middleware = (req, res, next) => {
4350
+ void (async () => {
4351
+ const rawUrl = req.url ?? "/";
4352
+ const url = new URL(rawUrl, "http://localhost");
4353
+ const pathname = decodeURIComponent(url.pathname);
4354
+ if (pathname === "/@vite/lazy" || pathname === "/@nasti/lazy") {
4355
+ const id = url.searchParams.get("id");
4356
+ const clientId = url.searchParams.get("clientId");
4357
+ if (!id || !clientId) {
4358
+ res.statusCode = 400;
4359
+ res.end("// [nasti] lazy endpoint requires id & clientId");
4360
+ return;
4361
+ }
4362
+ const code = await engine.compileEntry(id, clientId);
4363
+ res.setHeader("Content-Type", "application/javascript");
4364
+ res.setHeader("Cache-Control", "no-store");
4365
+ res.end(code + "\n;export {}");
4366
+ return;
4367
+ }
4368
+ const patchHit = patches.get(pathname.replace(/^\//, ""));
4369
+ if (patchHit) {
4370
+ res.setHeader("Content-Type", "application/javascript");
4371
+ res.setHeader("Cache-Control", "no-store");
4372
+ res.end(patchHit.content);
4373
+ return;
4374
+ }
4375
+ const fileName = pathname.replace(/^\//, "");
4376
+ const hit = memoryFiles.get(fileName);
4377
+ if (hit) {
4378
+ if (req.headers["if-none-match"] === hit.etag) {
4379
+ res.statusCode = 304;
4380
+ res.end();
4381
+ return;
4382
+ }
4383
+ res.setHeader("ETag", hit.etag);
4384
+ res.setHeader("Content-Type", MIME_TYPES[path14.extname(fileName)] ?? "application/octet-stream");
4385
+ res.setHeader("Cache-Control", "no-cache");
4386
+ res.end(hit.content);
4387
+ return;
4388
+ }
4389
+ if (pathname === "/" || pathname.endsWith(".html")) {
4390
+ const rawHtml = await readHtmlFile(config.root);
4391
+ if (rawHtml) {
4392
+ res.setHeader("Content-Type", "text/html");
4393
+ res.setHeader("Cache-Control", "no-store");
4394
+ res.end(await renderBundledIndexHtml(rawHtml, config, entryFileNames));
4395
+ return;
4396
+ }
4397
+ }
4398
+ next();
4399
+ })().catch((err) => {
4400
+ config.logger.error(pc8.red(`[bundled] ${err.message}`), { error: err });
4401
+ res.statusCode = 500;
4402
+ res.end(`[nasti bundled] ${err.message}`);
4403
+ });
4404
+ };
4405
+ return {
4406
+ middleware,
4407
+ async close() {
4408
+ if (fullReloadTimer) clearTimeout(fullReloadTimer);
4409
+ wss.close();
4410
+ await engine.close();
4411
+ }
4412
+ };
4413
+ }
4414
+ function stripCatchAllLoad(plugins) {
4415
+ return plugins.map(
4416
+ (p) => p?.name === "nasti:resolve" ? { ...p, load: void 0 } : p
4417
+ );
4418
+ }
4419
+ function createReactRefreshRuntimePlugin(entryPoints) {
4420
+ const entryIds = new Set(entryPoints.map((p) => path14.resolve(p)));
4421
+ return {
4422
+ name: "nasti:bundled-react-refresh",
4423
+ resolveId(source) {
4424
+ if (source === REFRESH_RUNTIME_URL) return REFRESH_RUNTIME_URL;
4425
+ if (source === PREAMBLE_SPEC) return RESOLVED_PREAMBLE_ID;
4426
+ return null;
4427
+ },
4428
+ load(id) {
4429
+ if (id === REFRESH_RUNTIME_URL) {
4430
+ return { code: getReactRefreshRuntimeEsm() + WRAPPER_RUNTIME_HELPERS, moduleType: "js" };
4431
+ }
4432
+ if (id === RESOLVED_PREAMBLE_ID) {
4433
+ return { code: BUNDLED_PREAMBLE_CODE, moduleType: "js" };
4434
+ }
4435
+ return null;
4436
+ },
4437
+ transform(code, id) {
4438
+ if (!entryIds.has(path14.resolve(id.split("?")[0]))) return null;
4439
+ return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
4440
+ ${code}`, map: null };
4441
+ }
4442
+ };
4443
+ }
4444
+ function createBundledOxcRefreshPlugin() {
4445
+ return {
4446
+ name: "nasti:bundled-oxc-refresh",
4447
+ transform(code, id) {
4448
+ const clean = id.split("?")[0];
4449
+ if (!/\.[jt]sx$/.test(clean) || clean.includes("/node_modules/")) return null;
4450
+ const result = transformCode(clean, code, {
4451
+ sourcemap: true,
4452
+ jsxRuntime: "automatic",
4453
+ jsxImportSource: "react",
4454
+ reactRefresh: true
4455
+ });
4456
+ return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
4457
+ }
4458
+ };
4459
+ }
4460
+ async function renderBundledIndexHtml(html, config, entryFileNames) {
4461
+ let processed = html;
4462
+ for (const plugin of config.plugins) {
4463
+ if (!plugin.transformIndexHtml || plugin.name === "nasti:html") continue;
4464
+ const result = await plugin.transformIndexHtml(processed);
4465
+ if (typeof result === "string") {
4466
+ processed = result;
4467
+ } else if (result && "html" in result) {
4468
+ processed = processHtml(result.html, result.tags);
4469
+ } else if (Array.isArray(result)) {
4470
+ processed = processHtml(processed, result);
4471
+ }
4472
+ }
4473
+ for (const [facadeModuleId, fileName] of entryFileNames) {
4474
+ const originalEntry = path14.relative(config.root, facadeModuleId);
4475
+ processed = processed.replace(
4476
+ new RegExp(`(src=["'])/?(${originalEntry.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})(["'])`, "g"),
4477
+ `$1/${fileName}$3`
4478
+ );
4479
+ }
4480
+ return processed;
4481
+ }
4482
+ var debug6, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
4483
+ var init_dev_engine = __esm({
4484
+ "src/server/bundled/dev-engine.ts"() {
4485
+ "use strict";
4486
+ init_build();
4487
+ init_html();
4488
+ init_transformer();
4489
+ init_middleware();
4490
+ init_debug();
4491
+ debug6 = createDebugger("nasti:bundled");
4492
+ MIME_TYPES = {
4493
+ ".js": "application/javascript",
4494
+ ".mjs": "application/javascript",
4495
+ ".css": "text/css",
4496
+ ".html": "text/html",
4497
+ ".json": "application/json",
4498
+ ".map": "application/json",
4499
+ ".svg": "image/svg+xml",
4500
+ ".png": "image/png",
4501
+ ".jpg": "image/jpeg",
4502
+ ".wasm": "application/wasm"
4503
+ };
4504
+ MemoryFiles = class {
4505
+ files = /* @__PURE__ */ new Map();
4506
+ set(fileName, content) {
4507
+ const etag = `"${crypto3.createHash("sha1").update(content).digest("base64").slice(0, 27)}"`;
4508
+ this.files.set(fileName, { content, etag });
4509
+ }
4510
+ get(fileName) {
4511
+ return this.files.get(fileName);
4512
+ }
4513
+ clear() {
4514
+ this.files.clear();
4515
+ }
4516
+ };
4517
+ PREAMBLE_SPEC = "nasti:react-preamble";
4518
+ RESOLVED_PREAMBLE_ID = "\0nasti:react-preamble";
4519
+ REFRESH_RUNTIME_URL = "/@react-refresh";
4520
+ BUNDLED_PREAMBLE_CODE = `
4521
+ import __rt from ${JSON.stringify(REFRESH_RUNTIME_URL)};
4522
+ __rt.injectIntoGlobalHook(window);
4523
+ window.$RefreshReg$ = () => {};
4524
+ window.$RefreshSig$ = () => (type) => type;
4525
+ window.__vite_plugin_react_preamble_installed__ = true;
4526
+ `;
4527
+ WRAPPER_RUNTIME_HELPERS = `
4528
+ // \u2500\u2500 viteReactRefreshWrapperPlugin \u8FD0\u884C\u65F6\u5951\u7EA6\uFF08@vitejs/plugin-react \u540C\u6B3E\uFF09\u2500\u2500
4529
+ function __isPlainObject(obj) {
4530
+ return Object.prototype.toString.call(obj) === '[object Object]' &&
4531
+ (obj.constructor === Object || obj.constructor === undefined);
4532
+ }
4533
+ function __isCompoundComponent(type) {
4534
+ if (!__isPlainObject(type)) return false;
4535
+ for (const key in type) {
4536
+ if (!isLikelyComponentType(type[key])) return false;
4537
+ }
4538
+ return true;
4539
+ }
4540
+ export function registerExportsForReactRefresh(filename, moduleExports) {
4541
+ for (const key in moduleExports) {
4542
+ if (key === '__esModule') continue;
4543
+ const exportValue = moduleExports[key];
4544
+ if (isLikelyComponentType(exportValue)) {
4545
+ register(exportValue, filename + ' export ' + key);
4546
+ } else if (__isCompoundComponent(exportValue)) {
4547
+ for (const subKey in exportValue) {
4548
+ register(exportValue[subKey], filename + ' export ' + key + '-' + subKey);
4549
+ }
4550
+ }
4551
+ }
4552
+ }
4553
+ let __enqueueTimer;
4554
+ const __hooks = [];
4555
+ window.__registerBeforePerformReactRefresh = (cb) => { __hooks.push(cb); };
4556
+ function __enqueueUpdate() {
4557
+ clearTimeout(__enqueueTimer);
4558
+ __enqueueTimer = setTimeout(async () => {
4559
+ if (__hooks.length) await Promise.all(__hooks.map((cb) => cb()));
4560
+ performReactRefresh();
4561
+ }, 16);
4562
+ }
4563
+ function __predicateOnExport(ignoredExports, moduleExports, predicate) {
4564
+ for (const key in moduleExports) {
4565
+ if (ignoredExports.includes(key)) continue;
4566
+ if (!predicate(key, moduleExports[key])) return key;
4567
+ }
4568
+ return true;
4569
+ }
4570
+ export function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
4571
+ const ignoredExports = window.__getReactRefreshIgnoredExports?.({ id }) ?? [];
4572
+ if (__predicateOnExport(ignoredExports, prevExports, (key) => key in nextExports) !== true) {
4573
+ return 'Could not Fast Refresh (export removed)';
4574
+ }
4575
+ if (__predicateOnExport(ignoredExports, nextExports, (key) => key in prevExports) !== true) {
4576
+ return 'Could not Fast Refresh (new export)';
4577
+ }
4578
+ let hasExports = false;
4579
+ const allExportsAreComponentsOrUnchanged = __predicateOnExport(
4580
+ ignoredExports,
4581
+ nextExports,
4582
+ (key, value) => {
4583
+ hasExports = true;
4584
+ if (isLikelyComponentType(value)) return true;
4585
+ if (__isCompoundComponent(value)) return true;
4586
+ return prevExports[key] === nextExports[key];
4587
+ },
4588
+ );
4589
+ if (hasExports && allExportsAreComponentsOrUnchanged === true) {
4590
+ __enqueueUpdate();
4591
+ } else {
4592
+ return 'Could not Fast Refresh ("' + allExportsAreComponentsOrUnchanged + '" export is incompatible)';
4593
+ }
4594
+ }
4595
+ export const __hmr_import = (module) => import(/* @vite-ignore */ module);
4596
+ `;
4597
+ }
4598
+ });
4599
+
2234
4600
  // src/server/index.ts
2235
4601
  var server_exports = {};
2236
4602
  __export(server_exports, {
2237
4603
  createServer: () => createServer
2238
4604
  });
2239
4605
  import http from "http";
2240
- import path12 from "path";
4606
+ import path15 from "path";
2241
4607
  import os from "os";
2242
4608
  import connect from "connect";
2243
4609
  import sirv from "sirv";
2244
4610
  import { watch } from "chokidar";
2245
- import pc3 from "picocolors";
4611
+ import pc9 from "picocolors";
2246
4612
  async function createServer(inlineConfig = {}) {
4613
+ const startTime = performance.now();
2247
4614
  const config = await resolveConfig(inlineConfig, "serve");
2248
- const allPlugins = [
2249
- ...config.framework === "vue" ? [vuePlugin(config)] : [],
2250
- resolvePlugin(config),
2251
- cssPlugin(config),
2252
- assetsPlugin(config),
2253
- htmlPlugin(config),
2254
- ...config.plugins
2255
- ];
4615
+ const logger = config.logger;
4616
+ const allPlugins = resolvePluginList(config, config.plugins);
2256
4617
  const configWithPlugins = { ...config, plugins: allPlugins };
2257
- const moduleGraph = new ModuleGraph();
2258
- const pluginContainer = new PluginContainer(configWithPlugins);
2259
4618
  const app = connect();
4619
+ const httpServer = http.createServer(app);
4620
+ const ws = createWebSocketServer(httpServer);
4621
+ const clientEnv = new NastiEnvironment("client", configWithPlugins, {
4622
+ hot: createWsHotChannel(ws),
4623
+ mode: "dev",
4624
+ plugins: allPlugins
4625
+ });
4626
+ await clientEnv.init();
4627
+ const environments = { client: clientEnv };
4628
+ for (const name of Object.keys(config.environments)) {
4629
+ if (name === "client") continue;
4630
+ const consumer = config.environments[name].consumer;
4631
+ const envPlugins = resolvePluginList(config, config.plugins, { consumer });
4632
+ environments[name] = new NastiEnvironment(name, { ...config, plugins: envPlugins }, {
4633
+ mode: "dev",
4634
+ plugins: envPlugins
4635
+ });
4636
+ }
4637
+ let ssrRunner = null;
4638
+ async function getSsrRunner() {
4639
+ if (ssrRunner) return ssrRunner;
4640
+ const ssrEnv = environments.ssr;
4641
+ if (!ssrEnv) {
4642
+ throw new Error('[nasti] no "ssr" environment configured (config.environments.ssr)');
4643
+ }
4644
+ await ssrEnv.init();
4645
+ const { createModuleRunner: createModuleRunner2 } = await Promise.resolve().then(() => (init_runnable_environment(), runnable_environment_exports));
4646
+ ssrRunner = createModuleRunner2(ssrEnv);
4647
+ return ssrRunner;
4648
+ }
4649
+ const moduleGraph = clientEnv.moduleGraph;
4650
+ const pluginContainer = clientEnv.pluginContainer;
4651
+ let bundledServer = null;
4652
+ if (config.experimental.bundledDev) {
4653
+ const { createBundledDevServer: createBundledDevServer2 } = await Promise.resolve().then(() => (init_dev_engine(), dev_engine_exports));
4654
+ bundledServer = await createBundledDevServer2({
4655
+ config: configWithPlugins,
4656
+ clientEnv,
4657
+ httpServer
4658
+ });
4659
+ app.use(bundledServer.middleware);
4660
+ }
2260
4661
  app.use(transformMiddleware({
2261
4662
  config: configWithPlugins,
2262
4663
  pluginContainer,
2263
4664
  moduleGraph
2264
4665
  }));
2265
- const publicDir = path12.resolve(config.root, "public");
4666
+ const publicDir = path15.resolve(config.root, "public");
2266
4667
  app.use(sirv(publicDir, { dev: true, etag: true }));
2267
4668
  app.use(sirv(config.root, { dev: true, etag: true }));
2268
- const httpServer = http.createServer(app);
2269
- const ws = createWebSocketServer(httpServer);
2270
4669
  const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
2271
- const outDirAbs = path12.resolve(config.root, config.build.outDir);
4670
+ const outDirAbs = path15.resolve(config.root, config.build.outDir);
2272
4671
  const watcher = watch(config.root, {
2273
4672
  ignored: (filePath) => {
2274
4673
  if (filePath === config.root) return false;
2275
- if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path12.sep)) return true;
2276
- const rel = path12.relative(config.root, filePath);
2277
- if (!rel || rel.startsWith("..") || path12.isAbsolute(rel)) return false;
2278
- for (const seg of rel.split(path12.sep)) {
4674
+ if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path15.sep)) return true;
4675
+ const rel = path15.relative(config.root, filePath);
4676
+ if (!rel || rel.startsWith("..") || path15.isAbsolute(rel)) return false;
4677
+ for (const seg of rel.split(path15.sep)) {
2279
4678
  if (ignoredSegments.has(seg)) return true;
2280
4679
  }
2281
4680
  return false;
@@ -2284,9 +4683,11 @@ async function createServer(inlineConfig = {}) {
2284
4683
  });
2285
4684
  let server;
2286
4685
  watcher.on("change", (file) => {
4686
+ ssrRunner?.invalidateFile(file);
2287
4687
  handleFileChange(file, server);
2288
4688
  });
2289
4689
  watcher.on("add", (file) => {
4690
+ ssrRunner?.invalidateFile(file);
2290
4691
  handleFileChange(file, server);
2291
4692
  });
2292
4693
  server = {
@@ -2295,6 +4696,7 @@ async function createServer(inlineConfig = {}) {
2295
4696
  moduleGraph,
2296
4697
  watcher,
2297
4698
  ws,
4699
+ environments,
2298
4700
  async listen(port) {
2299
4701
  const finalPort = port ?? config.server.port;
2300
4702
  const host = config.server.host === true ? "0.0.0.0" : config.server.host;
@@ -2304,23 +4706,27 @@ async function createServer(inlineConfig = {}) {
2304
4706
  const onListening = () => {
2305
4707
  const actualPort = httpServer.address()?.port ?? currentPort;
2306
4708
  config.server.port = actualPort;
2307
- const localUrl = `http://localhost:${actualPort}`;
2308
- const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}` : null;
2309
- console.log();
2310
- console.log(pc3.cyan(" nasti dev server") + pc3.dim(` v${"1.7.1"}`));
2311
- console.log();
2312
- console.log(` ${pc3.green(">")} Local: ${pc3.cyan(localUrl)}`);
2313
- if (networkUrl) {
2314
- console.log(` ${pc3.green(">")} Network: ${pc3.cyan(networkUrl)}`);
2315
- }
2316
- console.log();
4709
+ const localUrl = `http://localhost:${actualPort}/`;
4710
+ const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}/` : null;
4711
+ logger.clearScreen("info");
4712
+ const readyIn = Math.ceil(performance.now() - startTime);
4713
+ logger.info(
4714
+ `
4715
+ ${pc9.cyan(pc9.bold("NASTI"))} ${pc9.cyan(`v${"2.0.0"}`)} ${pc9.dim("ready in")} ${pc9.bold(readyIn)} ${pc9.dim("ms")}
4716
+ `
4717
+ );
4718
+ printServerUrls(
4719
+ { local: [localUrl], network: networkUrl ? [networkUrl] : [] },
4720
+ logger.info
4721
+ );
4722
+ logger.info("");
2317
4723
  resolve(server);
2318
4724
  };
2319
4725
  httpServer.on("listening", onListening);
2320
4726
  httpServer.on("error", (err) => {
2321
4727
  if (err.code === "EADDRINUSE") {
2322
4728
  currentPort++;
2323
- console.log(pc3.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
4729
+ logger.info(pc9.yellow(`Port ${currentPort - 1} is in use, trying ${currentPort}...`));
2324
4730
  httpServer.listen(currentPort, host);
2325
4731
  } else {
2326
4732
  reject(err);
@@ -2333,8 +4739,13 @@ async function createServer(inlineConfig = {}) {
2333
4739
  const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
2334
4740
  return transformRequest2(url, { config: configWithPlugins, pluginContainer, moduleGraph });
2335
4741
  },
4742
+ async ssrLoadModule(url) {
4743
+ const runner = await getSsrRunner();
4744
+ return runner.import(url);
4745
+ },
2336
4746
  async close() {
2337
4747
  await pluginContainer.buildEnd();
4748
+ await bundledServer?.close();
2338
4749
  watcher.close();
2339
4750
  ws.close();
2340
4751
  httpServer.close();
@@ -2367,16 +4778,13 @@ var init_server = __esm({
2367
4778
  "src/server/index.ts"() {
2368
4779
  "use strict";
2369
4780
  init_config();
2370
- init_plugin_container();
2371
- init_module_graph();
4781
+ init_environment();
4782
+ init_hot_channel();
4783
+ init_logger();
2372
4784
  init_ws();
2373
4785
  init_middleware();
2374
4786
  init_hmr();
2375
- init_resolve();
2376
- init_css();
2377
- init_assets();
2378
- init_vue();
2379
- init_html();
4787
+ init_builtins();
2380
4788
  }
2381
4789
  });
2382
4790
 
@@ -2387,16 +4795,16 @@ init_build();
2387
4795
  // src/build/electron.ts
2388
4796
  init_config();
2389
4797
  init_resolve();
2390
- import path9 from "path";
4798
+ import path10 from "path";
2391
4799
  import fs7 from "fs";
2392
4800
  import { rolldown as rolldown2 } from "rolldown";
2393
- import pc2 from "picocolors";
4801
+ import pc5 from "picocolors";
2394
4802
 
2395
4803
  // src/plugins/electron.ts
2396
- import { builtinModules } from "module";
2397
- var NODE_BUILTINS = /* @__PURE__ */ new Set([
2398
- ...builtinModules,
2399
- ...builtinModules.map((m) => `node:${m}`)
4804
+ import { builtinModules as builtinModules2 } from "module";
4805
+ var NODE_BUILTINS2 = /* @__PURE__ */ new Set([
4806
+ ...builtinModules2,
4807
+ ...builtinModules2.map((m) => `node:${m}`)
2400
4808
  ]);
2401
4809
  var ELECTRON_MODULES = /* @__PURE__ */ new Set([
2402
4810
  "electron",
@@ -2407,7 +4815,7 @@ var ELECTRON_MODULES = /* @__PURE__ */ new Set([
2407
4815
  function electronPlugin(config) {
2408
4816
  const external = /* @__PURE__ */ new Set([
2409
4817
  ...ELECTRON_MODULES,
2410
- ...NODE_BUILTINS,
4818
+ ...NODE_BUILTINS2,
2411
4819
  ...config.electron.external ?? []
2412
4820
  ]);
2413
4821
  return {
@@ -2432,16 +4840,16 @@ async function buildElectron(inlineConfig = {}) {
2432
4840
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
2433
4841
  const startTime = performance.now();
2434
4842
  assertElectronVersion(config);
2435
- console.log(pc2.cyan("\n\u26A1 nasti build (electron)") + pc2.dim(` v${"1.7.1"}`));
2436
- console.log(pc2.dim(` root: ${config.root}`));
2437
- console.log(pc2.dim(` mode: ${config.mode}`));
2438
- console.log(pc2.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
2439
- const outDir = path9.resolve(config.root, config.build.outDir);
4843
+ console.log(pc5.cyan("\n\u26A1 nasti build (electron)") + pc5.dim(` v${"2.0.0"}`));
4844
+ console.log(pc5.dim(` root: ${config.root}`));
4845
+ console.log(pc5.dim(` mode: ${config.mode}`));
4846
+ console.log(pc5.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
4847
+ const outDir = path10.resolve(config.root, config.build.outDir);
2440
4848
  if (config.build.emptyOutDir && fs7.existsSync(outDir)) {
2441
4849
  fs7.rmSync(outDir, { recursive: true, force: true });
2442
4850
  }
2443
4851
  fs7.mkdirSync(outDir, { recursive: true });
2444
- const rendererOutDir = path9.join(outDir, "renderer");
4852
+ const rendererOutDir = path10.join(outDir, "renderer");
2445
4853
  const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
2446
4854
  await build2({
2447
4855
  ...inlineConfig,
@@ -2452,7 +4860,7 @@ async function buildElectron(inlineConfig = {}) {
2452
4860
  emptyOutDir: false
2453
4861
  }
2454
4862
  });
2455
- const mainEntry = path9.resolve(config.root, config.electron.main);
4863
+ const mainEntry = path10.resolve(config.root, config.electron.main);
2456
4864
  if (!fs7.existsSync(mainEntry)) {
2457
4865
  throw new Error(
2458
4866
  `Electron main entry not found: ${config.electron.main}
@@ -2468,10 +4876,10 @@ async function buildElectron(inlineConfig = {}) {
2468
4876
  const preloadFiles = [];
2469
4877
  for (const entry of preloadEntries) {
2470
4878
  if (!fs7.existsSync(entry)) {
2471
- console.warn(pc2.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
4879
+ console.warn(pc5.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
2472
4880
  continue;
2473
4881
  }
2474
- const base = path9.basename(entry).replace(/\.[^.]+$/, "");
4882
+ const base = path10.basename(entry).replace(/\.[^.]+$/, "");
2475
4883
  const out = outFileName(outDir, base, config.electron.preloadFormat);
2476
4884
  await bundleNode(config, entry, {
2477
4885
  outFile: out,
@@ -2481,12 +4889,12 @@ async function buildElectron(inlineConfig = {}) {
2481
4889
  preloadFiles.push(out);
2482
4890
  }
2483
4891
  const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
2484
- console.log(pc2.green(`
4892
+ console.log(pc5.green(`
2485
4893
  \u2713 Electron build complete in ${elapsed}s`));
2486
- console.log(pc2.dim(` renderer: ${path9.relative(config.root, rendererOutDir)}/`));
2487
- console.log(pc2.dim(` main: ${path9.relative(config.root, mainFile)}`));
4894
+ console.log(pc5.dim(` renderer: ${path10.relative(config.root, rendererOutDir)}/`));
4895
+ console.log(pc5.dim(` main: ${path10.relative(config.root, mainFile)}`));
2488
4896
  for (const pf of preloadFiles) {
2489
- console.log(pc2.dim(` preload: ${path9.relative(config.root, pf)}`));
4897
+ console.log(pc5.dim(` preload: ${path10.relative(config.root, pf)}`));
2490
4898
  }
2491
4899
  console.log();
2492
4900
  return { rendererOutDir, mainFile, preloadFiles };
@@ -2512,15 +4920,15 @@ async function bundleNode(config, entry, opts) {
2512
4920
  };
2513
4921
  const { output: userOutput, transform: userTransform, ...restInputOptions } = config.build.rolldownOptions;
2514
4922
  const mergedDefine = { ...userTransform?.define ?? {}, ...envDefine };
2515
- const bundle = await rolldown2({
4923
+ const bundle2 = await rolldown2({
2516
4924
  ...restInputOptions,
2517
4925
  input: entry,
2518
4926
  platform: "node",
2519
4927
  transform: { ...userTransform, define: mergedDefine },
2520
4928
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2521
4929
  });
2522
- fs7.mkdirSync(path9.dirname(opts.outFile), { recursive: true });
2523
- await bundle.write({
4930
+ fs7.mkdirSync(path10.dirname(opts.outFile), { recursive: true });
4931
+ await bundle2.write({
2524
4932
  sourcemap: !!config.build.sourcemap,
2525
4933
  minify: !!config.build.minify,
2526
4934
  // 允许用户微调 output;但主进程 / preload 的单文件约束由下方键强制保证
@@ -2529,24 +4937,24 @@ async function bundleNode(config, entry, opts) {
2529
4937
  format: opts.format === "cjs" ? "cjs" : "esm",
2530
4938
  codeSplitting: false
2531
4939
  });
2532
- await bundle.close();
2533
- console.log(pc2.dim(` \u2713 ${opts.label} \u2192 ${path9.relative(config.root, opts.outFile)}`));
4940
+ await bundle2.close();
4941
+ console.log(pc5.dim(` \u2713 ${opts.label} \u2192 ${path10.relative(config.root, opts.outFile)}`));
2534
4942
  return opts.outFile;
2535
4943
  }
2536
4944
  function outFileName(outDir, base, format) {
2537
4945
  const ext = format === "cjs" ? ".cjs" : ".mjs";
2538
- return path9.join(outDir, base + ext);
4946
+ return path10.join(outDir, base + ext);
2539
4947
  }
2540
4948
  function normalizePreload(preload, root) {
2541
4949
  const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
2542
- return list.map((p) => path9.resolve(root, p));
4950
+ return list.map((p) => path10.resolve(root, p));
2543
4951
  }
2544
4952
  function assertElectronVersion(config) {
2545
4953
  const min = config.electron.minVersion;
2546
4954
  const installed = detectInstalledElectron(config.root);
2547
4955
  if (installed && installed < min) {
2548
4956
  console.warn(
2549
- pc2.yellow(
4957
+ pc5.yellow(
2550
4958
  ` \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`
2551
4959
  )
2552
4960
  );
@@ -2554,7 +4962,7 @@ function assertElectronVersion(config) {
2554
4962
  }
2555
4963
  function detectInstalledElectron(root) {
2556
4964
  try {
2557
- const pkgPath = path9.resolve(root, "node_modules/electron/package.json");
4965
+ const pkgPath = path10.resolve(root, "node_modules/electron/package.json");
2558
4966
  if (!fs7.existsSync(pkgPath)) return null;
2559
4967
  const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
2560
4968
  const major = parseInt(String(pkg.version).split(".")[0], 10);
@@ -2569,12 +4977,12 @@ init_server();
2569
4977
 
2570
4978
  // src/server/electron-dev.ts
2571
4979
  init_config();
2572
- import path13 from "path";
2573
- import fs10 from "fs";
2574
- import { createRequire as createRequire4 } from "module";
4980
+ import path16 from "path";
4981
+ import fs11 from "fs";
4982
+ import { createRequire as createRequire5 } from "module";
2575
4983
  import { spawn } from "child_process";
2576
4984
  import chokidar from "chokidar";
2577
- import pc4 from "picocolors";
4985
+ import pc10 from "picocolors";
2578
4986
  import { rolldown as rolldown3 } from "rolldown";
2579
4987
  init_resolve();
2580
4988
  init_transformer();
@@ -2583,17 +4991,17 @@ async function startElectronDev(inlineConfig = {}) {
2583
4991
  const { noSpawn, ...rest } = inlineConfig;
2584
4992
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
2585
4993
  warnElectronVersion(config);
2586
- console.log(pc4.cyan("\n\u26A1 nasti electron dev") + pc4.dim(` v${"1.7.1"}`));
4994
+ console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.0.0"}`));
2587
4995
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
2588
4996
  const server = await createServer2({ ...rest, target: "electron" });
2589
4997
  await server.listen();
2590
4998
  const devUrl = `http://localhost:${server.config.server.port}/`;
2591
- console.log(pc4.dim(` renderer: ${devUrl}`));
2592
- const stageDir = path13.resolve(config.root, ".nasti");
2593
- fs10.mkdirSync(stageDir, { recursive: true });
2594
- const mainEntry = path13.resolve(config.root, config.electron.main);
4999
+ console.log(pc10.dim(` renderer: ${devUrl}`));
5000
+ const stageDir = path16.resolve(config.root, ".nasti");
5001
+ fs11.mkdirSync(stageDir, { recursive: true });
5002
+ const mainEntry = path16.resolve(config.root, config.electron.main);
2595
5003
  const preloadEntries = normalizePreload(config.electron.preload, config.root);
2596
- const builtMainFile = path13.join(stageDir, "main" + extFor(config.electron.mainFormat));
5004
+ const builtMainFile = path16.join(stageDir, "main" + extFor(config.electron.mainFormat));
2597
5005
  const builtPreloadFiles = [];
2598
5006
  const compileAll = async () => {
2599
5007
  await compileNode(config, mainEntry, {
@@ -2603,9 +5011,9 @@ async function startElectronDev(inlineConfig = {}) {
2603
5011
  });
2604
5012
  builtPreloadFiles.length = 0;
2605
5013
  for (const entry of preloadEntries) {
2606
- if (!fs10.existsSync(entry)) continue;
2607
- const base = path13.basename(entry).replace(/\.[^.]+$/, "");
2608
- const out = path13.join(stageDir, base + extFor(config.electron.preloadFormat));
5014
+ if (!fs11.existsSync(entry)) continue;
5015
+ const base = path16.basename(entry).replace(/\.[^.]+$/, "");
5016
+ const out = path16.join(stageDir, base + extFor(config.electron.preloadFormat));
2609
5017
  await compileNode(config, entry, {
2610
5018
  outFile: out,
2611
5019
  format: config.electron.preloadFormat,
@@ -2616,13 +5024,13 @@ async function startElectronDev(inlineConfig = {}) {
2616
5024
  };
2617
5025
  await compileAll();
2618
5026
  if (noSpawn) {
2619
- console.log(pc4.dim(" (noSpawn) \u5DF2\u7F16\u8BD1\u4E3B/preload\uFF0C\u8DF3\u8FC7\u542F\u52A8 Electron\u3002"));
5027
+ console.log(pc10.dim(" (noSpawn) \u5DF2\u7F16\u8BD1\u4E3B/preload\uFF0C\u8DF3\u8FC7\u542F\u52A8 Electron\u3002"));
2620
5028
  return;
2621
5029
  }
2622
5030
  const electronBin = resolveElectronBinary(config);
2623
5031
  if (!electronBin) {
2624
5032
  console.warn(
2625
- pc4.yellow(
5033
+ pc10.yellow(
2626
5034
  " \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"
2627
5035
  )
2628
5036
  );
@@ -2637,14 +5045,14 @@ async function startElectronDev(inlineConfig = {}) {
2637
5045
  });
2638
5046
  child.on("exit", (code) => {
2639
5047
  if (code !== null && child && child.__nastiKilled !== true) {
2640
- console.log(pc4.dim(` Electron exited (${code}).`));
5048
+ console.log(pc10.dim(` Electron exited (${code}).`));
2641
5049
  process.exit(code ?? 0);
2642
5050
  }
2643
5051
  });
2644
5052
  };
2645
5053
  spawnElectron();
2646
5054
  if (config.electron.autoRestart) {
2647
- const watchTargets = [mainEntry, ...preloadEntries].filter(fs10.existsSync);
5055
+ const watchTargets = [mainEntry, ...preloadEntries].filter(fs11.existsSync);
2648
5056
  const watcher = chokidar.watch(watchTargets, { ignoreInitial: true });
2649
5057
  let restarting = null;
2650
5058
  let pending = false;
@@ -2656,7 +5064,7 @@ async function startElectronDev(inlineConfig = {}) {
2656
5064
  restarting = (async () => {
2657
5065
  do {
2658
5066
  pending = false;
2659
- console.log(pc4.cyan("\n \u267B \u4E3B/preload \u53D8\u66F4\uFF0C\u91CD\u542F Electron..."));
5067
+ console.log(pc10.cyan("\n \u267B \u4E3B/preload \u53D8\u66F4\uFF0C\u91CD\u542F Electron..."));
2660
5068
  if (child && !child.killed) {
2661
5069
  ;
2662
5070
  child.__nastiKilled = true;
@@ -2674,7 +5082,7 @@ async function startElectronDev(inlineConfig = {}) {
2674
5082
  await compileAll();
2675
5083
  spawnElectron();
2676
5084
  } catch (e) {
2677
- console.warn(pc4.yellow(` \u26A0 \u91CD\u542F\u7F16\u8BD1\u5931\u8D25\uFF0C\u4FDD\u7559\u4E0A\u4E00\u6B21\u8FDB\u7A0B: ${e.message}`));
5085
+ console.warn(pc10.yellow(` \u26A0 \u91CD\u542F\u7F16\u8BD1\u5931\u8D25\uFF0C\u4FDD\u7559\u4E0A\u4E00\u6B21\u8FDB\u7A0B: ${e.message}`));
2678
5086
  }
2679
5087
  } while (pending);
2680
5088
  restarting = null;
@@ -2714,14 +5122,14 @@ async function compileNode(config, entry, opts) {
2714
5122
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
2715
5123
  }
2716
5124
  };
2717
- const bundle = await rolldown3({
5125
+ const bundle2 = await rolldown3({
2718
5126
  input: entry,
2719
5127
  transform: { define: envDefine },
2720
5128
  platform: "node",
2721
5129
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
2722
5130
  });
2723
- fs10.mkdirSync(path13.dirname(opts.outFile), { recursive: true });
2724
- await bundle.write({
5131
+ fs11.mkdirSync(path16.dirname(opts.outFile), { recursive: true });
5132
+ await bundle2.write({
2725
5133
  file: opts.outFile,
2726
5134
  format: opts.format === "cjs" ? "cjs" : "esm",
2727
5135
  sourcemap: false,
@@ -2730,17 +5138,17 @@ async function compileNode(config, entry, opts) {
2730
5138
  // 同样语义(单 chunk、内联 dynamic import)
2731
5139
  codeSplitting: false
2732
5140
  });
2733
- await bundle.close();
5141
+ await bundle2.close();
2734
5142
  }
2735
5143
  function resolveElectronBinary(config) {
2736
- if (config.electron.electronPath && fs10.existsSync(config.electron.electronPath)) {
5144
+ if (config.electron.electronPath && fs11.existsSync(config.electron.electronPath)) {
2737
5145
  return config.electron.electronPath;
2738
5146
  }
2739
5147
  try {
2740
- const require2 = createRequire4(path13.resolve(config.root, "package.json"));
5148
+ const require2 = createRequire5(path16.resolve(config.root, "package.json"));
2741
5149
  const pathFile = require2.resolve("electron");
2742
5150
  const electronModule = require2(pathFile);
2743
- if (typeof electronModule === "string" && fs10.existsSync(electronModule)) {
5151
+ if (typeof electronModule === "string" && fs11.existsSync(electronModule)) {
2744
5152
  return electronModule;
2745
5153
  }
2746
5154
  } catch {
@@ -2751,7 +5159,7 @@ function warnElectronVersion(config) {
2751
5159
  const installed = detectInstalledElectron(config.root);
2752
5160
  if (installed === null) {
2753
5161
  console.warn(
2754
- pc4.yellow(
5162
+ pc10.yellow(
2755
5163
  ` \u26A0 \u672A\u68C0\u6D4B\u5230 Electron\uFF0C\u8BF7\u5B89\u88C5\uFF1Anpm install -D electron@^${config.electron.minVersion}`
2756
5164
  )
2757
5165
  );
@@ -2759,7 +5167,7 @@ function warnElectronVersion(config) {
2759
5167
  }
2760
5168
  if (installed < config.electron.minVersion) {
2761
5169
  console.warn(
2762
- pc4.yellow(
5170
+ pc10.yellow(
2763
5171
  ` \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`
2764
5172
  )
2765
5173
  );
@@ -2767,10 +5175,10 @@ function warnElectronVersion(config) {
2767
5175
  }
2768
5176
 
2769
5177
  // src/plugins/monaco-editor.ts
2770
- import path14 from "path";
2771
- import fs11 from "fs";
2772
- import crypto3 from "crypto";
2773
- import { createRequire as createRequire5 } from "module";
5178
+ import path17 from "path";
5179
+ import fs12 from "fs";
5180
+ import crypto4 from "crypto";
5181
+ import { createRequire as createRequire6 } from "module";
2774
5182
  var DEFAULT_WORKERS = {
2775
5183
  editorWorkerService: "monaco-editor/esm/vs/editor/editor.worker",
2776
5184
  css: "monaco-editor/esm/vs/language/css/css.worker",
@@ -2789,9 +5197,9 @@ function normalizePublicPath(p) {
2789
5197
  }
2790
5198
  function readMonacoVersion(root) {
2791
5199
  try {
2792
- const require2 = createRequire5(path14.resolve(root, "package.json"));
5200
+ const require2 = createRequire6(path17.resolve(root, "package.json"));
2793
5201
  const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
2794
- const pkg = JSON.parse(fs11.readFileSync(pkgJsonPath, "utf-8"));
5202
+ const pkg = JSON.parse(fs12.readFileSync(pkgJsonPath, "utf-8"));
2795
5203
  return typeof pkg.version === "string" ? pkg.version : "unknown";
2796
5204
  } catch {
2797
5205
  return "unknown";
@@ -2811,32 +5219,32 @@ function monacoEditorPlugin(options = {}) {
2811
5219
  let cacheDir = "";
2812
5220
  const building = /* @__PURE__ */ new Map();
2813
5221
  async function buildWorker(worker) {
2814
- const cacheFile = path14.join(cacheDir, `${worker.label}.worker.js`);
2815
- if (fs11.existsSync(cacheFile)) return cacheFile;
5222
+ const cacheFile = path17.join(cacheDir, `${worker.label}.worker.js`);
5223
+ if (fs12.existsSync(cacheFile)) return cacheFile;
2816
5224
  const existing = building.get(worker.label);
2817
5225
  if (existing) return existing;
2818
5226
  const task = (async () => {
2819
5227
  const { rolldown: rolldown4 } = await import("rolldown");
2820
- const require2 = createRequire5(path14.resolve(resolvedConfig.root, "package.json"));
5228
+ const require2 = createRequire6(path17.resolve(resolvedConfig.root, "package.json"));
2821
5229
  let entry;
2822
5230
  try {
2823
5231
  entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
2824
5232
  } catch {
2825
5233
  entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
2826
5234
  }
2827
- fs11.mkdirSync(cacheDir, { recursive: true });
2828
- const bundle = await rolldown4({
5235
+ fs12.mkdirSync(cacheDir, { recursive: true });
5236
+ const bundle2 = await rolldown4({
2829
5237
  input: entry,
2830
5238
  platform: "browser"
2831
5239
  });
2832
- await bundle.write({
5240
+ await bundle2.write({
2833
5241
  file: cacheFile,
2834
5242
  format: "iife",
2835
5243
  sourcemap: false,
2836
5244
  minify: true,
2837
5245
  codeSplitting: false
2838
5246
  });
2839
- await bundle.close();
5247
+ await bundle2.close();
2840
5248
  return cacheFile;
2841
5249
  })();
2842
5250
  building.set(worker.label, task);
@@ -2883,13 +5291,13 @@ function monacoEditorPlugin(options = {}) {
2883
5291
  configResolved(config) {
2884
5292
  resolvedConfig = config;
2885
5293
  const version = readMonacoVersion(config.root);
2886
- const key = crypto3.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
2887
- cacheDir = path14.resolve(config.root, "node_modules/.nasti/monaco", key);
5294
+ const key = crypto4.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
5295
+ cacheDir = path17.resolve(config.root, "node_modules/.nasti/monaco", key);
2888
5296
  },
2889
5297
  async configureServer(server) {
2890
5298
  const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
2891
5299
  const watcher = server.watcher;
2892
- const monacoDir = path14.resolve(resolvedConfig.root, "node_modules/monaco-editor");
5300
+ const monacoDir = path17.resolve(resolvedConfig.root, "node_modules/monaco-editor");
2893
5301
  try {
2894
5302
  watcher?.unwatch?.(monacoDir);
2895
5303
  } catch {
@@ -2919,7 +5327,7 @@ function monacoEditorPlugin(options = {}) {
2919
5327
  const file = await buildWorker(worker);
2920
5328
  res.setHeader("Content-Type", "application/javascript; charset=utf-8");
2921
5329
  res.setHeader("Cache-Control", "public, max-age=604800, immutable");
2922
- fs11.createReadStream(file).pipe(res);
5330
+ fs12.createReadStream(file).pipe(res);
2923
5331
  } catch (e) {
2924
5332
  res.statusCode = 500;
2925
5333
  res.end(`Monaco worker build failed: ${e.message}`);
@@ -2954,16 +5362,16 @@ self.monaco = monaco;`,
2954
5362
  resolvedConfig.root,
2955
5363
  resolvedConfig.build.outDir,
2956
5364
  resolvedConfig.base
2957
- ) : isCDN(publicPath) ? path14.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path14.resolve(
5365
+ ) : isCDN(publicPath) ? path17.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path17.resolve(
2958
5366
  resolvedConfig.root,
2959
5367
  resolvedConfig.build.outDir,
2960
5368
  publicPath.replace(/^\//, "")
2961
5369
  );
2962
- fs11.mkdirSync(outDir, { recursive: true });
5370
+ fs12.mkdirSync(outDir, { recursive: true });
2963
5371
  for (const worker of workers) {
2964
5372
  try {
2965
5373
  const cacheFile = await buildWorker(worker);
2966
- fs11.copyFileSync(cacheFile, path14.join(outDir, `${worker.label}.worker.js`));
5374
+ fs12.copyFileSync(cacheFile, path17.join(outDir, `${worker.label}.worker.js`));
2967
5375
  } catch (e) {
2968
5376
  throw new Error(
2969
5377
  `[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
@@ -2974,14 +5382,32 @@ ${e.stack || ""}`
2974
5382
  }
2975
5383
  };
2976
5384
  }
5385
+
5386
+ // src/index.ts
5387
+ init_environment();
5388
+ init_hot_channel();
5389
+ init_logger();
5390
+ init_debug();
5391
+ init_env();
2977
5392
  export {
5393
+ LogLevels,
5394
+ NastiEnvironment,
2978
5395
  build,
2979
5396
  buildElectron,
5397
+ buildEnvDefine,
5398
+ createDebugger,
5399
+ createLogger,
5400
+ createNoopHotChannel,
2980
5401
  createServer,
5402
+ createWsHotChannel,
2981
5403
  defineConfig,
2982
5404
  electronPlugin,
5405
+ loadEnv,
2983
5406
  monacoEditorPlugin,
5407
+ printServerUrls,
2984
5408
  resolveConfig,
5409
+ resolveEnvironmentPlugins,
5410
+ ssrDefineOverrides,
2985
5411
  startElectronDev
2986
5412
  };
2987
5413
  //# sourceMappingURL=index.js.map