@nasti-toolchain/nasti 2.2.0 → 2.4.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/README.md +100 -1
- package/bin/nasti.js +0 -0
- package/client/hmr.ts +4 -3
- package/dist/cli.cjs +1480 -363
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1474 -358
- package/dist/cli.js.map +1 -1
- package/dist/client/hmr.cjs.map +1 -1
- package/dist/client/hmr.d.cts +4 -3
- package/dist/client/hmr.d.ts +4 -3
- package/dist/index.cjs +1581 -460
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +167 -13
- package/dist/index.d.ts +167 -13
- package/dist/index.js +1572 -455
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/cli.js
CHANGED
|
@@ -10,10 +10,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
10
10
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
11
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
12
|
});
|
|
13
|
-
var __glob = (map) => (
|
|
14
|
-
var fn = map[
|
|
13
|
+
var __glob = (map) => (path18) => {
|
|
14
|
+
var fn = map[path18];
|
|
15
15
|
if (fn) return fn();
|
|
16
|
-
throw new Error("Module not found in bundle: " +
|
|
16
|
+
throw new Error("Module not found in bundle: " + path18);
|
|
17
17
|
};
|
|
18
18
|
var __esm = (fn, res) => function __init() {
|
|
19
19
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -231,6 +231,92 @@ var init_defaults = __esm({
|
|
|
231
231
|
}
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
+
// src/core/plugin-api.ts
|
|
235
|
+
function orderPlugins(plugins) {
|
|
236
|
+
const baseline = plugins.map((plugin, index2) => ({ plugin, index: index2 })).sort((a, b) => enforceRank(a.plugin) - enforceRank(b.plugin) || a.index - b.index).map(({ plugin }) => plugin);
|
|
237
|
+
const indexesByName = /* @__PURE__ */ new Map();
|
|
238
|
+
baseline.forEach((plugin, index2) => {
|
|
239
|
+
const indexes = indexesByName.get(plugin.name) ?? [];
|
|
240
|
+
indexes.push(index2);
|
|
241
|
+
indexesByName.set(plugin.name, indexes);
|
|
242
|
+
});
|
|
243
|
+
const edges = baseline.map(() => /* @__PURE__ */ new Set());
|
|
244
|
+
const indegree = baseline.map(() => 0);
|
|
245
|
+
const addEdge = (from, to) => {
|
|
246
|
+
if (from === to || edges[from].has(to)) return;
|
|
247
|
+
edges[from].add(to);
|
|
248
|
+
indegree[to]++;
|
|
249
|
+
};
|
|
250
|
+
baseline.forEach((plugin, current) => {
|
|
251
|
+
for (const dependency of plugin.pre ?? []) {
|
|
252
|
+
for (const before of indexesByName.get(dependency) ?? []) addEdge(before, current);
|
|
253
|
+
}
|
|
254
|
+
for (const dependency of plugin.post ?? []) {
|
|
255
|
+
for (const after of indexesByName.get(dependency) ?? []) addEdge(current, after);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
const ready = indegree.map((degree, index2) => ({ degree, index: index2 })).filter(({ degree }) => degree === 0).map(({ index: index2 }) => index2);
|
|
259
|
+
const ordered = [];
|
|
260
|
+
while (ready.length > 0) {
|
|
261
|
+
ready.sort((a, b) => a - b);
|
|
262
|
+
const current = ready.shift();
|
|
263
|
+
ordered.push(baseline[current]);
|
|
264
|
+
for (const next of edges[current]) {
|
|
265
|
+
indegree[next]--;
|
|
266
|
+
if (indegree[next] === 0) ready.push(next);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (ordered.length !== baseline.length) {
|
|
270
|
+
const cyclic = baseline.filter((_, index2) => indegree[index2] > 0).map((plugin) => plugin.name);
|
|
271
|
+
throw new Error(
|
|
272
|
+
`[nasti] circular plugin setup dependency: ${[...new Set(cyclic)].join(", ")}`
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
return ordered;
|
|
276
|
+
}
|
|
277
|
+
async function setupPluginApi(config, plugins) {
|
|
278
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
279
|
+
const api = {
|
|
280
|
+
config,
|
|
281
|
+
logger: config.logger,
|
|
282
|
+
expose(key, value) {
|
|
283
|
+
if (exposed.has(key) && exposed.get(key) !== value) {
|
|
284
|
+
throw new Error(`[nasti] plugin API key already exposed: ${String(key)}`);
|
|
285
|
+
}
|
|
286
|
+
exposed.set(key, value);
|
|
287
|
+
},
|
|
288
|
+
useExposed(key) {
|
|
289
|
+
return exposed.get(key);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
apiByConfig.set(config, api);
|
|
293
|
+
for (const plugin of plugins) {
|
|
294
|
+
await plugin.setup?.(api);
|
|
295
|
+
}
|
|
296
|
+
return api;
|
|
297
|
+
}
|
|
298
|
+
function getPluginApi(config) {
|
|
299
|
+
const api = apiByConfig.get(config);
|
|
300
|
+
if (!api) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
"[nasti] internal: plugin API requested before setup; getPluginApi requires the original ResolvedConfig reference registered by setupPluginApi, not a shallow copy"
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
return api;
|
|
306
|
+
}
|
|
307
|
+
function enforceRank(plugin) {
|
|
308
|
+
if (plugin.enforce === "pre") return 0;
|
|
309
|
+
if (plugin.enforce === "post") return 2;
|
|
310
|
+
return 1;
|
|
311
|
+
}
|
|
312
|
+
var apiByConfig;
|
|
313
|
+
var init_plugin_api = __esm({
|
|
314
|
+
"src/core/plugin-api.ts"() {
|
|
315
|
+
"use strict";
|
|
316
|
+
apiByConfig = /* @__PURE__ */ new WeakMap();
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
234
320
|
// src/config/index.ts
|
|
235
321
|
import { pathToFileURL } from "url";
|
|
236
322
|
import path from "path";
|
|
@@ -268,6 +354,43 @@ async function loadConfigFromFile(root) {
|
|
|
268
354
|
}
|
|
269
355
|
return {};
|
|
270
356
|
}
|
|
357
|
+
function detectFramework(root) {
|
|
358
|
+
const sourceRoot = path.resolve(root, "src");
|
|
359
|
+
if (containsVueFile(sourceRoot)) return "vue";
|
|
360
|
+
const packagePath = path.resolve(root, "package.json");
|
|
361
|
+
if (fs.existsSync(packagePath)) {
|
|
362
|
+
try {
|
|
363
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
364
|
+
const dependencies = {
|
|
365
|
+
...pkg.dependencies ?? {},
|
|
366
|
+
...pkg.devDependencies ?? {},
|
|
367
|
+
...pkg.peerDependencies ?? {},
|
|
368
|
+
...pkg.optionalDependencies ?? {}
|
|
369
|
+
};
|
|
370
|
+
const hasVue = "vue" in dependencies || "@vue/runtime-dom" in dependencies;
|
|
371
|
+
const hasReact = "react" in dependencies || "react-dom" in dependencies;
|
|
372
|
+
if (hasVue && !hasReact) return "vue";
|
|
373
|
+
if (hasReact) return "react";
|
|
374
|
+
if (hasVue) return "vue";
|
|
375
|
+
} catch {
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return "react";
|
|
379
|
+
}
|
|
380
|
+
function containsVueFile(dir, depth = 0) {
|
|
381
|
+
if (depth > 5 || !fs.existsSync(dir)) return false;
|
|
382
|
+
try {
|
|
383
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
384
|
+
if (entry.isFile() && entry.name.endsWith(".vue")) return true;
|
|
385
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && containsVueFile(path.join(dir, entry.name), depth + 1)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
} catch {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
271
394
|
async function loadTsConfig(filePath) {
|
|
272
395
|
const { transformSync: transformSync2 } = await import("oxc-transform");
|
|
273
396
|
const code = fs.readFileSync(filePath, "utf-8");
|
|
@@ -314,7 +437,7 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
314
437
|
base: merged.base ?? defaults.base,
|
|
315
438
|
mode,
|
|
316
439
|
target: merged.target ?? defaults.target,
|
|
317
|
-
framework: merged.framework ?? defaults.framework,
|
|
440
|
+
framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
|
|
318
441
|
command,
|
|
319
442
|
resolve: {
|
|
320
443
|
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
@@ -361,7 +484,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
361
484
|
if (envOptions.build) Object.assign(resolved.build, envOptions.build);
|
|
362
485
|
resolved.environments.client = {
|
|
363
486
|
consumer,
|
|
364
|
-
|
|
487
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
488
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
489
|
+
html: path.resolve(
|
|
490
|
+
root,
|
|
491
|
+
envOptions.html ?? (resolved.target === "electron" ? resolved.electron.renderer : "index.html")
|
|
492
|
+
),
|
|
493
|
+
driver: envOptions.driver,
|
|
365
494
|
// 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
|
|
366
495
|
resolve: resolved.resolve,
|
|
367
496
|
build: resolved.build
|
|
@@ -370,7 +499,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
370
499
|
}
|
|
371
500
|
resolved.environments[name] = {
|
|
372
501
|
consumer,
|
|
373
|
-
|
|
502
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
503
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
504
|
+
html: envOptions.consumer === "client" && envOptions.html ? path.resolve(root, envOptions.html) : void 0,
|
|
505
|
+
driver: envOptions.driver,
|
|
374
506
|
resolve: {
|
|
375
507
|
alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
|
|
376
508
|
extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
|
|
@@ -389,12 +521,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
389
521
|
};
|
|
390
522
|
}
|
|
391
523
|
assertClientEnvironmentMirror(resolved);
|
|
392
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
524
|
+
const filteredPlugins = orderPlugins(rawPlugins.filter((p) => {
|
|
393
525
|
if (!p.apply) return true;
|
|
394
526
|
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
395
527
|
return p.apply === command;
|
|
396
|
-
});
|
|
528
|
+
}));
|
|
397
529
|
resolved.plugins = filteredPlugins;
|
|
530
|
+
await setupPluginApi(resolved, filteredPlugins);
|
|
398
531
|
if (resolved.target === "electron") {
|
|
399
532
|
const autoExternal = detectNativeDeps(root);
|
|
400
533
|
if (autoExternal.length > 0) {
|
|
@@ -410,6 +543,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
410
543
|
}
|
|
411
544
|
return resolved;
|
|
412
545
|
}
|
|
546
|
+
function normalizeEnvironmentEntries(entry, root) {
|
|
547
|
+
const entries = Array.isArray(entry) ? entry : entry ? [entry] : [];
|
|
548
|
+
return entries.map((item) => path.resolve(root, item));
|
|
549
|
+
}
|
|
413
550
|
function detectNativeDeps(root) {
|
|
414
551
|
const result = /* @__PURE__ */ new Set();
|
|
415
552
|
const pkgJsonPath = path.resolve(root, "package.json");
|
|
@@ -527,6 +664,7 @@ var init_config = __esm({
|
|
|
527
664
|
"use strict";
|
|
528
665
|
init_defaults();
|
|
529
666
|
init_logger();
|
|
667
|
+
init_plugin_api();
|
|
530
668
|
CONFIG_FILES = [
|
|
531
669
|
"nasti.config.ts",
|
|
532
670
|
"nasti.config.js",
|
|
@@ -537,21 +675,11 @@ var init_config = __esm({
|
|
|
537
675
|
});
|
|
538
676
|
|
|
539
677
|
// src/core/plugin-container.ts
|
|
540
|
-
function sortPlugins(plugins) {
|
|
541
|
-
const pre = [];
|
|
542
|
-
const normal = [];
|
|
543
|
-
const post = [];
|
|
544
|
-
for (const plugin of plugins) {
|
|
545
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
546
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
547
|
-
else normal.push(plugin);
|
|
548
|
-
}
|
|
549
|
-
return [...pre, ...normal, ...post];
|
|
550
|
-
}
|
|
551
678
|
var PluginContainer;
|
|
552
679
|
var init_plugin_container = __esm({
|
|
553
680
|
"src/core/plugin-container.ts"() {
|
|
554
681
|
"use strict";
|
|
682
|
+
init_plugin_api();
|
|
555
683
|
PluginContainer = class {
|
|
556
684
|
plugins;
|
|
557
685
|
config;
|
|
@@ -562,7 +690,7 @@ var init_plugin_container = __esm({
|
|
|
562
690
|
constructor(config, environment) {
|
|
563
691
|
this.config = config;
|
|
564
692
|
this.environment = environment;
|
|
565
|
-
this.plugins =
|
|
693
|
+
this.plugins = orderPlugins(config.plugins);
|
|
566
694
|
this.ctx = this.createContext();
|
|
567
695
|
}
|
|
568
696
|
createContext() {
|
|
@@ -661,17 +789,35 @@ var init_plugin_container = __esm({
|
|
|
661
789
|
}
|
|
662
790
|
});
|
|
663
791
|
|
|
792
|
+
// src/core/url.ts
|
|
793
|
+
function removeTimestampQuery(url) {
|
|
794
|
+
const hashIndex = url.indexOf("#");
|
|
795
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
796
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
797
|
+
const queryIndex = withoutHash.indexOf("?");
|
|
798
|
+
if (queryIndex < 0) return url;
|
|
799
|
+
const pathname = withoutHash.slice(0, queryIndex);
|
|
800
|
+
const query = withoutHash.slice(queryIndex + 1).split("&").filter((part) => !/^t=\d+$/.test(part)).join("&");
|
|
801
|
+
return pathname + (query ? `?${query}` : "") + hash;
|
|
802
|
+
}
|
|
803
|
+
var init_url = __esm({
|
|
804
|
+
"src/core/url.ts"() {
|
|
805
|
+
"use strict";
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
|
|
664
809
|
// src/core/module-graph.ts
|
|
665
810
|
var ModuleGraph;
|
|
666
811
|
var init_module_graph = __esm({
|
|
667
812
|
"src/core/module-graph.ts"() {
|
|
668
813
|
"use strict";
|
|
814
|
+
init_url();
|
|
669
815
|
ModuleGraph = class {
|
|
670
816
|
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
671
817
|
idToModuleMap = /* @__PURE__ */ new Map();
|
|
672
818
|
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
673
819
|
getModuleByUrl(url) {
|
|
674
|
-
return this.urlToModuleMap.get(url);
|
|
820
|
+
return this.urlToModuleMap.get(removeTimestampQuery(url));
|
|
675
821
|
}
|
|
676
822
|
getModuleById(id) {
|
|
677
823
|
return this.idToModuleMap.get(id);
|
|
@@ -680,10 +826,11 @@ var init_module_graph = __esm({
|
|
|
680
826
|
return this.fileToModulesMap.get(file);
|
|
681
827
|
}
|
|
682
828
|
async ensureEntryFromUrl(url) {
|
|
683
|
-
|
|
829
|
+
const normalizedUrl = removeTimestampQuery(url);
|
|
830
|
+
let mod = this.urlToModuleMap.get(normalizedUrl);
|
|
684
831
|
if (mod) return mod;
|
|
685
|
-
mod = this.createModule(
|
|
686
|
-
this.urlToModuleMap.set(
|
|
832
|
+
mod = this.createModule(normalizedUrl);
|
|
833
|
+
this.urlToModuleMap.set(normalizedUrl, mod);
|
|
687
834
|
return mod;
|
|
688
835
|
}
|
|
689
836
|
createModule(url, id) {
|
|
@@ -697,6 +844,7 @@ var init_module_graph = __esm({
|
|
|
697
844
|
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
698
845
|
transformResult: null,
|
|
699
846
|
lastHMRTimestamp: 0,
|
|
847
|
+
invalidationVersion: 0,
|
|
700
848
|
isSelfAccepting: false
|
|
701
849
|
};
|
|
702
850
|
this.idToModuleMap.set(mod.id, mod);
|
|
@@ -739,10 +887,64 @@ var init_module_graph = __esm({
|
|
|
739
887
|
}
|
|
740
888
|
}
|
|
741
889
|
}
|
|
890
|
+
/**
|
|
891
|
+
* 用一次转换得到的信息原子更新 import 与 HMR accept 关系。
|
|
892
|
+
* 依赖节点会在真正被浏览器请求前预先创建,这样入口模块先转换时也能建立完整图。
|
|
893
|
+
*/
|
|
894
|
+
async updateModuleInfo(mod, importedUrls, acceptedUrls, isSelfAccepting, expectedInvalidationVersion) {
|
|
895
|
+
const importedModules = await Promise.all(
|
|
896
|
+
[...importedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
897
|
+
);
|
|
898
|
+
const acceptedModules = await Promise.all(
|
|
899
|
+
[...acceptedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
900
|
+
);
|
|
901
|
+
if (expectedInvalidationVersion !== void 0 && mod.invalidationVersion !== expectedInvalidationVersion) {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
const previousImports = new Set(mod.importedModules);
|
|
905
|
+
for (const imported of previousImports) {
|
|
906
|
+
imported.importers.delete(mod);
|
|
907
|
+
}
|
|
908
|
+
mod.importedModules.clear();
|
|
909
|
+
mod.acceptedHmrDeps.clear();
|
|
910
|
+
for (const imported of importedModules) {
|
|
911
|
+
mod.importedModules.add(imported);
|
|
912
|
+
imported.importers.add(mod);
|
|
913
|
+
}
|
|
914
|
+
for (const accepted of acceptedModules) {
|
|
915
|
+
mod.acceptedHmrDeps.add(accepted);
|
|
916
|
+
}
|
|
917
|
+
mod.isSelfAccepting = isSelfAccepting;
|
|
918
|
+
const pruned = /* @__PURE__ */ new Set();
|
|
919
|
+
for (const imported of previousImports) {
|
|
920
|
+
if (!mod.importedModules.has(imported) && imported.importers.size === 0) {
|
|
921
|
+
pruned.add(imported);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
return pruned;
|
|
925
|
+
}
|
|
742
926
|
/** 使模块的转换缓存失效 */
|
|
743
|
-
invalidateModule(mod) {
|
|
927
|
+
invalidateModule(mod, timestamp = Date.now()) {
|
|
744
928
|
mod.transformResult = null;
|
|
745
|
-
mod.lastHMRTimestamp =
|
|
929
|
+
mod.lastHMRTimestamp = timestamp;
|
|
930
|
+
mod.invalidationVersion++;
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* 仅失效到 HMR 边界:显式接受依赖的模块本身不会重执行;自接受模块需要失效,
|
|
934
|
+
* 但不再继续影响其 importer。这样既能传播依赖时间戳,也不会隐式重复副作用。
|
|
935
|
+
*/
|
|
936
|
+
invalidateModuleAndImporters(mod, timestamp = Date.now(), seen = /* @__PURE__ */ new Set()) {
|
|
937
|
+
if (seen.has(mod)) return;
|
|
938
|
+
seen.add(mod);
|
|
939
|
+
this.invalidateModule(mod, timestamp);
|
|
940
|
+
for (const importer of mod.importers) {
|
|
941
|
+
if (importer.acceptedHmrDeps.has(mod)) continue;
|
|
942
|
+
if (importer.isSelfAccepting) {
|
|
943
|
+
this.invalidateModule(importer, timestamp);
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
this.invalidateModuleAndImporters(importer, timestamp, seen);
|
|
947
|
+
}
|
|
746
948
|
}
|
|
747
949
|
/** 使所有模块缓存失效 */
|
|
748
950
|
invalidateAll() {
|
|
@@ -753,34 +955,32 @@ var init_module_graph = __esm({
|
|
|
753
955
|
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
754
956
|
getHmrBoundaries(mod) {
|
|
755
957
|
const boundaries = [];
|
|
756
|
-
const
|
|
757
|
-
const
|
|
758
|
-
if (
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
boundaries.push({ boundary
|
|
762
|
-
return true;
|
|
958
|
+
const traversed = /* @__PURE__ */ new Set();
|
|
959
|
+
const addBoundary = (boundary, acceptedVia) => {
|
|
960
|
+
if (!boundaries.some(
|
|
961
|
+
(item) => item.boundary === boundary && item.acceptedVia === acceptedVia
|
|
962
|
+
)) {
|
|
963
|
+
boundaries.push({ boundary, acceptedVia });
|
|
763
964
|
}
|
|
764
|
-
|
|
765
|
-
|
|
965
|
+
};
|
|
966
|
+
const propagate = (node) => {
|
|
967
|
+
if (traversed.has(node)) return true;
|
|
968
|
+
traversed.add(node);
|
|
969
|
+
if (node.isSelfAccepting) {
|
|
970
|
+
addBoundary(node, node);
|
|
766
971
|
return true;
|
|
767
972
|
}
|
|
768
973
|
if (node.importers.size === 0) return false;
|
|
769
974
|
for (const importer of node.importers) {
|
|
770
|
-
if (
|
|
975
|
+
if (importer.acceptedHmrDeps.has(node)) {
|
|
976
|
+
addBoundary(importer, node);
|
|
977
|
+
continue;
|
|
978
|
+
}
|
|
979
|
+
if (!propagate(importer)) return false;
|
|
771
980
|
}
|
|
772
981
|
return true;
|
|
773
982
|
};
|
|
774
|
-
|
|
775
|
-
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
776
|
-
return boundaries;
|
|
777
|
-
}
|
|
778
|
-
for (const importer of mod.importers) {
|
|
779
|
-
if (!propagate(importer, mod)) {
|
|
780
|
-
return [];
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return boundaries;
|
|
983
|
+
return propagate(mod) ? boundaries : [];
|
|
784
984
|
}
|
|
785
985
|
};
|
|
786
986
|
}
|
|
@@ -901,6 +1101,7 @@ var init_environment = __esm({
|
|
|
901
1101
|
init_module_graph();
|
|
902
1102
|
init_hot_channel();
|
|
903
1103
|
init_debug();
|
|
1104
|
+
init_plugin_api();
|
|
904
1105
|
debug = createDebugger("nasti:environment");
|
|
905
1106
|
NastiEnvironment = class {
|
|
906
1107
|
name;
|
|
@@ -909,6 +1110,7 @@ var init_environment = __esm({
|
|
|
909
1110
|
config;
|
|
910
1111
|
options;
|
|
911
1112
|
hot;
|
|
1113
|
+
driver;
|
|
912
1114
|
/** applyToEnvironment 过滤后的插件(init() 后可用) */
|
|
913
1115
|
plugins = [];
|
|
914
1116
|
/** per-env 插件容器(init() 后可用;dev 管线使用) */
|
|
@@ -916,6 +1118,8 @@ var init_environment = __esm({
|
|
|
916
1118
|
/** per-env 模块图(dev 管线使用) */
|
|
917
1119
|
moduleGraph;
|
|
918
1120
|
candidatePlugins;
|
|
1121
|
+
pluginApi;
|
|
1122
|
+
buildMetadata = {};
|
|
919
1123
|
initialized = false;
|
|
920
1124
|
constructor(name, config, init = {}) {
|
|
921
1125
|
const options = config.environments[name];
|
|
@@ -932,6 +1136,7 @@ var init_environment = __esm({
|
|
|
932
1136
|
this.hot = init.hot ?? createNoopHotChannel();
|
|
933
1137
|
this.moduleGraph = new ModuleGraph();
|
|
934
1138
|
this.candidatePlugins = init.plugins ?? config.plugins;
|
|
1139
|
+
this.pluginApi = init.pluginApi ?? getPluginApi(config);
|
|
935
1140
|
}
|
|
936
1141
|
/** 过滤插件并建 per-env PluginContainer */
|
|
937
1142
|
async init() {
|
|
@@ -942,10 +1147,57 @@ var init_environment = __esm({
|
|
|
942
1147
|
{ ...this.config, plugins: this.plugins },
|
|
943
1148
|
this
|
|
944
1149
|
);
|
|
1150
|
+
if (this.options.driver) {
|
|
1151
|
+
const claimed = [];
|
|
1152
|
+
for (const plugin of this.plugins) {
|
|
1153
|
+
const driver = await plugin.createEnvironmentDriver?.(this, this.pluginApi);
|
|
1154
|
+
if (driver) claimed.push({ plugin, driver });
|
|
1155
|
+
}
|
|
1156
|
+
if (claimed.length === 0) {
|
|
1157
|
+
throw new Error(
|
|
1158
|
+
`[nasti] environment "${this.name}" requested driver "${this.options.driver}", but no plugin provided it`
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
if (claimed.length > 1) {
|
|
1162
|
+
throw new Error(
|
|
1163
|
+
`[nasti] environment "${this.name}" was claimed by multiple drivers: ` + claimed.map(({ plugin, driver }) => `${plugin.name} (${driver.name})`).join(", ")
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
this.driver = claimed[0].driver;
|
|
1167
|
+
debug?.(`env "${this.name}" uses driver "${this.driver.name}"`);
|
|
1168
|
+
}
|
|
945
1169
|
debug?.(`env "${this.name}" initialized (${this.plugins.length} plugins)`);
|
|
946
1170
|
}
|
|
1171
|
+
getDriverContext() {
|
|
1172
|
+
return {
|
|
1173
|
+
environment: this,
|
|
1174
|
+
config: this.config,
|
|
1175
|
+
api: this.pluginApi,
|
|
1176
|
+
logger: this.config.logger
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
setBuildMetadata(metadata) {
|
|
1180
|
+
const { entries: currentEntries, ...currentMetadata } = this.buildMetadata;
|
|
1181
|
+
const { entries, ...nextMetadata } = metadata;
|
|
1182
|
+
this.buildMetadata = {
|
|
1183
|
+
...currentMetadata,
|
|
1184
|
+
...nextMetadata,
|
|
1185
|
+
...currentEntries || entries ? { entries: { ...currentEntries, ...entries } } : {}
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
1188
|
+
getBuildMetadata() {
|
|
1189
|
+
const { entries, ...metadata } = this.buildMetadata;
|
|
1190
|
+
return {
|
|
1191
|
+
...metadata,
|
|
1192
|
+
...entries ? { entries: { ...entries } } : {}
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
947
1195
|
async close() {
|
|
948
|
-
|
|
1196
|
+
try {
|
|
1197
|
+
await this.driver?.close?.(this.getDriverContext());
|
|
1198
|
+
} finally {
|
|
1199
|
+
await this.hot.close?.();
|
|
1200
|
+
}
|
|
949
1201
|
}
|
|
950
1202
|
};
|
|
951
1203
|
}
|
|
@@ -1010,7 +1262,8 @@ function transformCode(filename, code, options = {}) {
|
|
|
1010
1262
|
importSource: options.jsxImportSource ?? "react",
|
|
1011
1263
|
refresh: options.reactRefresh ?? false
|
|
1012
1264
|
} : void 0,
|
|
1013
|
-
sourcemap: options.sourcemap ?? true
|
|
1265
|
+
sourcemap: options.sourcemap ?? true,
|
|
1266
|
+
target: options.target
|
|
1014
1267
|
});
|
|
1015
1268
|
if (result.errors && result.errors.length > 0) {
|
|
1016
1269
|
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
@@ -1042,7 +1295,7 @@ function htmlPlugin(config) {
|
|
|
1042
1295
|
transformIndexHtml(html) {
|
|
1043
1296
|
const tags = [];
|
|
1044
1297
|
if (config.command === "serve") {
|
|
1045
|
-
const isReactLike = config.framework === "react"
|
|
1298
|
+
const isReactLike = config.framework === "react";
|
|
1046
1299
|
if (isReactLike) {
|
|
1047
1300
|
tags.push({
|
|
1048
1301
|
tag: "script",
|
|
@@ -1096,8 +1349,8 @@ function serializeTag(tag) {
|
|
|
1096
1349
|
}
|
|
1097
1350
|
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
1098
1351
|
}
|
|
1099
|
-
async function readHtmlFile(root) {
|
|
1100
|
-
const htmlPath = path2.resolve(root,
|
|
1352
|
+
async function readHtmlFile(root, htmlFile = "index.html") {
|
|
1353
|
+
const htmlPath = path2.isAbsolute(htmlFile) ? htmlFile : path2.resolve(root, htmlFile);
|
|
1101
1354
|
if (!fs2.existsSync(htmlPath)) return null;
|
|
1102
1355
|
return fs2.readFileSync(htmlPath, "utf-8");
|
|
1103
1356
|
}
|
|
@@ -1192,8 +1445,10 @@ import fs4 from "fs";
|
|
|
1192
1445
|
import { createRequire } from "module";
|
|
1193
1446
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
1194
1447
|
import pc3 from "picocolors";
|
|
1195
|
-
function getReactRefreshRuntimeEsm() {
|
|
1196
|
-
if (__refreshRuntimeCache)
|
|
1448
|
+
function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
|
|
1449
|
+
if (__refreshRuntimeCache) {
|
|
1450
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
1451
|
+
}
|
|
1197
1452
|
let cjsPath;
|
|
1198
1453
|
try {
|
|
1199
1454
|
const pkgPath = __require2.resolve("react-refresh/package.json");
|
|
@@ -1228,7 +1483,7 @@ export const findAffectedHostInstances = __rt.findAffectedHostInstances;
|
|
|
1228
1483
|
export const collectCustomHooksForSignature = __rt.collectCustomHooksForSignature;
|
|
1229
1484
|
export default __rt;
|
|
1230
1485
|
`;
|
|
1231
|
-
return __refreshRuntimeCache;
|
|
1486
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
1232
1487
|
}
|
|
1233
1488
|
function buildReactRefreshWrapper(moduleUrl, transformedCode) {
|
|
1234
1489
|
const urlLit = JSON.stringify(moduleUrl);
|
|
@@ -1254,22 +1509,40 @@ window.$RefreshReg$ = prevRefreshReg;
|
|
|
1254
1509
|
window.$RefreshSig$ = prevRefreshSig;
|
|
1255
1510
|
|
|
1256
1511
|
if (__nasti_hot__) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1512
|
+
let __nasti_current_exports__;
|
|
1513
|
+
__nasti_hot__.accept((nextExports) => {
|
|
1514
|
+
if (!nextExports) return;
|
|
1515
|
+
if (!__nasti_current_exports__) {
|
|
1516
|
+
__nasti_hot__.invalidate('Could not Fast Refresh (previous exports unavailable)');
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(
|
|
1520
|
+
${urlLit},
|
|
1521
|
+
__nasti_current_exports__,
|
|
1522
|
+
nextExports,
|
|
1523
|
+
);
|
|
1524
|
+
if (invalidateMessage) __nasti_hot__.invalidate(invalidateMessage);
|
|
1525
|
+
});
|
|
1526
|
+
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
|
|
1527
|
+
__nasti_current_exports__ = currentExports;
|
|
1528
|
+
RefreshRuntime.registerExportsForReactRefresh(${urlLit}, currentExports);
|
|
1262
1529
|
});
|
|
1263
1530
|
}
|
|
1264
1531
|
`;
|
|
1265
1532
|
}
|
|
1266
1533
|
function injectImportMetaHot(code, moduleUrl) {
|
|
1267
|
-
|
|
1534
|
+
const hotRE = /\bimport\.meta\.hot\b/g;
|
|
1535
|
+
const matches = [...maskStringsAndComments(code).matchAll(hotRE)];
|
|
1536
|
+
if (matches.length === 0) return code;
|
|
1537
|
+
for (const match of matches.reverse()) {
|
|
1538
|
+
const start = match.index;
|
|
1539
|
+
code = code.slice(0, start) + "__nasti_hot__" + code.slice(start + match[0].length);
|
|
1540
|
+
}
|
|
1268
1541
|
const urlLit = JSON.stringify(moduleUrl);
|
|
1269
1542
|
const header = `import { createHotContext as __nasti_createHotContext__ } from "/@nasti/client";
|
|
1270
1543
|
const __nasti_hot__ = __nasti_createHotContext__(${urlLit});
|
|
1271
1544
|
`;
|
|
1272
|
-
return header + code
|
|
1545
|
+
return header + code;
|
|
1273
1546
|
}
|
|
1274
1547
|
function transformMiddleware(ctx) {
|
|
1275
1548
|
ctx.envDefine = buildEnvDefine(
|
|
@@ -1296,7 +1569,10 @@ function transformMiddleware(ctx) {
|
|
|
1296
1569
|
return;
|
|
1297
1570
|
}
|
|
1298
1571
|
if (url === "/" || url.endsWith(".html")) {
|
|
1299
|
-
const html = await readHtmlFile(
|
|
1572
|
+
const html = await readHtmlFile(
|
|
1573
|
+
ctx.config.root,
|
|
1574
|
+
ctx.config.environments.client?.html
|
|
1575
|
+
);
|
|
1300
1576
|
if (html) {
|
|
1301
1577
|
let processedHtml = html;
|
|
1302
1578
|
for (const plugin of ctx.config.plugins) {
|
|
@@ -1342,13 +1618,14 @@ function transformMiddleware(ctx) {
|
|
|
1342
1618
|
}
|
|
1343
1619
|
async function transformRequest(url, ctx) {
|
|
1344
1620
|
const { config, pluginContainer, moduleGraph } = ctx;
|
|
1621
|
+
url = removeTimestampQuery(url);
|
|
1345
1622
|
const cleanReqUrl = url.split("?")[0];
|
|
1346
1623
|
const cached2 = moduleGraph.getModuleByUrl(url);
|
|
1347
1624
|
if (cached2?.transformResult) {
|
|
1348
1625
|
return cached2.transformResult;
|
|
1349
1626
|
}
|
|
1350
1627
|
if (cleanReqUrl === "/@react-refresh") {
|
|
1351
|
-
return { code: getReactRefreshRuntimeEsm() };
|
|
1628
|
+
return { code: getReactRefreshRuntimeEsm(true) };
|
|
1352
1629
|
}
|
|
1353
1630
|
if (cleanReqUrl.startsWith("/@modules/") && url.includes("?")) {
|
|
1354
1631
|
const idParam = new URLSearchParams(url.slice(url.indexOf("?") + 1)).get("id");
|
|
@@ -1384,6 +1661,8 @@ async function transformRequest(url, ctx) {
|
|
|
1384
1661
|
}
|
|
1385
1662
|
const rawQuery = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
|
|
1386
1663
|
if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
|
|
1664
|
+
const mod2 = await moduleGraph.ensureEntryFromUrl(url);
|
|
1665
|
+
const transformVersion2 = mod2.invalidationVersion;
|
|
1387
1666
|
const loaded = await pluginContainer.load(url);
|
|
1388
1667
|
if (loaded != null) {
|
|
1389
1668
|
let code2 = typeof loaded === "string" ? loaded : loaded.code;
|
|
@@ -1391,16 +1670,28 @@ async function transformRequest(url, ctx) {
|
|
|
1391
1670
|
if (transformed != null) {
|
|
1392
1671
|
code2 = typeof transformed === "string" ? transformed : transformed.code;
|
|
1393
1672
|
}
|
|
1394
|
-
const
|
|
1395
|
-
moduleGraph.registerModule(mod2,
|
|
1396
|
-
|
|
1673
|
+
const parentFile = resolveUrlToFile(cleanReqUrl, config.root) ?? cleanReqUrl;
|
|
1674
|
+
moduleGraph.registerModule(mod2, parentFile);
|
|
1675
|
+
const hotInfo2 = rewriteHotAcceptDeps(code2, config, parentFile);
|
|
1676
|
+
code2 = injectImportMetaHot(hotInfo2.code, url);
|
|
1397
1677
|
code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
|
|
1398
1678
|
loadEnv(config.mode, config.root, config.envPrefix),
|
|
1399
1679
|
config.mode
|
|
1400
1680
|
));
|
|
1401
|
-
|
|
1681
|
+
const importedUrls2 = /* @__PURE__ */ new Set();
|
|
1682
|
+
code2 = rewriteImports(code2, config, parentFile, importedUrls2, moduleGraph);
|
|
1683
|
+
const pruned2 = await moduleGraph.updateModuleInfo(
|
|
1684
|
+
mod2,
|
|
1685
|
+
importedUrls2,
|
|
1686
|
+
hotInfo2.acceptedUrls,
|
|
1687
|
+
hotInfo2.isSelfAccepting,
|
|
1688
|
+
transformVersion2
|
|
1689
|
+
);
|
|
1402
1690
|
const transformResult2 = { code: code2 };
|
|
1403
|
-
|
|
1691
|
+
if (pruned2) {
|
|
1692
|
+
if (pruned2.size > 0) ctx.onPrune?.([...pruned2].map((item) => item.url));
|
|
1693
|
+
mod2.transformResult = transformResult2;
|
|
1694
|
+
}
|
|
1404
1695
|
return transformResult2;
|
|
1405
1696
|
}
|
|
1406
1697
|
}
|
|
@@ -1408,6 +1699,7 @@ async function transformRequest(url, ctx) {
|
|
|
1408
1699
|
if (!filePath || !fs4.existsSync(filePath)) return null;
|
|
1409
1700
|
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
1410
1701
|
moduleGraph.registerModule(mod, filePath);
|
|
1702
|
+
const transformVersion = mod.invalidationVersion;
|
|
1411
1703
|
if (cleanReqUrl.startsWith("/@modules/")) {
|
|
1412
1704
|
const code2 = await bundlePackageAsEsm(filePath, config.root);
|
|
1413
1705
|
const transformResult2 = { code: code2 };
|
|
@@ -1434,9 +1726,10 @@ async function transformRequest(url, ctx) {
|
|
|
1434
1726
|
if (useRefresh) {
|
|
1435
1727
|
code = buildReactRefreshWrapper(stableUrl, code);
|
|
1436
1728
|
wrappedWithRefresh = true;
|
|
1437
|
-
mod.isSelfAccepting = true;
|
|
1438
1729
|
}
|
|
1439
1730
|
}
|
|
1731
|
+
const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
|
|
1732
|
+
code = hotInfo.code;
|
|
1440
1733
|
if (!wrappedWithRefresh) {
|
|
1441
1734
|
code = injectImportMetaHot(code, stableUrl);
|
|
1442
1735
|
}
|
|
@@ -1445,9 +1738,20 @@ async function transformRequest(url, ctx) {
|
|
|
1445
1738
|
config.mode
|
|
1446
1739
|
);
|
|
1447
1740
|
code = replaceEnvInCode(code, envDefine);
|
|
1448
|
-
|
|
1741
|
+
const importedUrls = /* @__PURE__ */ new Set();
|
|
1742
|
+
code = rewriteImports(code, config, filePath, importedUrls, moduleGraph);
|
|
1743
|
+
const pruned = await moduleGraph.updateModuleInfo(
|
|
1744
|
+
mod,
|
|
1745
|
+
importedUrls,
|
|
1746
|
+
hotInfo.acceptedUrls,
|
|
1747
|
+
wrappedWithRefresh || hotInfo.isSelfAccepting,
|
|
1748
|
+
transformVersion
|
|
1749
|
+
);
|
|
1449
1750
|
const transformResult = { code };
|
|
1450
|
-
|
|
1751
|
+
if (pruned) {
|
|
1752
|
+
if (pruned.size > 0) ctx.onPrune?.([...pruned].map((item) => item.url));
|
|
1753
|
+
mod.transformResult = transformResult;
|
|
1754
|
+
}
|
|
1451
1755
|
return transformResult;
|
|
1452
1756
|
}
|
|
1453
1757
|
async function loadVirtualModule(spec, ctx) {
|
|
@@ -1652,49 +1956,202 @@ async function injectCjsNamedExports(code, entryFile) {
|
|
|
1652
1956
|
return code;
|
|
1653
1957
|
}
|
|
1654
1958
|
}
|
|
1655
|
-
function rewriteImports(code, config, filePath) {
|
|
1959
|
+
function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
|
|
1960
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
1961
|
+
const transformSpec = (spec) => {
|
|
1962
|
+
const resolved = removeTimestampQuery(resolveSpec(spec));
|
|
1963
|
+
importedUrls?.add(resolved);
|
|
1964
|
+
const timestamp = moduleGraph?.getModuleByUrl(resolved)?.lastHMRTimestamp ?? 0;
|
|
1965
|
+
return timestamp > 0 ? appendTimestampQuery(resolved, timestamp) : resolved;
|
|
1966
|
+
};
|
|
1967
|
+
return code.replace(
|
|
1968
|
+
/\bfrom\s+(['"])([^'"]+)\1/g,
|
|
1969
|
+
(_m, q, s) => `from ${q}${transformSpec(s)}${q}`
|
|
1970
|
+
).replace(
|
|
1971
|
+
/\bimport\s+(['"])([^'"]+)\1/g,
|
|
1972
|
+
(_m, q, s) => `import ${q}${transformSpec(s)}${q}`
|
|
1973
|
+
).replace(
|
|
1974
|
+
/\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g,
|
|
1975
|
+
(_m, q, s) => `import(${q}${transformSpec(s)}${q})`
|
|
1976
|
+
);
|
|
1977
|
+
}
|
|
1978
|
+
function createModuleSpecifierResolver(config, filePath) {
|
|
1656
1979
|
const root = config.root;
|
|
1657
1980
|
const fileDir = path4.dirname(filePath);
|
|
1658
1981
|
const aliasEntries = Object.entries(config.resolve.alias).sort(
|
|
1659
1982
|
([a], [b]) => b.length - a.length
|
|
1660
1983
|
);
|
|
1661
1984
|
const toRootUrl = (abs) => "/" + path4.relative(root, abs).replace(/\\/g, "/");
|
|
1662
|
-
|
|
1663
|
-
const suffixMatch =
|
|
1985
|
+
return (specifier) => {
|
|
1986
|
+
const suffixMatch = specifier.match(/[?#].*$/);
|
|
1664
1987
|
const suffix = suffixMatch ? suffixMatch[0] : "";
|
|
1665
|
-
const baseSpec = suffix ?
|
|
1988
|
+
const baseSpec = suffix ? specifier.slice(0, -suffix.length) : specifier;
|
|
1666
1989
|
for (const [key, value] of aliasEntries) {
|
|
1667
1990
|
if (baseSpec === key || baseSpec.startsWith(key + "/")) {
|
|
1668
1991
|
const aliasBase = resolveAliasTarget(value, root);
|
|
1669
1992
|
const sub = baseSpec.slice(key.length).replace(/^\//, "");
|
|
1670
1993
|
const target = sub ? path4.join(aliasBase, sub) : aliasBase;
|
|
1671
1994
|
const resolved = tryResolveDiskPath(target);
|
|
1672
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix :
|
|
1995
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
1673
1996
|
}
|
|
1674
1997
|
}
|
|
1675
1998
|
if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
|
|
1999
|
+
const resolved = tryResolveDiskPath(path4.resolve(fileDir, baseSpec));
|
|
2000
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
1679
2001
|
}
|
|
1680
2002
|
if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
|
|
1681
|
-
const
|
|
1682
|
-
|
|
1683
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
|
|
2003
|
+
const resolved = tryResolveDiskPath(path4.join(root, baseSpec.replace(/^\//, "")));
|
|
2004
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
1684
2005
|
}
|
|
1685
|
-
if (baseSpec.startsWith("/")) return
|
|
1686
|
-
return `/@modules/${
|
|
2006
|
+
if (baseSpec.startsWith("/")) return specifier;
|
|
2007
|
+
return `/@modules/${specifier}`;
|
|
1687
2008
|
};
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
)
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
)
|
|
2009
|
+
}
|
|
2010
|
+
function rewriteHotAcceptDeps(code, config, filePath) {
|
|
2011
|
+
const acceptedUrls = /* @__PURE__ */ new Set();
|
|
2012
|
+
const edits = [];
|
|
2013
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
2014
|
+
const acceptRE = /(?:\bimport\.meta\.hot|\b__nasti_hot__)(?:(?:\?\.)|\.)accept\s*\(/g;
|
|
2015
|
+
const searchableCode = maskStringsAndComments(code);
|
|
2016
|
+
let isSelfAccepting = false;
|
|
2017
|
+
let match;
|
|
2018
|
+
while (match = acceptRE.exec(searchableCode)) {
|
|
2019
|
+
let cursor = match.index + match[0].length;
|
|
2020
|
+
const skipTrivia = () => {
|
|
2021
|
+
while (cursor < code.length) {
|
|
2022
|
+
if (/\s/.test(code[cursor])) {
|
|
2023
|
+
cursor++;
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
if (code[cursor] === "/" && code[cursor + 1] === "/") {
|
|
2027
|
+
cursor += 2;
|
|
2028
|
+
while (cursor < code.length && code[cursor] !== "\n") cursor++;
|
|
2029
|
+
continue;
|
|
2030
|
+
}
|
|
2031
|
+
if (code[cursor] === "/" && code[cursor + 1] === "*") {
|
|
2032
|
+
cursor += 2;
|
|
2033
|
+
while (cursor < code.length && !(code[cursor] === "*" && code[cursor + 1] === "/")) cursor++;
|
|
2034
|
+
cursor += 2;
|
|
2035
|
+
continue;
|
|
2036
|
+
}
|
|
2037
|
+
break;
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
skipTrivia();
|
|
2041
|
+
const first = code[cursor];
|
|
2042
|
+
if (!first || first === ")" || first !== "[" && first !== "'" && first !== '"' && first !== "`") {
|
|
2043
|
+
isSelfAccepting = true;
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
const readLiteral = () => {
|
|
2047
|
+
const quote = code[cursor];
|
|
2048
|
+
if (quote !== "'" && quote !== '"' && quote !== "`") return;
|
|
2049
|
+
const start = cursor;
|
|
2050
|
+
cursor++;
|
|
2051
|
+
let raw = "";
|
|
2052
|
+
while (cursor < code.length) {
|
|
2053
|
+
const char = code[cursor];
|
|
2054
|
+
if (char === "\\") {
|
|
2055
|
+
raw += code[cursor + 1] ?? "";
|
|
2056
|
+
cursor += 2;
|
|
2057
|
+
continue;
|
|
2058
|
+
}
|
|
2059
|
+
if (char === quote) {
|
|
2060
|
+
cursor++;
|
|
2061
|
+
const resolved = removeTimestampQuery(resolveSpec(raw));
|
|
2062
|
+
acceptedUrls.add(resolved);
|
|
2063
|
+
edits.push({ start, end: cursor, value: JSON.stringify(resolved) });
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
if (quote === "`" && char === "$" && code[cursor + 1] === "{") return;
|
|
2067
|
+
raw += char;
|
|
2068
|
+
cursor++;
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
if (first === "[") {
|
|
2072
|
+
cursor++;
|
|
2073
|
+
while (cursor < code.length) {
|
|
2074
|
+
skipTrivia();
|
|
2075
|
+
if (code[cursor] === ",") {
|
|
2076
|
+
cursor++;
|
|
2077
|
+
skipTrivia();
|
|
2078
|
+
}
|
|
2079
|
+
if (code[cursor] === "]") break;
|
|
2080
|
+
const before = cursor;
|
|
2081
|
+
readLiteral();
|
|
2082
|
+
if (cursor === before) break;
|
|
2083
|
+
}
|
|
2084
|
+
} else {
|
|
2085
|
+
readLiteral();
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
2089
|
+
code = code.slice(0, edit.start) + edit.value + code.slice(edit.end);
|
|
2090
|
+
}
|
|
2091
|
+
return { code, acceptedUrls, isSelfAccepting };
|
|
2092
|
+
}
|
|
2093
|
+
function maskStringsAndComments(code) {
|
|
2094
|
+
const masked = code.split("");
|
|
2095
|
+
let state = "code";
|
|
2096
|
+
const isRegexStart = (index2) => {
|
|
2097
|
+
let previous = index2 - 1;
|
|
2098
|
+
while (previous >= 0 && /\s/.test(code[previous])) previous--;
|
|
2099
|
+
return previous < 0 || "=(:,!&|?{};[]+-*%^~<>".includes(code[previous]);
|
|
2100
|
+
};
|
|
2101
|
+
for (let i = 0; i < code.length; i++) {
|
|
2102
|
+
const char = code[i];
|
|
2103
|
+
const next = code[i + 1];
|
|
2104
|
+
if (state === "code") {
|
|
2105
|
+
if (char === "'") state = "single";
|
|
2106
|
+
else if (char === '"') state = "double";
|
|
2107
|
+
else if (char === "`") state = "template";
|
|
2108
|
+
else if (char === "/" && next === "/") state = "line-comment";
|
|
2109
|
+
else if (char === "/" && next === "*") state = "block-comment";
|
|
2110
|
+
else if (char === "/" && isRegexStart(i)) state = "regex";
|
|
2111
|
+
else continue;
|
|
2112
|
+
masked[i] = " ";
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
if (state === "line-comment") {
|
|
2116
|
+
if (char === "\n") {
|
|
2117
|
+
state = "code";
|
|
2118
|
+
} else {
|
|
2119
|
+
masked[i] = " ";
|
|
2120
|
+
}
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
if (state === "block-comment") {
|
|
2124
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
2125
|
+
if (char === "*" && next === "/") {
|
|
2126
|
+
masked[i + 1] = " ";
|
|
2127
|
+
i++;
|
|
2128
|
+
state = "code";
|
|
2129
|
+
}
|
|
2130
|
+
continue;
|
|
2131
|
+
}
|
|
2132
|
+
if (state === "regex" || state === "regex-class") {
|
|
2133
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
2134
|
+
if (char === "\\") {
|
|
2135
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
2136
|
+
} else if (state === "regex" && char === "[") {
|
|
2137
|
+
state = "regex-class";
|
|
2138
|
+
} else if (state === "regex-class" && char === "]") {
|
|
2139
|
+
state = "regex";
|
|
2140
|
+
} else if (state === "regex" && char === "/") {
|
|
2141
|
+
state = "code";
|
|
2142
|
+
}
|
|
2143
|
+
continue;
|
|
2144
|
+
}
|
|
2145
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
2146
|
+
if (char === "\\") {
|
|
2147
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
if (state === "single" && char === "'" || state === "double" && char === '"' || state === "template" && char === "`") {
|
|
2151
|
+
state = "code";
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
return masked.join("");
|
|
1698
2155
|
}
|
|
1699
2156
|
function resolveAliasTarget(value, root) {
|
|
1700
2157
|
if (path4.isAbsolute(value) && fs4.existsSync(value)) return value;
|
|
@@ -1719,6 +2176,12 @@ function isUnderRoot(abs, root) {
|
|
|
1719
2176
|
const rel = path4.relative(root, abs);
|
|
1720
2177
|
return !!rel && !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
1721
2178
|
}
|
|
2179
|
+
function appendTimestampQuery(url, timestamp) {
|
|
2180
|
+
const hashIndex = url.indexOf("#");
|
|
2181
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
2182
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
2183
|
+
return `${withoutHash}${withoutHash.includes("?") ? "&" : "?"}t=${timestamp}${hash}`;
|
|
2184
|
+
}
|
|
1722
2185
|
function externalSpecToModuleUrl(spec, baseDir, root) {
|
|
1723
2186
|
const resolved = resolveNodeModule(baseDir, spec);
|
|
1724
2187
|
if (!resolved) return `/@modules/${spec}`;
|
|
@@ -1862,30 +2325,29 @@ function isModuleRequest(url) {
|
|
|
1862
2325
|
function getHmrClientCode() {
|
|
1863
2326
|
return `
|
|
1864
2327
|
// Nasti HMR Client
|
|
1865
|
-
const
|
|
2328
|
+
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
|
2329
|
+
const socket = new WebSocket(socketProtocol + '://' + location.host, 'nasti-hmr');
|
|
1866
2330
|
const hotModulesMap = new Map();
|
|
1867
2331
|
const disposeMap = new Map();
|
|
1868
2332
|
const pruneMap = new Map();
|
|
2333
|
+
const dataMap = new Map();
|
|
2334
|
+
let updateQueue = [];
|
|
2335
|
+
let pendingUpdateQueue = false;
|
|
1869
2336
|
|
|
1870
2337
|
socket.addEventListener('message', async ({ data }) => {
|
|
1871
2338
|
const payload = JSON.parse(data);
|
|
1872
2339
|
switch (payload.type) {
|
|
1873
2340
|
case 'connected':
|
|
1874
|
-
console.
|
|
2341
|
+
console.debug('[nasti] connected.');
|
|
1875
2342
|
clearErrorOverlay();
|
|
1876
2343
|
break;
|
|
1877
2344
|
case 'update':
|
|
1878
2345
|
try {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
} else if (update.type === 'css-update') {
|
|
1883
|
-
return updateCss(update.path);
|
|
1884
|
-
}
|
|
1885
|
-
}));
|
|
2346
|
+
// CSS \u5728 unbundled \u6A21\u5F0F\u4E0B\u4E5F\u662F\u4F1A\u6CE8\u5165 <style> \u7684 JS \u6A21\u5757\uFF0C\u548C\u666E\u901A JS
|
|
2347
|
+
// \u4E00\u6837\u91CD\u65B0 import \u624D\u80FD\u6267\u884C dispose/accept \u5E76\u4FDD\u6301\u9875\u9762\u72B6\u6001\u3002
|
|
2348
|
+
await Promise.all(payload.updates.map(queueUpdate));
|
|
1886
2349
|
clearErrorOverlay();
|
|
1887
|
-
console.
|
|
1888
|
-
location.reload();
|
|
2350
|
+
console.debug('[nasti] HMR update complete.');
|
|
1889
2351
|
} catch (err) {
|
|
1890
2352
|
console.error('[nasti] HMR update failed:', err);
|
|
1891
2353
|
showErrorOverlay(err);
|
|
@@ -1896,10 +2358,17 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
1896
2358
|
location.reload();
|
|
1897
2359
|
break;
|
|
1898
2360
|
case 'prune':
|
|
1899
|
-
payload.paths.
|
|
1900
|
-
const
|
|
1901
|
-
|
|
1902
|
-
|
|
2361
|
+
await Promise.all(payload.paths.map(async (path) => {
|
|
2362
|
+
const data = dataMap.get(path);
|
|
2363
|
+
const dispose = disposeMap.get(path);
|
|
2364
|
+
const prune = pruneMap.get(path);
|
|
2365
|
+
if (dispose) await dispose(data);
|
|
2366
|
+
if (prune) await prune(data);
|
|
2367
|
+
hotModulesMap.delete(path);
|
|
2368
|
+
disposeMap.delete(path);
|
|
2369
|
+
pruneMap.delete(path);
|
|
2370
|
+
dataMap.delete(path);
|
|
2371
|
+
}));
|
|
1903
2372
|
break;
|
|
1904
2373
|
case 'error':
|
|
1905
2374
|
console.error('[nasti] error:', payload.err.message);
|
|
@@ -1908,33 +2377,64 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
1908
2377
|
}
|
|
1909
2378
|
});
|
|
1910
2379
|
|
|
1911
|
-
// \
|
|
2380
|
+
// \u670D\u52A1\u91CD\u542F\u540E\u65E7\u6A21\u5757\u56FE\u5DF2\u5931\u6548\uFF0C\u91CD\u8FDE\u65F6\u6574\u9875\u5237\u65B0\u662F\u5FC5\u8981\u515C\u5E95\uFF1B\u6B63\u5E38 update \u4E0D\u518D\u5237\u65B0\u3002
|
|
1912
2381
|
let reconnectTimer = 0;
|
|
1913
2382
|
socket.addEventListener('close', () => {
|
|
1914
2383
|
clearTimeout(reconnectTimer);
|
|
1915
2384
|
reconnectTimer = setTimeout(() => location.reload(), 1000);
|
|
1916
2385
|
});
|
|
1917
2386
|
|
|
2387
|
+
/**
|
|
2388
|
+
* \u540C\u4E00\u6279\u66F4\u65B0\u5148\u5168\u90E8\u62C9\u53D6\uFF0C\u518D\u6309\u670D\u52A1\u7AEF\u6D88\u606F\u987A\u5E8F\u6267\u884C accept \u56DE\u8C03\uFF0C\u907F\u514D HTTP \u5F80\u8FD4\u901F\u5EA6
|
|
2389
|
+
* \u6539\u53D8\u6A21\u5757\u5E94\u7528\u987A\u5E8F\u3002\u8FD9\u4E0E Vite HMRClient \u7684 fetch/apply \u4E24\u9636\u6BB5\u4E00\u81F4\u3002
|
|
2390
|
+
*/
|
|
2391
|
+
async function queueUpdate(update) {
|
|
2392
|
+
updateQueue.push(fetchUpdate(update));
|
|
2393
|
+
if (pendingUpdateQueue) return;
|
|
2394
|
+
|
|
2395
|
+
pendingUpdateQueue = true;
|
|
2396
|
+
await Promise.resolve();
|
|
2397
|
+
pendingUpdateQueue = false;
|
|
2398
|
+
const loading = updateQueue;
|
|
2399
|
+
updateQueue = [];
|
|
2400
|
+
const applyUpdates = await Promise.all(loading);
|
|
2401
|
+
for (const apply of applyUpdates) {
|
|
2402
|
+
if (apply) apply();
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
|
|
1918
2406
|
async function fetchUpdate(update) {
|
|
1919
2407
|
const mod = hotModulesMap.get(update.path);
|
|
1920
|
-
// \
|
|
1921
|
-
|
|
1922
|
-
if (dispose) dispose();
|
|
2408
|
+
// \u5C1A\u672A\u5728\u5F53\u524D\u9875\u9762\u52A0\u8F7D\u7684\u52A8\u6001\u6A21\u5757\u4E0D\u9700\u8981\u66F4\u65B0\u3002
|
|
2409
|
+
if (!mod) return;
|
|
1923
2410
|
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2411
|
+
// \u5FC5\u987B\u5728\u91CD\u65B0 import \u524D\u786E\u5B9A\u65E7\u56DE\u8C03\uFF1B\u65B0\u6A21\u5757\u6267\u884C createHotContext \u65F6\u4F1A\u6E05\u7A7A\u5E76\u6CE8\u518C\u65B0\u56DE\u8C03\u3002
|
|
2412
|
+
const qualifiedCallbacks = mod.callbacks.filter(({ deps }) =>
|
|
2413
|
+
deps.includes(update.acceptedPath)
|
|
2414
|
+
);
|
|
2415
|
+
const isSelfUpdate = update.path === update.acceptedPath;
|
|
2416
|
+
if (!isSelfUpdate && qualifiedCallbacks.length === 0) return;
|
|
2417
|
+
|
|
2418
|
+
const dispose = disposeMap.get(update.acceptedPath);
|
|
2419
|
+
if (dispose) await dispose(dataMap.get(update.acceptedPath));
|
|
2420
|
+
const newMod = await import(appendTimestampQuery(update.acceptedPath, update.timestamp));
|
|
2421
|
+
|
|
2422
|
+
return () => {
|
|
2423
|
+
for (const { deps, fn } of qualifiedCallbacks) {
|
|
2424
|
+
fn(deps.map((dep) => dep === update.acceptedPath ? newMod : undefined));
|
|
2425
|
+
}
|
|
2426
|
+
const detail = isSelfUpdate
|
|
2427
|
+
? update.path
|
|
2428
|
+
: update.acceptedPath + ' via ' + update.path;
|
|
2429
|
+
console.debug('[nasti] hot updated:', detail);
|
|
2430
|
+
};
|
|
1929
2431
|
}
|
|
1930
2432
|
|
|
1931
|
-
function
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
.then(css => { el.textContent = css; });
|
|
1937
|
-
}
|
|
2433
|
+
function appendTimestampQuery(url, timestamp) {
|
|
2434
|
+
const hashIndex = url.indexOf('#');
|
|
2435
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : '';
|
|
2436
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
2437
|
+
return withoutHash + (withoutHash.includes('?') ? '&' : '?') + 't=' + timestamp + hash;
|
|
1938
2438
|
}
|
|
1939
2439
|
|
|
1940
2440
|
function clearErrorOverlay() {
|
|
@@ -1962,23 +2462,30 @@ function showErrorOverlay(err) {
|
|
|
1962
2462
|
document.body.appendChild(overlay);
|
|
1963
2463
|
}
|
|
1964
2464
|
|
|
1965
|
-
/**
|
|
1966
|
-
* \u751F\u6210 import.meta.hot \u7684 hot context\u3002
|
|
1967
|
-
* \u5173\u952E\u7EA6\u675F\uFF1A\u540C\u4E00 ownerPath \u7684 accept \u56DE\u8C03\u5FC5\u987B\u66FF\u6362\uFF08\u4E0D\u662F append\uFF09\u3002
|
|
1968
|
-
* \u6BCF\u6B21\u6A21\u5757\u91CD\u65B0 import \u90FD\u4F1A\u8C03\u7528 createHotContext\uFF0C\u65E7\u56DE\u8C03\u4F1A\u88AB fetchUpdate \u8C03\u7528\u540E\u7ACB\u5373\u88AB\u65B0 import
|
|
1969
|
-
* \u91CC\u7684 accept \u66FF\u6362\u3002\u4E0D\u66FF\u6362\u7684\u8BDD\u6BCF\u7F16\u8F91\u4E00\u6B21\u5C31\u591A\u4E00\u4E2A\u56DE\u8C03\uFF0C\u8D8A\u8DD1\u8D8A\u6162\u3002
|
|
1970
|
-
*/
|
|
1971
2465
|
export function createHotContext(ownerPath) {
|
|
2466
|
+
if (!dataMap.has(ownerPath)) dataMap.set(ownerPath, {});
|
|
2467
|
+
|
|
2468
|
+
// \u6A21\u5757\u91CD\u65B0\u6267\u884C\u65F6\u4E22\u5F03\u65E7 accept \u56DE\u8C03\uFF0C\u4F46\u4FDD\u7559\u540C\u4E00\u4E2A hot.data \u5BF9\u8C61\u3002
|
|
2469
|
+
const existing = hotModulesMap.get(ownerPath);
|
|
2470
|
+
if (existing) existing.callbacks = [];
|
|
2471
|
+
|
|
2472
|
+
const acceptDeps = (deps, callback = () => {}) => {
|
|
2473
|
+
const mod = hotModulesMap.get(ownerPath) || { id: ownerPath, callbacks: [] };
|
|
2474
|
+
mod.callbacks.push({ deps, fn: callback });
|
|
2475
|
+
hotModulesMap.set(ownerPath, mod);
|
|
2476
|
+
};
|
|
2477
|
+
|
|
1972
2478
|
return {
|
|
1973
2479
|
accept(deps, callback) {
|
|
1974
|
-
// \u81EA\u63A5\u53D7: hot.accept() \u6216 hot.accept(callback)
|
|
1975
2480
|
if (typeof deps === 'function' || deps === undefined) {
|
|
1976
|
-
|
|
1977
|
-
|
|
2481
|
+
acceptDeps([ownerPath], ([mod]) => deps?.(mod));
|
|
2482
|
+
} else if (typeof deps === 'string') {
|
|
2483
|
+
acceptDeps([deps], ([mod]) => callback?.(mod));
|
|
2484
|
+
} else if (Array.isArray(deps)) {
|
|
2485
|
+
acceptDeps(deps, callback);
|
|
2486
|
+
} else {
|
|
2487
|
+
throw new Error('invalid hot.accept() usage');
|
|
1978
2488
|
}
|
|
1979
|
-
// \u4F9D\u8D56\u63A5\u53D7: hot.accept(deps, callback)\uFF0C\u591A\u6B21\u8C03\u7528\u8FFD\u52A0
|
|
1980
|
-
const existing = hotModulesMap.get(ownerPath)?.callbacks ?? [];
|
|
1981
|
-
hotModulesMap.set(ownerPath, { callbacks: [...existing, callback] });
|
|
1982
2489
|
},
|
|
1983
2490
|
prune(callback) {
|
|
1984
2491
|
pruneMap.set(ownerPath, callback);
|
|
@@ -1989,21 +2496,85 @@ export function createHotContext(ownerPath) {
|
|
|
1989
2496
|
invalidate() {
|
|
1990
2497
|
location.reload();
|
|
1991
2498
|
},
|
|
1992
|
-
data:
|
|
2499
|
+
data: dataMap.get(ownerPath),
|
|
1993
2500
|
};
|
|
1994
2501
|
}
|
|
1995
2502
|
`;
|
|
1996
2503
|
}
|
|
1997
|
-
var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
2504
|
+
var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
1998
2505
|
var init_middleware = __esm({
|
|
1999
2506
|
"src/server/middleware.ts"() {
|
|
2000
2507
|
"use strict";
|
|
2001
2508
|
init_transformer();
|
|
2002
2509
|
init_html();
|
|
2003
2510
|
init_env();
|
|
2511
|
+
init_url();
|
|
2004
2512
|
__dirname_esm = path4.dirname(fileURLToPath(import.meta.url));
|
|
2005
2513
|
__require2 = createRequire(import.meta.url);
|
|
2006
2514
|
__refreshRuntimeCache = null;
|
|
2515
|
+
REACT_REFRESH_BOUNDARY_HELPERS = `
|
|
2516
|
+
function __nastiIsPlainObject(obj) {
|
|
2517
|
+
return Object.prototype.toString.call(obj) === '[object Object]' &&
|
|
2518
|
+
(obj.constructor === Object || obj.constructor === undefined);
|
|
2519
|
+
}
|
|
2520
|
+
function __nastiIsCompoundComponent(type) {
|
|
2521
|
+
if (!__nastiIsPlainObject(type)) return false;
|
|
2522
|
+
for (const key in type) {
|
|
2523
|
+
if (!isLikelyComponentType(type[key])) return false;
|
|
2524
|
+
}
|
|
2525
|
+
return true;
|
|
2526
|
+
}
|
|
2527
|
+
export function registerExportsForReactRefresh(filename, moduleExports) {
|
|
2528
|
+
for (const key in moduleExports) {
|
|
2529
|
+
if (key === '__esModule') continue;
|
|
2530
|
+
const value = moduleExports[key];
|
|
2531
|
+
if (isLikelyComponentType(value)) {
|
|
2532
|
+
register(value, filename + ' export ' + key);
|
|
2533
|
+
} else if (__nastiIsCompoundComponent(value)) {
|
|
2534
|
+
for (const subKey in value) {
|
|
2535
|
+
register(value[subKey], filename + ' export ' + key + '-' + subKey);
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
let __nastiRefreshTimer;
|
|
2541
|
+
function __nastiEnqueueRefresh() {
|
|
2542
|
+
clearTimeout(__nastiRefreshTimer);
|
|
2543
|
+
__nastiRefreshTimer = setTimeout(() => performReactRefresh(), 16);
|
|
2544
|
+
}
|
|
2545
|
+
function __nastiCheckExports(ignored, exports, predicate) {
|
|
2546
|
+
for (const key in exports) {
|
|
2547
|
+
if (ignored.includes(key)) continue;
|
|
2548
|
+
if (!predicate(key, exports[key])) return key;
|
|
2549
|
+
}
|
|
2550
|
+
return true;
|
|
2551
|
+
}
|
|
2552
|
+
export function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
|
|
2553
|
+
const ignored = window.__getReactRefreshIgnoredExports?.({ id }) ?? [];
|
|
2554
|
+
if (__nastiCheckExports(ignored, prevExports, (key) => key in nextExports) !== true) {
|
|
2555
|
+
return 'Could not Fast Refresh (export removed)';
|
|
2556
|
+
}
|
|
2557
|
+
if (__nastiCheckExports(ignored, nextExports, (key) => key in prevExports) !== true) {
|
|
2558
|
+
return 'Could not Fast Refresh (new export)';
|
|
2559
|
+
}
|
|
2560
|
+
let hasExports = false;
|
|
2561
|
+
const compatible = __nastiCheckExports(ignored, nextExports, (key, value) => {
|
|
2562
|
+
hasExports = true;
|
|
2563
|
+
return isLikelyComponentType(value) ||
|
|
2564
|
+
__nastiIsCompoundComponent(value) ||
|
|
2565
|
+
prevExports[key] === value;
|
|
2566
|
+
});
|
|
2567
|
+
if (!hasExports) {
|
|
2568
|
+
return 'Could not Fast Refresh (no exports)';
|
|
2569
|
+
}
|
|
2570
|
+
if (compatible === true) {
|
|
2571
|
+
__nastiEnqueueRefresh();
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
return 'Could not Fast Refresh ("' + compatible + '" export is incompatible)';
|
|
2575
|
+
}
|
|
2576
|
+
export const __hmr_import = (module) => import(module);
|
|
2577
|
+
`;
|
|
2007
2578
|
REACT_REFRESH_GLOBAL_PREAMBLE = `
|
|
2008
2579
|
import RefreshRuntime from "/@react-refresh";
|
|
2009
2580
|
RefreshRuntime.injectIntoGlobalHook(window);
|
|
@@ -2033,8 +2604,10 @@ async function handleFileChange(file, server) {
|
|
|
2033
2604
|
}
|
|
2034
2605
|
const updates = [];
|
|
2035
2606
|
const timestamp = Date.now();
|
|
2607
|
+
const graph = moduleGraph;
|
|
2608
|
+
const invalidatedModules = /* @__PURE__ */ new Set();
|
|
2036
2609
|
for (const mod of mods) {
|
|
2037
|
-
|
|
2610
|
+
graph.invalidateModuleAndImporters(mod, timestamp, invalidatedModules);
|
|
2038
2611
|
const ctx = {
|
|
2039
2612
|
file,
|
|
2040
2613
|
timestamp,
|
|
@@ -2052,19 +2625,25 @@ async function handleFileChange(file, server) {
|
|
|
2052
2625
|
}
|
|
2053
2626
|
}
|
|
2054
2627
|
for (const affected of affectedModules) {
|
|
2055
|
-
|
|
2628
|
+
graph.invalidateModuleAndImporters(affected, timestamp, invalidatedModules);
|
|
2629
|
+
const boundaries = graph.getHmrBoundaries(affected);
|
|
2056
2630
|
if (boundaries.length === 0) {
|
|
2057
2631
|
logger.info(pc4.green("page reload ") + pc4.dim(shortFile), { timestamp: true });
|
|
2058
2632
|
ws.send({ type: "full-reload", path: relativePath });
|
|
2059
2633
|
return;
|
|
2060
2634
|
}
|
|
2061
|
-
for (const { boundary } of boundaries) {
|
|
2062
|
-
|
|
2635
|
+
for (const { boundary, acceptedVia } of boundaries) {
|
|
2636
|
+
const update = {
|
|
2063
2637
|
type: boundary.type === "css" ? "css-update" : "js-update",
|
|
2064
2638
|
path: boundary.url,
|
|
2065
|
-
acceptedPath:
|
|
2639
|
+
acceptedPath: acceptedVia.url,
|
|
2066
2640
|
timestamp
|
|
2067
|
-
}
|
|
2641
|
+
};
|
|
2642
|
+
if (!updates.some(
|
|
2643
|
+
(existing) => existing.type === update.type && existing.path === update.path && existing.acceptedPath === update.acceptedPath
|
|
2644
|
+
)) {
|
|
2645
|
+
updates.push(update);
|
|
2646
|
+
}
|
|
2068
2647
|
}
|
|
2069
2648
|
}
|
|
2070
2649
|
}
|
|
@@ -2134,6 +2713,7 @@ function resolvePlugin(config) {
|
|
|
2134
2713
|
}
|
|
2135
2714
|
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
2136
2715
|
if (vueRuntimeEntry && source === "vue") return vueRuntimeEntry;
|
|
2716
|
+
if (config.command === "build") return null;
|
|
2137
2717
|
try {
|
|
2138
2718
|
const resolved = require2.resolve(source, {
|
|
2139
2719
|
paths: [importer ? path6.dirname(importer) : config.root]
|
|
@@ -2222,27 +2802,27 @@ var require_process = __commonJS({
|
|
|
2222
2802
|
var require_filesystem = __commonJS({
|
|
2223
2803
|
"node_modules/detect-libc/lib/filesystem.js"(exports, module) {
|
|
2224
2804
|
"use strict";
|
|
2225
|
-
var
|
|
2805
|
+
var fs13 = __require("fs");
|
|
2226
2806
|
var LDD_PATH = "/usr/bin/ldd";
|
|
2227
2807
|
var SELF_PATH = "/proc/self/exe";
|
|
2228
2808
|
var MAX_LENGTH = 2048;
|
|
2229
|
-
var readFileSync = (
|
|
2230
|
-
const fd =
|
|
2809
|
+
var readFileSync = (path18) => {
|
|
2810
|
+
const fd = fs13.openSync(path18, "r");
|
|
2231
2811
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
2232
|
-
const bytesRead =
|
|
2233
|
-
|
|
2812
|
+
const bytesRead = fs13.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
2813
|
+
fs13.close(fd, () => {
|
|
2234
2814
|
});
|
|
2235
2815
|
return buffer.subarray(0, bytesRead);
|
|
2236
2816
|
};
|
|
2237
|
-
var readFile = (
|
|
2238
|
-
|
|
2817
|
+
var readFile = (path18) => new Promise((resolve, reject) => {
|
|
2818
|
+
fs13.open(path18, "r", (err, fd) => {
|
|
2239
2819
|
if (err) {
|
|
2240
2820
|
reject(err);
|
|
2241
2821
|
} else {
|
|
2242
2822
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
2243
|
-
|
|
2823
|
+
fs13.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
2244
2824
|
resolve(buffer.subarray(0, bytesRead));
|
|
2245
|
-
|
|
2825
|
+
fs13.close(fd, () => {
|
|
2246
2826
|
});
|
|
2247
2827
|
});
|
|
2248
2828
|
}
|
|
@@ -2354,11 +2934,11 @@ var require_detect_libc = __commonJS({
|
|
|
2354
2934
|
}
|
|
2355
2935
|
return null;
|
|
2356
2936
|
};
|
|
2357
|
-
var familyFromInterpreterPath = (
|
|
2358
|
-
if (
|
|
2359
|
-
if (
|
|
2937
|
+
var familyFromInterpreterPath = (path18) => {
|
|
2938
|
+
if (path18) {
|
|
2939
|
+
if (path18.includes("/ld-musl-")) {
|
|
2360
2940
|
return MUSL;
|
|
2361
|
-
} else if (
|
|
2941
|
+
} else if (path18.includes("/ld-linux-")) {
|
|
2362
2942
|
return GLIBC;
|
|
2363
2943
|
}
|
|
2364
2944
|
}
|
|
@@ -2405,8 +2985,8 @@ var require_detect_libc = __commonJS({
|
|
|
2405
2985
|
cachedFamilyInterpreter = null;
|
|
2406
2986
|
try {
|
|
2407
2987
|
const selfContent = await readFile(SELF_PATH);
|
|
2408
|
-
const
|
|
2409
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
2988
|
+
const path18 = interpreterPath(selfContent);
|
|
2989
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path18);
|
|
2410
2990
|
} catch (e) {
|
|
2411
2991
|
}
|
|
2412
2992
|
return cachedFamilyInterpreter;
|
|
@@ -2418,8 +2998,8 @@ var require_detect_libc = __commonJS({
|
|
|
2418
2998
|
cachedFamilyInterpreter = null;
|
|
2419
2999
|
try {
|
|
2420
3000
|
const selfContent = readFileSync(SELF_PATH);
|
|
2421
|
-
const
|
|
2422
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
3001
|
+
const path18 = interpreterPath(selfContent);
|
|
3002
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path18);
|
|
2423
3003
|
} catch (e) {
|
|
2424
3004
|
}
|
|
2425
3005
|
return cachedFamilyInterpreter;
|
|
@@ -3445,8 +4025,8 @@ function vuePlugin(config) {
|
|
|
3445
4025
|
let descriptor = descriptorCache.get(filePath);
|
|
3446
4026
|
if (!descriptor) {
|
|
3447
4027
|
try {
|
|
3448
|
-
const
|
|
3449
|
-
const source =
|
|
4028
|
+
const fs13 = await import("fs");
|
|
4029
|
+
const source = fs13.readFileSync(filePath, "utf-8");
|
|
3450
4030
|
const parsed = sfc.parse(source, { filename: filePath });
|
|
3451
4031
|
if (parsed.errors.length) return null;
|
|
3452
4032
|
descriptor = parsed.descriptor;
|
|
@@ -3584,16 +4164,27 @@ var init_vue = __esm({
|
|
|
3584
4164
|
// src/plugins/builtins.ts
|
|
3585
4165
|
function resolvePluginList(config, userPlugins, opts = {}) {
|
|
3586
4166
|
const isServe = config.command === "serve";
|
|
4167
|
+
let environmentOptions;
|
|
4168
|
+
if (opts.environmentName) {
|
|
4169
|
+
environmentOptions = config.environments[opts.environmentName];
|
|
4170
|
+
if (!environmentOptions) {
|
|
4171
|
+
throw new Error(
|
|
4172
|
+
`[nasti] unknown environment "${opts.environmentName}" \u2014 declare it in config.environments`
|
|
4173
|
+
);
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
const pluginConfig = environmentOptions ? { ...config, resolve: environmentOptions.resolve, build: environmentOptions.build } : config;
|
|
4177
|
+
const consumer = opts.consumer ?? environmentOptions?.consumer;
|
|
3587
4178
|
return [
|
|
3588
4179
|
// vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
|
|
3589
|
-
...config.framework === "vue" ? [vuePlugin(
|
|
3590
|
-
resolvePlugin(
|
|
3591
|
-
cssPlugin(
|
|
3592
|
-
assetsPlugin(
|
|
3593
|
-
...isServe ? [htmlPlugin(
|
|
4180
|
+
...config.framework === "vue" ? [vuePlugin(pluginConfig)] : [],
|
|
4181
|
+
resolvePlugin(pluginConfig),
|
|
4182
|
+
cssPlugin(pluginConfig, opts.cssEngine, consumer),
|
|
4183
|
+
assetsPlugin(pluginConfig),
|
|
4184
|
+
...isServe ? [htmlPlugin(pluginConfig)] : [],
|
|
3594
4185
|
...userPlugins,
|
|
3595
4186
|
// cssPostPlugin 最后(enforce: 'post' 语义):renderChunk 聚合抽取
|
|
3596
|
-
...!isServe && opts.cssEngine ? [cssPostPlugin(
|
|
4187
|
+
...!isServe && opts.cssEngine ? [cssPostPlugin(pluginConfig, opts.cssEngine)] : []
|
|
3597
4188
|
];
|
|
3598
4189
|
}
|
|
3599
4190
|
var init_builtins = __esm({
|
|
@@ -3917,16 +4508,145 @@ var init_reporter = __esm({
|
|
|
3917
4508
|
}
|
|
3918
4509
|
});
|
|
3919
4510
|
|
|
4511
|
+
// src/core/build-app-context.ts
|
|
4512
|
+
import fs9 from "fs";
|
|
4513
|
+
import path12 from "path";
|
|
4514
|
+
function createBuildAppContext(config, results) {
|
|
4515
|
+
const output = [];
|
|
4516
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
4517
|
+
const outDir = path12.resolve(config.root, config.build.outDir);
|
|
4518
|
+
let environmentArtifacts;
|
|
4519
|
+
return {
|
|
4520
|
+
config,
|
|
4521
|
+
results,
|
|
4522
|
+
get output() {
|
|
4523
|
+
return Object.freeze([...output]);
|
|
4524
|
+
},
|
|
4525
|
+
getResult(environmentName) {
|
|
4526
|
+
return results[environmentName];
|
|
4527
|
+
},
|
|
4528
|
+
getArtifact(environmentName, fileName) {
|
|
4529
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
4530
|
+
return results[environmentName]?.output.find(
|
|
4531
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalized
|
|
4532
|
+
);
|
|
4533
|
+
},
|
|
4534
|
+
getEntry(environmentName, entryName) {
|
|
4535
|
+
const result = results[environmentName];
|
|
4536
|
+
const fileName = result?.entries?.[entryName];
|
|
4537
|
+
if (!fileName) return void 0;
|
|
4538
|
+
return result.output.find(
|
|
4539
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalizeEnvironmentFileName(fileName)
|
|
4540
|
+
);
|
|
4541
|
+
},
|
|
4542
|
+
getManifest(environmentName) {
|
|
4543
|
+
return results[environmentName]?.manifest;
|
|
4544
|
+
},
|
|
4545
|
+
emitFile(file) {
|
|
4546
|
+
const fileName = normalizeAppFileName(file.fileName);
|
|
4547
|
+
const collisionKey = artifactCollisionKey(fileName);
|
|
4548
|
+
if (emitted.has(collisionKey)) {
|
|
4549
|
+
throw new Error(`[nasti] app artifact already emitted: ${fileName}`);
|
|
4550
|
+
}
|
|
4551
|
+
environmentArtifacts ??= collectEnvironmentArtifacts(config, results, outDir);
|
|
4552
|
+
if (environmentArtifacts.has(collisionKey)) {
|
|
4553
|
+
throw new Error(`[nasti] app artifact conflicts with environment output: ${fileName}`);
|
|
4554
|
+
}
|
|
4555
|
+
const target = path12.resolve(outDir, ...fileName.split("/"));
|
|
4556
|
+
const relative = path12.relative(outDir, target);
|
|
4557
|
+
if (relative.startsWith("..") || path12.isAbsolute(relative)) {
|
|
4558
|
+
throw new Error(`[nasti] app artifact must stay inside build.outDir: ${file.fileName}`);
|
|
4559
|
+
}
|
|
4560
|
+
assertNoSymlinkComponents(outDir, fileName);
|
|
4561
|
+
fs9.mkdirSync(path12.dirname(target), { recursive: true });
|
|
4562
|
+
fs9.writeFileSync(target, file.source);
|
|
4563
|
+
const artifact = {
|
|
4564
|
+
...file,
|
|
4565
|
+
fileName,
|
|
4566
|
+
type: "asset"
|
|
4567
|
+
};
|
|
4568
|
+
emitted.add(collisionKey);
|
|
4569
|
+
output.push(artifact);
|
|
4570
|
+
return fileName;
|
|
4571
|
+
}
|
|
4572
|
+
};
|
|
4573
|
+
}
|
|
4574
|
+
function normalizeEnvironmentFileName(fileName) {
|
|
4575
|
+
return path12.posix.normalize(fileName.replace(/\\/g, "/").replace(/^\.\//, ""));
|
|
4576
|
+
}
|
|
4577
|
+
function isInvalidEnvironmentFileName(fileName) {
|
|
4578
|
+
return !fileName || fileName === "." || fileName === ".." || fileName.startsWith("../") || path12.posix.isAbsolute(fileName) || /^[A-Za-z]:\//.test(fileName);
|
|
4579
|
+
}
|
|
4580
|
+
function normalizeAppFileName(fileName) {
|
|
4581
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
4582
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
4583
|
+
throw new Error(`[nasti] invalid app artifact fileName: ${fileName}`);
|
|
4584
|
+
}
|
|
4585
|
+
return normalized;
|
|
4586
|
+
}
|
|
4587
|
+
function artifactCollisionKey(fileName) {
|
|
4588
|
+
return normalizeEnvironmentFileName(fileName).toLowerCase();
|
|
4589
|
+
}
|
|
4590
|
+
function collectEnvironmentArtifacts(config, results, appOutDir) {
|
|
4591
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
4592
|
+
for (const [environmentName, result] of Object.entries(results)) {
|
|
4593
|
+
const environment = config.environments[environmentName];
|
|
4594
|
+
if (!environment) continue;
|
|
4595
|
+
const environmentOutDir = path12.resolve(config.root, environment.build.outDir);
|
|
4596
|
+
for (const artifact of result.output) {
|
|
4597
|
+
const artifactPath = path12.resolve(
|
|
4598
|
+
environmentOutDir,
|
|
4599
|
+
...normalizeEnvironmentFileName(artifact.fileName).split("/")
|
|
4600
|
+
);
|
|
4601
|
+
const relative = path12.relative(appOutDir, artifactPath);
|
|
4602
|
+
if (!relative.startsWith("..") && !path12.isAbsolute(relative)) {
|
|
4603
|
+
occupied.add(artifactCollisionKey(relative));
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
return occupied;
|
|
4608
|
+
}
|
|
4609
|
+
function assertNoSymlinkComponents(outDir, fileName) {
|
|
4610
|
+
let current = outDir;
|
|
4611
|
+
for (const segment of fileName.split("/")) {
|
|
4612
|
+
current = path12.join(current, segment);
|
|
4613
|
+
let stats;
|
|
4614
|
+
try {
|
|
4615
|
+
stats = fs9.lstatSync(current);
|
|
4616
|
+
} catch (error) {
|
|
4617
|
+
if (error.code === "ENOENT") continue;
|
|
4618
|
+
throw error;
|
|
4619
|
+
}
|
|
4620
|
+
if (stats.isSymbolicLink()) {
|
|
4621
|
+
throw new Error(`[nasti] app artifact path cannot traverse a symlink: ${fileName}`);
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
function inferEnvironmentEntries(output) {
|
|
4626
|
+
const entries = {};
|
|
4627
|
+
for (const artifact of output) {
|
|
4628
|
+
if (artifact.type !== "chunk" || !artifact.isEntry || !artifact.name) continue;
|
|
4629
|
+
entries[artifact.name] = normalizeEnvironmentFileName(artifact.fileName);
|
|
4630
|
+
}
|
|
4631
|
+
return Object.keys(entries).length > 0 ? entries : void 0;
|
|
4632
|
+
}
|
|
4633
|
+
var init_build_app_context = __esm({
|
|
4634
|
+
"src/core/build-app-context.ts"() {
|
|
4635
|
+
"use strict";
|
|
4636
|
+
}
|
|
4637
|
+
});
|
|
4638
|
+
|
|
3920
4639
|
// src/build/index.ts
|
|
3921
4640
|
var build_exports = {};
|
|
3922
4641
|
__export(build_exports, {
|
|
3923
4642
|
build: () => build,
|
|
3924
4643
|
getRolldownOptions: () => getRolldownOptions,
|
|
4644
|
+
replaceEntryScript: () => replaceEntryScript,
|
|
3925
4645
|
resolveClientEntries: () => resolveClientEntries,
|
|
3926
4646
|
toRolldownPlugins: () => toRolldownPlugins
|
|
3927
4647
|
});
|
|
3928
|
-
import
|
|
3929
|
-
import
|
|
4648
|
+
import path13 from "path";
|
|
4649
|
+
import fs10 from "fs";
|
|
3930
4650
|
import { builtinModules as builtinModules2 } from "module";
|
|
3931
4651
|
import { rolldown } from "rolldown";
|
|
3932
4652
|
import pc6 from "picocolors";
|
|
@@ -3934,9 +4654,14 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
3934
4654
|
const config = environment.config;
|
|
3935
4655
|
const envOptions = environment.options;
|
|
3936
4656
|
const isServer = environment.consumer === "server";
|
|
3937
|
-
const outDir =
|
|
4657
|
+
const outDir = path13.resolve(config.root, envOptions.build.outDir);
|
|
3938
4658
|
const assetsDir = envOptions.build.assetsDir;
|
|
3939
|
-
const {
|
|
4659
|
+
const {
|
|
4660
|
+
output: userOutput,
|
|
4661
|
+
transform: userTransform,
|
|
4662
|
+
resolve: userResolve,
|
|
4663
|
+
...restInputOptions
|
|
4664
|
+
} = envOptions.build.rolldownOptions;
|
|
3940
4665
|
const vueDefine = config.framework === "vue" ? {
|
|
3941
4666
|
__VUE_OPTIONS_API__: "true",
|
|
3942
4667
|
__VUE_PROD_DEVTOOLS__: "false",
|
|
@@ -3950,19 +4675,22 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
3950
4675
|
input: entryPoints,
|
|
3951
4676
|
transform: { ...userTransform, define: mergedDefine },
|
|
3952
4677
|
plugins: rolldownPlugins,
|
|
4678
|
+
// client/server consumer 都必须使用当前环境的 conditions/mainFields;Lynx
|
|
4679
|
+
// BG/MT 通常同为 client consumer,但仍可能声明不同的运行时条件。
|
|
4680
|
+
resolve: {
|
|
4681
|
+
...userResolve ?? {},
|
|
4682
|
+
// Environment API 是条件解析的唯一高层入口,优先于继承来的底层选项。
|
|
4683
|
+
conditionNames: envOptions.resolve.conditions,
|
|
4684
|
+
mainFields: envOptions.resolve.mainFields
|
|
4685
|
+
},
|
|
3953
4686
|
...isServer ? {
|
|
3954
4687
|
platform: restInputOptions.platform ?? "node",
|
|
3955
|
-
resolve: {
|
|
3956
|
-
conditionNames: envOptions.resolve.conditions,
|
|
3957
|
-
mainFields: envOptions.resolve.mainFields,
|
|
3958
|
-
...restInputOptions.resolve
|
|
3959
|
-
},
|
|
3960
4688
|
// server 产物:node 内建恒外部化;bare specifier 默认外部化
|
|
3961
4689
|
//(同 Vite ssr.external 默认 —— 依赖由 node_modules 运行时解析),
|
|
3962
4690
|
// 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
|
|
3963
4691
|
external: restInputOptions.external ?? ((id) => {
|
|
3964
4692
|
if (NODE_BUILTINS2.has(id)) return true;
|
|
3965
|
-
return !id.startsWith(".") && !
|
|
4693
|
+
return !id.startsWith(".") && !path13.isAbsolute(id) && !id.startsWith("\0");
|
|
3966
4694
|
})
|
|
3967
4695
|
} : {}
|
|
3968
4696
|
};
|
|
@@ -3989,37 +4717,139 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
3989
4717
|
};
|
|
3990
4718
|
return { inputOptions, outputOptions, outDir };
|
|
3991
4719
|
}
|
|
3992
|
-
function toRolldownPlugins(plugins) {
|
|
4720
|
+
function toRolldownPlugins(plugins, environment) {
|
|
4721
|
+
const wrap = (hook) => {
|
|
4722
|
+
if (!hook) return hook;
|
|
4723
|
+
return function(...args) {
|
|
4724
|
+
return hook.apply(attachEnvironment(this, environment), args);
|
|
4725
|
+
};
|
|
4726
|
+
};
|
|
3993
4727
|
return plugins.map((p) => ({
|
|
3994
4728
|
name: p.name,
|
|
3995
|
-
resolveId: p.resolveId,
|
|
3996
|
-
load: p.load,
|
|
3997
|
-
transform: p.transform,
|
|
3998
|
-
buildStart: p.buildStart,
|
|
3999
|
-
buildEnd: p.buildEnd,
|
|
4729
|
+
resolveId: wrap(p.resolveId),
|
|
4730
|
+
load: wrap(p.load),
|
|
4731
|
+
transform: wrap(p.transform),
|
|
4732
|
+
buildStart: wrap(p.buildStart),
|
|
4733
|
+
buildEnd: wrap(p.buildEnd),
|
|
4000
4734
|
// closeBundle 在 bundle.close() 时触发 —— PWA manifest/SW 等终态产物依赖
|
|
4001
|
-
closeBundle: p.closeBundle,
|
|
4002
|
-
renderChunk: p.renderChunk,
|
|
4003
|
-
augmentChunkHash: p.augmentChunkHash,
|
|
4004
|
-
generateBundle: p.generateBundle
|
|
4735
|
+
closeBundle: wrap(p.closeBundle),
|
|
4736
|
+
renderChunk: wrap(p.renderChunk),
|
|
4737
|
+
augmentChunkHash: wrap(p.augmentChunkHash),
|
|
4738
|
+
generateBundle: wrap(p.generateBundle)
|
|
4005
4739
|
}));
|
|
4006
4740
|
}
|
|
4741
|
+
function attachEnvironment(context, environment) {
|
|
4742
|
+
if (context?.environment === environment) return context;
|
|
4743
|
+
try {
|
|
4744
|
+
Object.defineProperty(context, "environment", {
|
|
4745
|
+
configurable: true,
|
|
4746
|
+
enumerable: false,
|
|
4747
|
+
writable: false,
|
|
4748
|
+
value: environment
|
|
4749
|
+
});
|
|
4750
|
+
return context;
|
|
4751
|
+
} catch {
|
|
4752
|
+
return new Proxy(context, {
|
|
4753
|
+
get(target, property) {
|
|
4754
|
+
if (property === "environment") return environment;
|
|
4755
|
+
const value = Reflect.get(target, property, target);
|
|
4756
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
4757
|
+
},
|
|
4758
|
+
set(target, property, value) {
|
|
4759
|
+
return Reflect.set(target, property, value, target);
|
|
4760
|
+
}
|
|
4761
|
+
});
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
function finalizeEnvironmentResult(environment, result) {
|
|
4765
|
+
const metadata = environment.getBuildMetadata();
|
|
4766
|
+
const inferredEntries = inferEnvironmentEntries(result.output);
|
|
4767
|
+
const entries = {
|
|
4768
|
+
...inferredEntries,
|
|
4769
|
+
...metadata.entries,
|
|
4770
|
+
...result.entries
|
|
4771
|
+
};
|
|
4772
|
+
const normalizedEntries = Object.fromEntries(
|
|
4773
|
+
Object.entries(entries).map(([name, fileName]) => {
|
|
4774
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
4775
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
4776
|
+
throw new Error(
|
|
4777
|
+
`[nasti] environment "${environment.name}" returned invalid entry "${name}": ${fileName}`
|
|
4778
|
+
);
|
|
4779
|
+
}
|
|
4780
|
+
return [name, normalized];
|
|
4781
|
+
})
|
|
4782
|
+
);
|
|
4783
|
+
return {
|
|
4784
|
+
...metadata,
|
|
4785
|
+
...result,
|
|
4786
|
+
output: result.output,
|
|
4787
|
+
...Object.keys(normalizedEntries).length > 0 ? { entries: normalizedEntries } : {}
|
|
4788
|
+
};
|
|
4789
|
+
}
|
|
4790
|
+
function prepareBuildOutputDirectories(config, buildableNames) {
|
|
4791
|
+
const directories = /* @__PURE__ */ new Set();
|
|
4792
|
+
const protectedPaths = /* @__PURE__ */ new Set();
|
|
4793
|
+
const clientIsBuilt = buildableNames.includes("client");
|
|
4794
|
+
if (!clientIsBuilt && config.build.emptyOutDir) {
|
|
4795
|
+
directories.add(path13.resolve(config.root, config.build.outDir));
|
|
4796
|
+
}
|
|
4797
|
+
for (const name of buildableNames) {
|
|
4798
|
+
const environment = config.environments[name];
|
|
4799
|
+
const outDir = path13.resolve(config.root, environment.build.outDir);
|
|
4800
|
+
if (!environment.build.emptyOutDir) {
|
|
4801
|
+
protectedPaths.add(outDir);
|
|
4802
|
+
continue;
|
|
4803
|
+
}
|
|
4804
|
+
if (!environment.driver) directories.add(outDir);
|
|
4805
|
+
}
|
|
4806
|
+
const containsPath = (parent, child) => {
|
|
4807
|
+
const relative = path13.relative(parent, child);
|
|
4808
|
+
return relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative);
|
|
4809
|
+
};
|
|
4810
|
+
const roots = [...directories].filter(
|
|
4811
|
+
(directory) => ![...protectedPaths].some((protectedPath) => containsPath(directory, protectedPath))
|
|
4812
|
+
).sort((a, b) => a.length - b.length).filter(
|
|
4813
|
+
(directory, index2, all) => !all.slice(0, index2).some((parent) => containsPath(parent, directory))
|
|
4814
|
+
);
|
|
4815
|
+
for (const directory of roots) {
|
|
4816
|
+
if (fs10.existsSync(directory)) fs10.rmSync(directory, { recursive: true, force: true });
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
function assertDriverBuildResult(environment, result) {
|
|
4820
|
+
const output = result != null && typeof result === "object" ? result.output : void 0;
|
|
4821
|
+
const hasValidOutput = Array.isArray(output) && output.every(
|
|
4822
|
+
(artifact) => artifact != null && typeof artifact === "object" && typeof artifact.fileName === "string" && typeof artifact.type === "string"
|
|
4823
|
+
);
|
|
4824
|
+
if (!hasValidOutput) {
|
|
4825
|
+
throw new Error(
|
|
4826
|
+
`[nasti] environment "${environment.name}" driver "${environment.driver?.name}" returned an invalid build result; expected { output: EnvironmentBuildOutput[] }`
|
|
4827
|
+
);
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4007
4830
|
function resolveClientEntries(config, html) {
|
|
4831
|
+
const configuredEntries = config.environments.client?.entry ?? [];
|
|
4832
|
+
if (configuredEntries.length > 0) return configuredEntries;
|
|
4008
4833
|
const entryPoints = [];
|
|
4834
|
+
const htmlFile = config.environments.client?.html;
|
|
4835
|
+
const htmlDir = htmlFile ? path13.dirname(htmlFile) : config.root;
|
|
4009
4836
|
if (html) {
|
|
4010
4837
|
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
4011
4838
|
for (const match of scriptMatches) {
|
|
4012
4839
|
const src = match[1];
|
|
4013
4840
|
if (src && !src.startsWith("http")) {
|
|
4014
|
-
|
|
4841
|
+
const cleanSrc = src.split(/[?#]/, 1)[0];
|
|
4842
|
+
entryPoints.push(
|
|
4843
|
+
cleanSrc.startsWith("/") ? path13.resolve(config.root, cleanSrc.replace(/^\//, "")) : path13.resolve(htmlDir, cleanSrc)
|
|
4844
|
+
);
|
|
4015
4845
|
}
|
|
4016
4846
|
}
|
|
4017
4847
|
}
|
|
4018
4848
|
if (entryPoints.length === 0) {
|
|
4019
4849
|
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
4020
4850
|
for (const entry of fallbackEntries) {
|
|
4021
|
-
const fullPath =
|
|
4022
|
-
if (
|
|
4851
|
+
const fullPath = path13.resolve(config.root, entry);
|
|
4852
|
+
if (fs10.existsSync(fullPath)) {
|
|
4023
4853
|
entryPoints.push(fullPath);
|
|
4024
4854
|
break;
|
|
4025
4855
|
}
|
|
@@ -4047,130 +4877,229 @@ async function build(inlineConfig = {}) {
|
|
|
4047
4877
|
const startTime = performance.now();
|
|
4048
4878
|
logger.info(
|
|
4049
4879
|
pc6.cyan(`
|
|
4050
|
-
nasti v${"2.
|
|
4880
|
+
nasti v${"2.4.0"} `) + pc6.green(`building for ${config.mode}...`)
|
|
4051
4881
|
);
|
|
4052
4882
|
debug5?.(`root: ${config.root}`);
|
|
4053
|
-
const buildableNames = Object.keys(config.environments).filter(
|
|
4054
|
-
|
|
4055
|
-
|
|
4883
|
+
const buildableNames = Object.keys(config.environments).filter((name) => {
|
|
4884
|
+
const environment = config.environments[name];
|
|
4885
|
+
if (!environment.buildEnabled) return false;
|
|
4886
|
+
return name === "client" || environment.entry.length > 0 || !!environment.driver;
|
|
4887
|
+
});
|
|
4056
4888
|
buildableNames.sort((a, b) => a === "client" ? -1 : b === "client" ? 1 : 0);
|
|
4889
|
+
prepareBuildOutputDirectories(config, buildableNames);
|
|
4057
4890
|
const environments = {};
|
|
4891
|
+
const environmentResults = {};
|
|
4892
|
+
const initializedEnvironments = [];
|
|
4893
|
+
const buildAppContext = createBuildAppContext(config, environmentResults);
|
|
4058
4894
|
let clientOutput = [];
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4895
|
+
let buildFailed = false;
|
|
4896
|
+
try {
|
|
4897
|
+
for (const name of buildableNames) {
|
|
4898
|
+
const built = name === "client" ? await buildClientEnvironment(config) : await buildServerEnvironment(config, name);
|
|
4899
|
+
initializedEnvironments.push(built.environment);
|
|
4900
|
+
environments[name] = built.result.output;
|
|
4901
|
+
environmentResults[name] = built.result;
|
|
4902
|
+
if (name === "client") clientOutput = built.result.output;
|
|
4903
|
+
if (buildableNames.length > 1) {
|
|
4904
|
+
debug5?.(`environment "${name}" built (${built.result.output.length} files)`);
|
|
4905
|
+
}
|
|
4906
|
+
}
|
|
4907
|
+
const pluginApi = getPluginApi(config);
|
|
4908
|
+
for (const plugin of config.plugins) {
|
|
4909
|
+
await plugin.afterBuildApp?.(environmentResults, pluginApi, buildAppContext);
|
|
4910
|
+
}
|
|
4911
|
+
} catch (error) {
|
|
4912
|
+
buildFailed = true;
|
|
4913
|
+
throw error;
|
|
4914
|
+
} finally {
|
|
4915
|
+
let closeFailed = false;
|
|
4916
|
+
let firstCloseError;
|
|
4917
|
+
for (const environment of [...initializedEnvironments].reverse()) {
|
|
4918
|
+
try {
|
|
4919
|
+
await environment.close();
|
|
4920
|
+
} catch (error) {
|
|
4921
|
+
if (!closeFailed) {
|
|
4922
|
+
closeFailed = true;
|
|
4923
|
+
firstCloseError = error;
|
|
4924
|
+
}
|
|
4925
|
+
const closeError = error instanceof Error ? error : new Error(String(error));
|
|
4926
|
+
logger.error(`[nasti] failed to close environment "${environment.name}"`, {
|
|
4927
|
+
error: closeError
|
|
4928
|
+
});
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
if (closeFailed && !buildFailed) {
|
|
4932
|
+
throw firstCloseError;
|
|
4065
4933
|
}
|
|
4066
4934
|
}
|
|
4067
4935
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
4068
|
-
const
|
|
4936
|
+
const allOutput = [...Object.values(environments).flat(), ...buildAppContext.output];
|
|
4937
|
+
const totalSize = allOutput.reduce((sum, chunk) => {
|
|
4069
4938
|
const content = chunk.type === "chunk" ? chunk.code : chunk.source;
|
|
4070
4939
|
if (content == null) return sum;
|
|
4071
4940
|
return sum + (typeof content === "string" ? Buffer.byteLength(content) : content.byteLength);
|
|
4072
4941
|
}, 0);
|
|
4073
|
-
const fileCount =
|
|
4942
|
+
const fileCount = allOutput.length;
|
|
4074
4943
|
const envSuffix = buildableNames.length > 1 ? ` (${buildableNames.join(" + ")})` : "";
|
|
4075
4944
|
logger.info(pc6.green(`\u2713 built in ${elapsed}s`) + pc6.dim(envSuffix));
|
|
4076
4945
|
logger.info(pc6.dim(` ${fileCount} files, ${displaySize(totalSize)} total \u2192 ${config.build.outDir}/`));
|
|
4077
|
-
return {
|
|
4946
|
+
return {
|
|
4947
|
+
output: clientOutput,
|
|
4948
|
+
environments,
|
|
4949
|
+
environmentResults,
|
|
4950
|
+
appOutput: [...buildAppContext.output]
|
|
4951
|
+
};
|
|
4078
4952
|
}
|
|
4079
4953
|
async function buildClientEnvironment(config) {
|
|
4080
4954
|
const logger = config.logger;
|
|
4081
|
-
const outDir =
|
|
4082
|
-
if (config.build.emptyOutDir && fs9.existsSync(outDir)) {
|
|
4083
|
-
fs9.rmSync(outDir, { recursive: true, force: true });
|
|
4084
|
-
}
|
|
4085
|
-
fs9.mkdirSync(outDir, { recursive: true });
|
|
4086
|
-
const html = await readHtmlFile(config.root);
|
|
4087
|
-
const entryPoints = resolveClientEntries(config, html);
|
|
4088
|
-
if (entryPoints.length === 0) {
|
|
4089
|
-
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
4090
|
-
}
|
|
4955
|
+
const outDir = path13.resolve(config.root, config.build.outDir);
|
|
4091
4956
|
const cssEngine = createCssEngine();
|
|
4092
|
-
const pluginList = resolvePluginList(config, config.plugins, {
|
|
4093
|
-
|
|
4957
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
4958
|
+
cssEngine,
|
|
4959
|
+
environmentName: "client"
|
|
4960
|
+
});
|
|
4961
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
4094
4962
|
mode: "build",
|
|
4095
|
-
plugins: pluginList
|
|
4963
|
+
plugins: pluginList,
|
|
4964
|
+
pluginApi: getPluginApi(config)
|
|
4096
4965
|
});
|
|
4097
4966
|
await clientEnv.init();
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
...nativeReporter ? [nativeReporter] : []
|
|
4104
|
-
];
|
|
4105
|
-
const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
|
|
4106
|
-
const bundle2 = await rolldown(inputOptions);
|
|
4107
|
-
const { output } = await bundle2.write(outputOptions);
|
|
4108
|
-
await bundle2.close();
|
|
4109
|
-
if (html) {
|
|
4110
|
-
let processedHtml = html;
|
|
4111
|
-
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
4112
|
-
for (const p of htmlPlugins) {
|
|
4113
|
-
const result = await p.transformIndexHtml(processedHtml);
|
|
4114
|
-
if (typeof result === "string") {
|
|
4115
|
-
processedHtml = result;
|
|
4116
|
-
} else if (result && "html" in result) {
|
|
4117
|
-
processedHtml = processHtml(result.html, result.tags);
|
|
4118
|
-
} else if (Array.isArray(result)) {
|
|
4119
|
-
processedHtml = processHtml(processedHtml, result);
|
|
4120
|
-
}
|
|
4121
|
-
}
|
|
4122
|
-
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
4123
|
-
for (const chunk of output) {
|
|
4124
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
4125
|
-
const originalEntry = path12.relative(config.root, chunk.facadeModuleId);
|
|
4126
|
-
processedHtml = processedHtml.replace(
|
|
4127
|
-
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
4128
|
-
`$1${config.base}${chunk.fileName}$3`
|
|
4967
|
+
try {
|
|
4968
|
+
if (clientEnv.driver) {
|
|
4969
|
+
if (!clientEnv.driver.build) {
|
|
4970
|
+
throw new Error(
|
|
4971
|
+
`[nasti] environment "client" driver "${clientEnv.driver.name}" does not implement build()`
|
|
4129
4972
|
);
|
|
4130
4973
|
}
|
|
4974
|
+
const result = await clientEnv.driver.build(clientEnv.getDriverContext());
|
|
4975
|
+
assertDriverBuildResult(clientEnv, result);
|
|
4976
|
+
return { environment: clientEnv, result: finalizeEnvironmentResult(clientEnv, result) };
|
|
4131
4977
|
}
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4978
|
+
fs10.mkdirSync(outDir, { recursive: true });
|
|
4979
|
+
const htmlFile = config.environments.client.html ?? path13.resolve(config.root, "index.html");
|
|
4980
|
+
const html = await readHtmlFile(config.root, htmlFile);
|
|
4981
|
+
const entryPoints = resolveClientEntries(config, html);
|
|
4982
|
+
if (entryPoints.length === 0) {
|
|
4983
|
+
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
4984
|
+
}
|
|
4985
|
+
const allPlugins = clientEnv.plugins;
|
|
4986
|
+
const nativeReporter = config.logLevel === "silent" ? null : await tryNativeReporterPlugin(config, logger);
|
|
4987
|
+
const rolldownPlugins = [
|
|
4988
|
+
createOxcTransformPlugin(config, clientEnv),
|
|
4989
|
+
...toRolldownPlugins(allPlugins, clientEnv),
|
|
4990
|
+
...nativeReporter ? [nativeReporter] : []
|
|
4991
|
+
];
|
|
4992
|
+
const { inputOptions, outputOptions } = getRolldownOptions(
|
|
4993
|
+
clientEnv,
|
|
4994
|
+
entryPoints,
|
|
4995
|
+
rolldownPlugins
|
|
4996
|
+
);
|
|
4997
|
+
const bundle2 = await rolldown(inputOptions);
|
|
4998
|
+
const { output } = await bundle2.write(outputOptions);
|
|
4999
|
+
await bundle2.close();
|
|
5000
|
+
if (html) {
|
|
5001
|
+
let processedHtml = html;
|
|
5002
|
+
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
5003
|
+
for (const p of htmlPlugins) {
|
|
5004
|
+
const result = await p.transformIndexHtml(processedHtml);
|
|
5005
|
+
if (typeof result === "string") {
|
|
5006
|
+
processedHtml = result;
|
|
5007
|
+
} else if (result && "html" in result) {
|
|
5008
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
5009
|
+
} else if (Array.isArray(result)) {
|
|
5010
|
+
processedHtml = processHtml(processedHtml, result);
|
|
5011
|
+
}
|
|
5012
|
+
}
|
|
5013
|
+
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
5014
|
+
for (const chunk of output) {
|
|
5015
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
5016
|
+
processedHtml = replaceEntryScript(
|
|
5017
|
+
processedHtml,
|
|
5018
|
+
chunk.facadeModuleId,
|
|
5019
|
+
chunk.fileName,
|
|
5020
|
+
config,
|
|
5021
|
+
htmlFile,
|
|
5022
|
+
config.base
|
|
5023
|
+
);
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
fs10.writeFileSync(path13.resolve(outDir, "index.html"), processedHtml);
|
|
5027
|
+
}
|
|
5028
|
+
if (!nativeReporter && config.logLevel !== "silent") {
|
|
5029
|
+
reportBuildOutput(output, config, logger);
|
|
5030
|
+
}
|
|
5031
|
+
warnLargeChunks(output, config, logger);
|
|
5032
|
+
return {
|
|
5033
|
+
environment: clientEnv,
|
|
5034
|
+
result: finalizeEnvironmentResult(clientEnv, { output })
|
|
5035
|
+
};
|
|
5036
|
+
} catch (error) {
|
|
5037
|
+
try {
|
|
5038
|
+
await clientEnv.close();
|
|
5039
|
+
} catch (closeError) {
|
|
5040
|
+
const normalized = closeError instanceof Error ? closeError : new Error(String(closeError));
|
|
5041
|
+
logger.error("[nasti] failed to close client environment after build failure", {
|
|
5042
|
+
error: normalized
|
|
5043
|
+
});
|
|
5044
|
+
}
|
|
5045
|
+
throw error;
|
|
4136
5046
|
}
|
|
4137
|
-
warnLargeChunks(output, config, logger);
|
|
4138
|
-
return output;
|
|
4139
5047
|
}
|
|
4140
5048
|
async function buildServerEnvironment(config, name) {
|
|
4141
5049
|
const envOptions = config.environments[name];
|
|
4142
5050
|
const logger = config.logger;
|
|
5051
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
5052
|
+
consumer: envOptions.consumer,
|
|
5053
|
+
environmentName: name
|
|
5054
|
+
});
|
|
5055
|
+
const environment = new NastiEnvironment(name, config, {
|
|
5056
|
+
mode: "build",
|
|
5057
|
+
plugins: pluginList,
|
|
5058
|
+
pluginApi: getPluginApi(config)
|
|
5059
|
+
});
|
|
5060
|
+
await environment.init();
|
|
5061
|
+
if (environment.driver) {
|
|
5062
|
+
if (!environment.driver.build) {
|
|
5063
|
+
await environment.close();
|
|
5064
|
+
throw new Error(
|
|
5065
|
+
`[nasti] environment "${name}" driver "${environment.driver.name}" does not implement build()`
|
|
5066
|
+
);
|
|
5067
|
+
}
|
|
5068
|
+
try {
|
|
5069
|
+
const result = await environment.driver.build(environment.getDriverContext());
|
|
5070
|
+
assertDriverBuildResult(environment, result);
|
|
5071
|
+
return { environment, result: finalizeEnvironmentResult(environment, result) };
|
|
5072
|
+
} catch (error) {
|
|
5073
|
+
await environment.close();
|
|
5074
|
+
throw error;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
4143
5077
|
for (const entry of envOptions.entry) {
|
|
4144
|
-
if (!
|
|
5078
|
+
if (!fs10.existsSync(entry)) {
|
|
5079
|
+
await environment.close();
|
|
4145
5080
|
throw new Error(`[nasti] environment "${name}" entry not found: ${entry}`);
|
|
4146
5081
|
}
|
|
4147
5082
|
}
|
|
4148
|
-
const pluginList = resolvePluginList(config, config.plugins, { consumer: envOptions.consumer });
|
|
4149
|
-
const environment = new NastiEnvironment(name, { ...config, plugins: pluginList }, {
|
|
4150
|
-
mode: "build",
|
|
4151
|
-
plugins: pluginList
|
|
4152
|
-
});
|
|
4153
|
-
await environment.init();
|
|
4154
5083
|
const rolldownPlugins = [
|
|
4155
5084
|
createOxcTransformPlugin(config, environment),
|
|
4156
|
-
...toRolldownPlugins(environment.plugins)
|
|
5085
|
+
...toRolldownPlugins(environment.plugins, environment)
|
|
4157
5086
|
];
|
|
4158
5087
|
const { inputOptions, outputOptions, outDir } = getRolldownOptions(
|
|
4159
5088
|
environment,
|
|
4160
5089
|
envOptions.entry,
|
|
4161
5090
|
rolldownPlugins
|
|
4162
5091
|
);
|
|
4163
|
-
|
|
4164
|
-
fs9.rmSync(outDir, { recursive: true, force: true });
|
|
4165
|
-
}
|
|
4166
|
-
fs9.mkdirSync(outDir, { recursive: true });
|
|
5092
|
+
fs10.mkdirSync(outDir, { recursive: true });
|
|
4167
5093
|
const bundle2 = await rolldown(inputOptions);
|
|
4168
5094
|
const { output } = await bundle2.write(outputOptions);
|
|
4169
5095
|
await bundle2.close();
|
|
4170
5096
|
logger.info(
|
|
4171
|
-
pc6.dim(` [${name}] `) + output.map((o) =>
|
|
5097
|
+
pc6.dim(` [${name}] `) + output.map((o) => path13.join(envOptions.build.outDir, o.fileName)).join(pc6.dim(", "))
|
|
4172
5098
|
);
|
|
4173
|
-
return
|
|
5099
|
+
return {
|
|
5100
|
+
environment,
|
|
5101
|
+
result: finalizeEnvironmentResult(environment, { output })
|
|
5102
|
+
};
|
|
4174
5103
|
}
|
|
4175
5104
|
function injectCssLinks(html, cssEngine, config) {
|
|
4176
5105
|
const cssLinkTags = [];
|
|
@@ -4196,6 +5125,25 @@ function injectCssLinks(html, cssEngine, config) {
|
|
|
4196
5125
|
function escapeRegExp(string) {
|
|
4197
5126
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4198
5127
|
}
|
|
5128
|
+
function replaceEntryScript(html, facadeModuleId, fileName, config, htmlFile, urlPrefix) {
|
|
5129
|
+
const rootRelative = path13.relative(config.root, facadeModuleId).split(path13.sep).join("/");
|
|
5130
|
+
const resolvedHtmlFile = path13.resolve(config.root, htmlFile);
|
|
5131
|
+
const htmlRelative = path13.relative(path13.dirname(resolvedHtmlFile), facadeModuleId).split(path13.sep).join("/");
|
|
5132
|
+
const candidates = /* @__PURE__ */ new Set([
|
|
5133
|
+
rootRelative,
|
|
5134
|
+
`/${rootRelative}`,
|
|
5135
|
+
htmlRelative,
|
|
5136
|
+
`./${htmlRelative}`
|
|
5137
|
+
]);
|
|
5138
|
+
let processed = html;
|
|
5139
|
+
for (const candidate of candidates) {
|
|
5140
|
+
processed = processed.replace(
|
|
5141
|
+
new RegExp(`(src=["'])${escapeRegExp(candidate)}([?#][^"']*)?(["'])`, "g"),
|
|
5142
|
+
`$1${urlPrefix}${fileName}$3`
|
|
5143
|
+
);
|
|
5144
|
+
}
|
|
5145
|
+
return processed;
|
|
5146
|
+
}
|
|
4199
5147
|
var debug5, NODE_BUILTINS2;
|
|
4200
5148
|
var init_build = __esm({
|
|
4201
5149
|
"src/build/index.ts"() {
|
|
@@ -4209,6 +5157,8 @@ var init_build = __esm({
|
|
|
4209
5157
|
init_env();
|
|
4210
5158
|
init_reporter();
|
|
4211
5159
|
init_debug();
|
|
5160
|
+
init_plugin_api();
|
|
5161
|
+
init_build_app_context();
|
|
4212
5162
|
debug5 = createDebugger("nasti:build");
|
|
4213
5163
|
NODE_BUILTINS2 = /* @__PURE__ */ new Set([...builtinModules2, ...builtinModules2.map((m) => `node:${m}`)]);
|
|
4214
5164
|
}
|
|
@@ -4219,7 +5169,7 @@ var dev_engine_exports = {};
|
|
|
4219
5169
|
__export(dev_engine_exports, {
|
|
4220
5170
|
createBundledDevServer: () => createBundledDevServer
|
|
4221
5171
|
});
|
|
4222
|
-
import
|
|
5172
|
+
import path14 from "path";
|
|
4223
5173
|
import crypto3 from "crypto";
|
|
4224
5174
|
import { WebSocketServer as WsServer2 } from "ws";
|
|
4225
5175
|
import pc7 from "picocolors";
|
|
@@ -4240,7 +5190,7 @@ async function createBundledDevServer(opts) {
|
|
|
4240
5190
|
`[nasti] experimental.bundledDev requires rolldown's experimental dev() API (locked to the installed rc; got: ${err.message}). Remove --bundle / experimental.bundledDev to use the default unbundled dev server.`
|
|
4241
5191
|
);
|
|
4242
5192
|
}
|
|
4243
|
-
const html = await readHtmlFile(config.root);
|
|
5193
|
+
const html = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4244
5194
|
const entryPoints = resolveClientEntries(config, html);
|
|
4245
5195
|
if (entryPoints.length === 0) {
|
|
4246
5196
|
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
@@ -4255,7 +5205,7 @@ async function createBundledDevServer(opts) {
|
|
|
4255
5205
|
createReactRefreshRuntimePlugin(entryPoints),
|
|
4256
5206
|
createBundledOxcRefreshPlugin()
|
|
4257
5207
|
] : [],
|
|
4258
|
-
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins)),
|
|
5208
|
+
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
|
|
4259
5209
|
...useReactRefresh ? [
|
|
4260
5210
|
refreshWrapperFn({
|
|
4261
5211
|
cwd: config.root,
|
|
@@ -4304,7 +5254,7 @@ async function createBundledDevServer(opts) {
|
|
|
4304
5254
|
}
|
|
4305
5255
|
const url = `/${patchPath}`;
|
|
4306
5256
|
logger.info(
|
|
4307
|
-
pc7.green("hmr update ") + pc7.dim(changedFiles.map((f) =>
|
|
5257
|
+
pc7.green("hmr update ") + pc7.dim(changedFiles.map((f) => path14.relative(config.root, f)).join(", ")),
|
|
4308
5258
|
{ timestamp: true }
|
|
4309
5259
|
);
|
|
4310
5260
|
sendTo(clientId, { type: "hmr:update", path: url, url });
|
|
@@ -4440,13 +5390,13 @@ async function createBundledDevServer(opts) {
|
|
|
4440
5390
|
return;
|
|
4441
5391
|
}
|
|
4442
5392
|
res.setHeader("ETag", hit.etag);
|
|
4443
|
-
res.setHeader("Content-Type", MIME_TYPES[
|
|
5393
|
+
res.setHeader("Content-Type", MIME_TYPES[path14.extname(fileName)] ?? "application/octet-stream");
|
|
4444
5394
|
res.setHeader("Cache-Control", "no-cache");
|
|
4445
5395
|
res.end(hit.content);
|
|
4446
5396
|
return;
|
|
4447
5397
|
}
|
|
4448
5398
|
if (pathname === "/" || pathname.endsWith(".html")) {
|
|
4449
|
-
const rawHtml = await readHtmlFile(config.root);
|
|
5399
|
+
const rawHtml = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4450
5400
|
if (rawHtml) {
|
|
4451
5401
|
res.setHeader("Content-Type", "text/html");
|
|
4452
5402
|
res.setHeader("Cache-Control", "no-store");
|
|
@@ -4476,7 +5426,7 @@ function stripCatchAllLoad(plugins) {
|
|
|
4476
5426
|
);
|
|
4477
5427
|
}
|
|
4478
5428
|
function createReactRefreshRuntimePlugin(entryPoints) {
|
|
4479
|
-
const entryIds = new Set(entryPoints.map((p) =>
|
|
5429
|
+
const entryIds = new Set(entryPoints.map((p) => path14.resolve(p)));
|
|
4480
5430
|
return {
|
|
4481
5431
|
name: "nasti:bundled-react-refresh",
|
|
4482
5432
|
resolveId(source) {
|
|
@@ -4494,7 +5444,7 @@ function createReactRefreshRuntimePlugin(entryPoints) {
|
|
|
4494
5444
|
return null;
|
|
4495
5445
|
},
|
|
4496
5446
|
transform(code, id) {
|
|
4497
|
-
if (!entryIds.has(
|
|
5447
|
+
if (!entryIds.has(path14.resolve(id.split("?")[0]))) return null;
|
|
4498
5448
|
return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
|
|
4499
5449
|
${code}`, map: null };
|
|
4500
5450
|
}
|
|
@@ -4530,10 +5480,13 @@ async function renderBundledIndexHtml(html, config, entryFileNames) {
|
|
|
4530
5480
|
}
|
|
4531
5481
|
}
|
|
4532
5482
|
for (const [facadeModuleId, fileName] of entryFileNames) {
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
5483
|
+
processed = replaceEntryScript(
|
|
5484
|
+
processed,
|
|
5485
|
+
facadeModuleId,
|
|
5486
|
+
fileName,
|
|
5487
|
+
config,
|
|
5488
|
+
config.environments.client?.html ?? "index.html",
|
|
5489
|
+
"/"
|
|
4537
5490
|
);
|
|
4538
5491
|
}
|
|
4539
5492
|
return processed;
|
|
@@ -4662,7 +5615,7 @@ __export(server_exports, {
|
|
|
4662
5615
|
createServer: () => createServer
|
|
4663
5616
|
});
|
|
4664
5617
|
import http from "http";
|
|
4665
|
-
import
|
|
5618
|
+
import path15 from "path";
|
|
4666
5619
|
import os from "os";
|
|
4667
5620
|
import connect from "connect";
|
|
4668
5621
|
import sirv from "sirv";
|
|
@@ -4672,27 +5625,38 @@ async function createServer(inlineConfig = {}) {
|
|
|
4672
5625
|
const startTime = performance.now();
|
|
4673
5626
|
const config = await resolveConfig(inlineConfig, "serve");
|
|
4674
5627
|
const logger = config.logger;
|
|
4675
|
-
const allPlugins = resolvePluginList(config, config.plugins
|
|
5628
|
+
const allPlugins = resolvePluginList(config, config.plugins, {
|
|
5629
|
+
environmentName: "client"
|
|
5630
|
+
});
|
|
4676
5631
|
const configWithPlugins = { ...config, plugins: allPlugins };
|
|
4677
5632
|
const app = connect();
|
|
4678
5633
|
const httpServer = http.createServer(app);
|
|
4679
5634
|
const ws = createWebSocketServer(httpServer);
|
|
4680
|
-
const
|
|
5635
|
+
const pluginApi = getPluginApi(config);
|
|
5636
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
4681
5637
|
hot: createWsHotChannel(ws),
|
|
4682
5638
|
mode: "dev",
|
|
4683
|
-
plugins: allPlugins
|
|
5639
|
+
plugins: allPlugins,
|
|
5640
|
+
pluginApi
|
|
4684
5641
|
});
|
|
4685
5642
|
await clientEnv.init();
|
|
4686
5643
|
const environments = { client: clientEnv };
|
|
4687
5644
|
for (const name of Object.keys(config.environments)) {
|
|
4688
5645
|
if (name === "client") continue;
|
|
4689
5646
|
const consumer = config.environments[name].consumer;
|
|
4690
|
-
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
4691
|
-
|
|
5647
|
+
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
5648
|
+
consumer,
|
|
5649
|
+
environmentName: name
|
|
5650
|
+
});
|
|
5651
|
+
environments[name] = new NastiEnvironment(name, config, {
|
|
4692
5652
|
mode: "dev",
|
|
4693
|
-
plugins: envPlugins
|
|
5653
|
+
plugins: envPlugins,
|
|
5654
|
+
pluginApi
|
|
4694
5655
|
});
|
|
4695
5656
|
}
|
|
5657
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5658
|
+
if (name !== "client" && environment.options.driver) await environment.init();
|
|
5659
|
+
}
|
|
4696
5660
|
let ssrRunner = null;
|
|
4697
5661
|
async function getSsrRunner() {
|
|
4698
5662
|
if (ssrRunner) return ssrRunner;
|
|
@@ -4717,23 +5681,15 @@ async function createServer(inlineConfig = {}) {
|
|
|
4717
5681
|
});
|
|
4718
5682
|
app.use(bundledServer.middleware);
|
|
4719
5683
|
}
|
|
4720
|
-
app.use(transformMiddleware({
|
|
4721
|
-
config: configWithPlugins,
|
|
4722
|
-
pluginContainer,
|
|
4723
|
-
moduleGraph
|
|
4724
|
-
}));
|
|
4725
|
-
const publicDir = path14.resolve(config.root, "public");
|
|
4726
|
-
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
4727
|
-
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
4728
5684
|
const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
|
|
4729
|
-
const outDirAbs =
|
|
5685
|
+
const outDirAbs = path15.resolve(config.root, config.build.outDir);
|
|
4730
5686
|
const watcher = watch(config.root, {
|
|
4731
5687
|
ignored: (filePath) => {
|
|
4732
5688
|
if (filePath === config.root) return false;
|
|
4733
|
-
if (filePath === outDirAbs || filePath.startsWith(outDirAbs +
|
|
4734
|
-
const rel =
|
|
4735
|
-
if (!rel || rel.startsWith("..") ||
|
|
4736
|
-
for (const seg of rel.split(
|
|
5689
|
+
if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path15.sep)) return true;
|
|
5690
|
+
const rel = path15.relative(config.root, filePath);
|
|
5691
|
+
if (!rel || rel.startsWith("..") || path15.isAbsolute(rel)) return false;
|
|
5692
|
+
for (const seg of rel.split(path15.sep)) {
|
|
4737
5693
|
if (ignoredSegments.has(seg)) return true;
|
|
4738
5694
|
}
|
|
4739
5695
|
return false;
|
|
@@ -4741,13 +5697,72 @@ async function createServer(inlineConfig = {}) {
|
|
|
4741
5697
|
ignoreInitial: true
|
|
4742
5698
|
});
|
|
4743
5699
|
let server;
|
|
5700
|
+
const environmentServices = {};
|
|
5701
|
+
let environmentDriversStarted = false;
|
|
5702
|
+
const logCloseError = (target, error) => {
|
|
5703
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
5704
|
+
logger.error(`[nasti] failed to close ${target}`, { error: normalized });
|
|
5705
|
+
};
|
|
5706
|
+
const startEnvironmentDrivers = async () => {
|
|
5707
|
+
if (environmentDriversStarted) return;
|
|
5708
|
+
environmentDriversStarted = true;
|
|
5709
|
+
const started = [];
|
|
5710
|
+
const attempted = [];
|
|
5711
|
+
try {
|
|
5712
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5713
|
+
if (!environment.driver?.serve) continue;
|
|
5714
|
+
attempted.push(environment);
|
|
5715
|
+
const result = await environment.driver.serve({
|
|
5716
|
+
...environment.getDriverContext(),
|
|
5717
|
+
server
|
|
5718
|
+
});
|
|
5719
|
+
started.push({ name, environment, service: result ?? {} });
|
|
5720
|
+
}
|
|
5721
|
+
for (const { name, service } of started) {
|
|
5722
|
+
environmentServices[name] = service;
|
|
5723
|
+
if (service.middleware) app.use(service.middleware);
|
|
5724
|
+
}
|
|
5725
|
+
} catch (error) {
|
|
5726
|
+
environmentDriversStarted = false;
|
|
5727
|
+
for (const { name } of started) {
|
|
5728
|
+
delete environmentServices[name];
|
|
5729
|
+
}
|
|
5730
|
+
for (const environment of attempted.reverse()) {
|
|
5731
|
+
try {
|
|
5732
|
+
await environment.driver?.close?.(environment.getDriverContext());
|
|
5733
|
+
} catch (closeError) {
|
|
5734
|
+
logCloseError(`environment driver "${environment.driver.name}"`, closeError);
|
|
5735
|
+
}
|
|
5736
|
+
}
|
|
5737
|
+
throw error;
|
|
5738
|
+
}
|
|
5739
|
+
};
|
|
5740
|
+
const notifyEnvironmentDrivers = (file, event) => {
|
|
5741
|
+
for (const environment of Object.values(environments)) {
|
|
5742
|
+
if (!environment.driver?.watchChange) continue;
|
|
5743
|
+
void Promise.resolve(
|
|
5744
|
+
environment.driver.watchChange(file, event, environment.getDriverContext())
|
|
5745
|
+
).catch((error) => {
|
|
5746
|
+
logger.error(
|
|
5747
|
+
`[nasti] environment driver "${environment.driver.name}" watchChange failed`,
|
|
5748
|
+
{ error }
|
|
5749
|
+
);
|
|
5750
|
+
});
|
|
5751
|
+
}
|
|
5752
|
+
};
|
|
4744
5753
|
watcher.on("change", (file) => {
|
|
4745
5754
|
ssrRunner?.invalidateFile(file);
|
|
4746
5755
|
handleFileChange(file, server);
|
|
5756
|
+
notifyEnvironmentDrivers(file, "change");
|
|
4747
5757
|
});
|
|
4748
5758
|
watcher.on("add", (file) => {
|
|
4749
5759
|
ssrRunner?.invalidateFile(file);
|
|
4750
5760
|
handleFileChange(file, server);
|
|
5761
|
+
notifyEnvironmentDrivers(file, "add");
|
|
5762
|
+
});
|
|
5763
|
+
watcher.on("unlink", (file) => {
|
|
5764
|
+
ssrRunner?.invalidateFile(file);
|
|
5765
|
+
notifyEnvironmentDrivers(file, "unlink");
|
|
4751
5766
|
});
|
|
4752
5767
|
server = {
|
|
4753
5768
|
config: configWithPlugins,
|
|
@@ -4756,10 +5771,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4756
5771
|
watcher,
|
|
4757
5772
|
ws,
|
|
4758
5773
|
environments,
|
|
5774
|
+
environmentServices,
|
|
4759
5775
|
async listen(port) {
|
|
4760
5776
|
const finalPort = port ?? config.server.port;
|
|
4761
5777
|
const host = config.server.host === true ? "0.0.0.0" : config.server.host;
|
|
4762
5778
|
await pluginContainer.buildStart();
|
|
5779
|
+
await startEnvironmentDrivers();
|
|
4763
5780
|
return new Promise((resolve, reject) => {
|
|
4764
5781
|
let currentPort = finalPort;
|
|
4765
5782
|
const onListening = () => {
|
|
@@ -4767,15 +5784,20 @@ async function createServer(inlineConfig = {}) {
|
|
|
4767
5784
|
config.server.port = actualPort;
|
|
4768
5785
|
const localUrl = `http://localhost:${actualPort}/`;
|
|
4769
5786
|
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}/` : null;
|
|
5787
|
+
const driverLocalUrls = Object.values(environmentServices).flatMap((service) => service.localUrls ?? []);
|
|
5788
|
+
const driverNetworkUrls = Object.values(environmentServices).flatMap((service) => service.networkUrls ?? []);
|
|
4770
5789
|
logger.clearScreen("info");
|
|
4771
5790
|
const readyIn = Math.ceil(performance.now() - startTime);
|
|
4772
5791
|
logger.info(
|
|
4773
5792
|
`
|
|
4774
|
-
${pc8.cyan(pc8.bold("NASTI"))} ${pc8.cyan(`v${"2.
|
|
5793
|
+
${pc8.cyan(pc8.bold("NASTI"))} ${pc8.cyan(`v${"2.4.0"}`)} ${pc8.dim("ready in")} ${pc8.bold(readyIn)} ${pc8.dim("ms")}
|
|
4775
5794
|
`
|
|
4776
5795
|
);
|
|
4777
5796
|
printServerUrls(
|
|
4778
|
-
{
|
|
5797
|
+
{
|
|
5798
|
+
local: [localUrl, ...driverLocalUrls],
|
|
5799
|
+
network: [...networkUrl ? [networkUrl] : [], ...driverNetworkUrls]
|
|
5800
|
+
},
|
|
4779
5801
|
logger.info
|
|
4780
5802
|
);
|
|
4781
5803
|
logger.info("");
|
|
@@ -4796,7 +5818,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4796
5818
|
},
|
|
4797
5819
|
async transformRequest(url) {
|
|
4798
5820
|
const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
|
|
4799
|
-
return transformRequest2(url, {
|
|
5821
|
+
return transformRequest2(url, {
|
|
5822
|
+
config: configWithPlugins,
|
|
5823
|
+
pluginContainer,
|
|
5824
|
+
moduleGraph,
|
|
5825
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5826
|
+
});
|
|
4800
5827
|
},
|
|
4801
5828
|
async ssrLoadModule(url) {
|
|
4802
5829
|
const runner = await getSsrRunner();
|
|
@@ -4805,11 +5832,63 @@ async function createServer(inlineConfig = {}) {
|
|
|
4805
5832
|
async close() {
|
|
4806
5833
|
await pluginContainer.buildEnd();
|
|
4807
5834
|
await bundledServer?.close();
|
|
4808
|
-
|
|
5835
|
+
let environmentCloseFailed = false;
|
|
5836
|
+
let firstEnvironmentCloseError;
|
|
5837
|
+
for (const environment of Object.values(environments).reverse()) {
|
|
5838
|
+
try {
|
|
5839
|
+
await environment.close();
|
|
5840
|
+
} catch (error) {
|
|
5841
|
+
if (!environmentCloseFailed) {
|
|
5842
|
+
environmentCloseFailed = true;
|
|
5843
|
+
firstEnvironmentCloseError = error;
|
|
5844
|
+
}
|
|
5845
|
+
logCloseError(`environment "${environment.name}"`, error);
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
await watcher.close();
|
|
4809
5849
|
ws.close();
|
|
4810
5850
|
httpServer.close();
|
|
5851
|
+
if (environmentCloseFailed) {
|
|
5852
|
+
throw firstEnvironmentCloseError;
|
|
5853
|
+
}
|
|
4811
5854
|
}
|
|
4812
5855
|
};
|
|
5856
|
+
try {
|
|
5857
|
+
await startEnvironmentDrivers();
|
|
5858
|
+
} catch (error) {
|
|
5859
|
+
if (bundledServer) {
|
|
5860
|
+
try {
|
|
5861
|
+
await bundledServer.close();
|
|
5862
|
+
} catch (closeError) {
|
|
5863
|
+
logCloseError("bundled dev server after driver startup failure", closeError);
|
|
5864
|
+
}
|
|
5865
|
+
}
|
|
5866
|
+
try {
|
|
5867
|
+
await watcher.close();
|
|
5868
|
+
} catch (closeError) {
|
|
5869
|
+
logCloseError("file watcher after driver startup failure", closeError);
|
|
5870
|
+
}
|
|
5871
|
+
try {
|
|
5872
|
+
ws.close();
|
|
5873
|
+
} catch (closeError) {
|
|
5874
|
+
logCloseError("WebSocket server after driver startup failure", closeError);
|
|
5875
|
+
}
|
|
5876
|
+
try {
|
|
5877
|
+
httpServer.close();
|
|
5878
|
+
} catch (closeError) {
|
|
5879
|
+
logCloseError("HTTP server after driver startup failure", closeError);
|
|
5880
|
+
}
|
|
5881
|
+
throw error;
|
|
5882
|
+
}
|
|
5883
|
+
app.use(transformMiddleware({
|
|
5884
|
+
config: configWithPlugins,
|
|
5885
|
+
pluginContainer,
|
|
5886
|
+
moduleGraph,
|
|
5887
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5888
|
+
}));
|
|
5889
|
+
const publicDir = path15.resolve(config.root, "public");
|
|
5890
|
+
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
5891
|
+
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
4813
5892
|
const postMiddlewares = [];
|
|
4814
5893
|
for (const plugin of allPlugins) {
|
|
4815
5894
|
if (plugin.configureServer) {
|
|
@@ -4844,6 +5923,7 @@ var init_server = __esm({
|
|
|
4844
5923
|
init_middleware();
|
|
4845
5924
|
init_hmr();
|
|
4846
5925
|
init_builtins();
|
|
5926
|
+
init_plugin_api();
|
|
4847
5927
|
}
|
|
4848
5928
|
});
|
|
4849
5929
|
|
|
@@ -4890,39 +5970,38 @@ var init_electron = __esm({
|
|
|
4890
5970
|
var electron_exports = {};
|
|
4891
5971
|
__export(electron_exports, {
|
|
4892
5972
|
buildElectron: () => buildElectron,
|
|
5973
|
+
createElectronRendererConfig: () => createElectronRendererConfig,
|
|
4893
5974
|
detectInstalledElectron: () => detectInstalledElectron,
|
|
4894
5975
|
normalizePreload: () => normalizePreload
|
|
4895
5976
|
});
|
|
4896
|
-
import
|
|
4897
|
-
import
|
|
5977
|
+
import path16 from "path";
|
|
5978
|
+
import fs11 from "fs";
|
|
4898
5979
|
import { rolldown as rolldown2 } from "rolldown";
|
|
4899
5980
|
import pc9 from "picocolors";
|
|
4900
5981
|
async function buildElectron(inlineConfig = {}) {
|
|
4901
5982
|
const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
|
|
4902
5983
|
const startTime = performance.now();
|
|
4903
5984
|
assertElectronVersion(config);
|
|
4904
|
-
console.log(pc9.cyan("\n\u26A1 nasti build (electron)") + pc9.dim(` v${"2.
|
|
5985
|
+
console.log(pc9.cyan("\n\u26A1 nasti build (electron)") + pc9.dim(` v${"2.4.0"}`));
|
|
4905
5986
|
console.log(pc9.dim(` root: ${config.root}`));
|
|
4906
5987
|
console.log(pc9.dim(` mode: ${config.mode}`));
|
|
4907
5988
|
console.log(pc9.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
|
|
4908
|
-
const outDir =
|
|
4909
|
-
if (config.build.emptyOutDir &&
|
|
4910
|
-
|
|
5989
|
+
const outDir = path16.resolve(config.root, config.build.outDir);
|
|
5990
|
+
if (config.build.emptyOutDir && fs11.existsSync(outDir)) {
|
|
5991
|
+
fs11.rmSync(outDir, { recursive: true, force: true });
|
|
4911
5992
|
}
|
|
4912
|
-
|
|
4913
|
-
const rendererOutDir =
|
|
5993
|
+
fs11.mkdirSync(outDir, { recursive: true });
|
|
5994
|
+
const rendererOutDir = path16.join(outDir, "renderer");
|
|
4914
5995
|
const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
4915
|
-
await build2({
|
|
4916
|
-
...inlineConfig,
|
|
4917
|
-
target: "web",
|
|
5996
|
+
await build2(createElectronRendererConfig(config, inlineConfig, {
|
|
4918
5997
|
build: {
|
|
4919
5998
|
...inlineConfig.build,
|
|
4920
5999
|
outDir: rendererOutDir,
|
|
4921
6000
|
emptyOutDir: false
|
|
4922
6001
|
}
|
|
4923
|
-
});
|
|
4924
|
-
const mainEntry =
|
|
4925
|
-
if (!
|
|
6002
|
+
}));
|
|
6003
|
+
const mainEntry = path16.resolve(config.root, config.electron.main);
|
|
6004
|
+
if (!fs11.existsSync(mainEntry)) {
|
|
4926
6005
|
throw new Error(
|
|
4927
6006
|
`Electron main entry not found: ${config.electron.main}
|
|
4928
6007
|
\u5728 nasti.config.ts \u7684 electron.main \u6307\u5B9A\u4E3B\u8FDB\u7A0B\u5165\u53E3\u6587\u4EF6\u3002`
|
|
@@ -4936,11 +6015,11 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4936
6015
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
4937
6016
|
const preloadFiles = [];
|
|
4938
6017
|
for (const entry of preloadEntries) {
|
|
4939
|
-
if (!
|
|
6018
|
+
if (!fs11.existsSync(entry)) {
|
|
4940
6019
|
console.warn(pc9.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
|
|
4941
6020
|
continue;
|
|
4942
6021
|
}
|
|
4943
|
-
const base =
|
|
6022
|
+
const base = path16.basename(entry).replace(/\.[^.]+$/, "");
|
|
4944
6023
|
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
4945
6024
|
await bundleNode(config, entry, {
|
|
4946
6025
|
outFile: out,
|
|
@@ -4952,10 +6031,10 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4952
6031
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
4953
6032
|
console.log(pc9.green(`
|
|
4954
6033
|
\u2713 Electron build complete in ${elapsed}s`));
|
|
4955
|
-
console.log(pc9.dim(` renderer: ${
|
|
4956
|
-
console.log(pc9.dim(` main: ${
|
|
6034
|
+
console.log(pc9.dim(` renderer: ${path16.relative(config.root, rendererOutDir)}/`));
|
|
6035
|
+
console.log(pc9.dim(` main: ${path16.relative(config.root, mainFile)}`));
|
|
4957
6036
|
for (const pf of preloadFiles) {
|
|
4958
|
-
console.log(pc9.dim(` preload: ${
|
|
6037
|
+
console.log(pc9.dim(` preload: ${path16.relative(config.root, pf)}`));
|
|
4959
6038
|
}
|
|
4960
6039
|
console.log();
|
|
4961
6040
|
return { rendererOutDir, mainFile, preloadFiles };
|
|
@@ -4974,7 +6053,8 @@ async function bundleNode(config, entry, opts) {
|
|
|
4974
6053
|
const result = transformCode(id, code, {
|
|
4975
6054
|
sourcemap: !!config.build.sourcemap,
|
|
4976
6055
|
jsxRuntime: "automatic",
|
|
4977
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6056
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6057
|
+
target: config.electron.nodeTarget
|
|
4978
6058
|
});
|
|
4979
6059
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
4980
6060
|
}
|
|
@@ -4985,10 +6065,14 @@ async function bundleNode(config, entry, opts) {
|
|
|
4985
6065
|
...restInputOptions,
|
|
4986
6066
|
input: entry,
|
|
4987
6067
|
platform: "node",
|
|
4988
|
-
transform: {
|
|
6068
|
+
transform: {
|
|
6069
|
+
...userTransform,
|
|
6070
|
+
target: config.electron.nodeTarget,
|
|
6071
|
+
define: mergedDefine
|
|
6072
|
+
},
|
|
4989
6073
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
4990
6074
|
});
|
|
4991
|
-
|
|
6075
|
+
fs11.mkdirSync(path16.dirname(opts.outFile), { recursive: true });
|
|
4992
6076
|
await bundle2.write({
|
|
4993
6077
|
sourcemap: !!config.build.sourcemap,
|
|
4994
6078
|
minify: !!config.build.minify,
|
|
@@ -4999,16 +6083,35 @@ async function bundleNode(config, entry, opts) {
|
|
|
4999
6083
|
codeSplitting: false
|
|
5000
6084
|
});
|
|
5001
6085
|
await bundle2.close();
|
|
5002
|
-
console.log(pc9.dim(` \u2713 ${opts.label} \u2192 ${
|
|
6086
|
+
console.log(pc9.dim(` \u2713 ${opts.label} \u2192 ${path16.relative(config.root, opts.outFile)}`));
|
|
5003
6087
|
return opts.outFile;
|
|
5004
6088
|
}
|
|
6089
|
+
function createElectronRendererConfig(config, inlineConfig = {}, overrides = {}) {
|
|
6090
|
+
const inlineClient = inlineConfig.environments?.client ?? {};
|
|
6091
|
+
return {
|
|
6092
|
+
...inlineConfig,
|
|
6093
|
+
...overrides,
|
|
6094
|
+
root: config.root,
|
|
6095
|
+
mode: config.mode,
|
|
6096
|
+
target: "web",
|
|
6097
|
+
framework: config.framework,
|
|
6098
|
+
base: config.base === "/" ? "./" : config.base,
|
|
6099
|
+
environments: {
|
|
6100
|
+
...inlineConfig.environments ?? {},
|
|
6101
|
+
client: {
|
|
6102
|
+
...inlineClient,
|
|
6103
|
+
html: config.electron.renderer
|
|
6104
|
+
}
|
|
6105
|
+
}
|
|
6106
|
+
};
|
|
6107
|
+
}
|
|
5005
6108
|
function outFileName(outDir, base, format) {
|
|
5006
6109
|
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
5007
|
-
return
|
|
6110
|
+
return path16.join(outDir, base + ext);
|
|
5008
6111
|
}
|
|
5009
6112
|
function normalizePreload(preload, root) {
|
|
5010
6113
|
const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
|
|
5011
|
-
return list.map((p) =>
|
|
6114
|
+
return list.map((p) => path16.resolve(root, p));
|
|
5012
6115
|
}
|
|
5013
6116
|
function assertElectronVersion(config) {
|
|
5014
6117
|
const min = config.electron.minVersion;
|
|
@@ -5023,9 +6126,9 @@ function assertElectronVersion(config) {
|
|
|
5023
6126
|
}
|
|
5024
6127
|
function detectInstalledElectron(root) {
|
|
5025
6128
|
try {
|
|
5026
|
-
const pkgPath =
|
|
5027
|
-
if (!
|
|
5028
|
-
const pkg = JSON.parse(
|
|
6129
|
+
const pkgPath = path16.resolve(root, "node_modules/electron/package.json");
|
|
6130
|
+
if (!fs11.existsSync(pkgPath)) return null;
|
|
6131
|
+
const pkg = JSON.parse(fs11.readFileSync(pkgPath, "utf-8"));
|
|
5029
6132
|
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
5030
6133
|
return Number.isFinite(major) ? major : null;
|
|
5031
6134
|
} catch {
|
|
@@ -5046,10 +6149,11 @@ var init_electron2 = __esm({
|
|
|
5046
6149
|
// src/server/electron-dev.ts
|
|
5047
6150
|
var electron_dev_exports = {};
|
|
5048
6151
|
__export(electron_dev_exports, {
|
|
6152
|
+
electronRendererDevPath: () => electronRendererDevPath,
|
|
5049
6153
|
startElectronDev: () => startElectronDev
|
|
5050
6154
|
});
|
|
5051
|
-
import
|
|
5052
|
-
import
|
|
6155
|
+
import path17 from "path";
|
|
6156
|
+
import fs12 from "fs";
|
|
5053
6157
|
import { createRequire as createRequire5 } from "module";
|
|
5054
6158
|
import { spawn } from "child_process";
|
|
5055
6159
|
import chokidar from "chokidar";
|
|
@@ -5059,17 +6163,21 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5059
6163
|
const { noSpawn, ...rest } = inlineConfig;
|
|
5060
6164
|
const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
|
|
5061
6165
|
warnElectronVersion(config);
|
|
5062
|
-
console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.
|
|
6166
|
+
console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.4.0"}`));
|
|
5063
6167
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5064
|
-
const server = await createServer2({
|
|
6168
|
+
const server = await createServer2({
|
|
6169
|
+
...rest,
|
|
6170
|
+
target: "electron",
|
|
6171
|
+
framework: config.framework
|
|
6172
|
+
});
|
|
5065
6173
|
await server.listen();
|
|
5066
|
-
const devUrl = `http://localhost:${server.config.server.port}
|
|
6174
|
+
const devUrl = `http://localhost:${server.config.server.port}` + electronRendererDevPath(config.electron.renderer);
|
|
5067
6175
|
console.log(pc10.dim(` renderer: ${devUrl}`));
|
|
5068
|
-
const stageDir =
|
|
5069
|
-
|
|
5070
|
-
const mainEntry =
|
|
6176
|
+
const stageDir = path17.resolve(config.root, ".nasti");
|
|
6177
|
+
fs12.mkdirSync(stageDir, { recursive: true });
|
|
6178
|
+
const mainEntry = path17.resolve(config.root, config.electron.main);
|
|
5071
6179
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
5072
|
-
const builtMainFile =
|
|
6180
|
+
const builtMainFile = path17.join(stageDir, "main" + extFor(config.electron.mainFormat));
|
|
5073
6181
|
const builtPreloadFiles = [];
|
|
5074
6182
|
const compileAll = async () => {
|
|
5075
6183
|
await compileNode(config, mainEntry, {
|
|
@@ -5079,9 +6187,9 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5079
6187
|
});
|
|
5080
6188
|
builtPreloadFiles.length = 0;
|
|
5081
6189
|
for (const entry of preloadEntries) {
|
|
5082
|
-
if (!
|
|
5083
|
-
const base =
|
|
5084
|
-
const out =
|
|
6190
|
+
if (!fs12.existsSync(entry)) continue;
|
|
6191
|
+
const base = path17.basename(entry).replace(/\.[^.]+$/, "");
|
|
6192
|
+
const out = path17.join(stageDir, base + extFor(config.electron.preloadFormat));
|
|
5085
6193
|
await compileNode(config, entry, {
|
|
5086
6194
|
outFile: out,
|
|
5087
6195
|
format: config.electron.preloadFormat,
|
|
@@ -5120,7 +6228,7 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5120
6228
|
};
|
|
5121
6229
|
spawnElectron();
|
|
5122
6230
|
if (config.electron.autoRestart) {
|
|
5123
|
-
const watchTargets = [mainEntry, ...preloadEntries].filter(
|
|
6231
|
+
const watchTargets = [mainEntry, ...preloadEntries].filter(fs12.existsSync);
|
|
5124
6232
|
const watcher = chokidar.watch(watchTargets, { ignoreInitial: true });
|
|
5125
6233
|
let restarting = null;
|
|
5126
6234
|
let pending = false;
|
|
@@ -5185,18 +6293,22 @@ async function compileNode(config, entry, opts) {
|
|
|
5185
6293
|
const result = transformCode(id, code, {
|
|
5186
6294
|
sourcemap: true,
|
|
5187
6295
|
jsxRuntime: "automatic",
|
|
5188
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6296
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6297
|
+
target: config.electron.nodeTarget
|
|
5189
6298
|
});
|
|
5190
6299
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
5191
6300
|
}
|
|
5192
6301
|
};
|
|
5193
6302
|
const bundle2 = await rolldown3({
|
|
5194
6303
|
input: entry,
|
|
5195
|
-
transform: {
|
|
6304
|
+
transform: {
|
|
6305
|
+
target: config.electron.nodeTarget,
|
|
6306
|
+
define: envDefine
|
|
6307
|
+
},
|
|
5196
6308
|
platform: "node",
|
|
5197
6309
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
5198
6310
|
});
|
|
5199
|
-
|
|
6311
|
+
fs12.mkdirSync(path17.dirname(opts.outFile), { recursive: true });
|
|
5200
6312
|
await bundle2.write({
|
|
5201
6313
|
file: opts.outFile,
|
|
5202
6314
|
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
@@ -5208,15 +6320,19 @@ async function compileNode(config, entry, opts) {
|
|
|
5208
6320
|
});
|
|
5209
6321
|
await bundle2.close();
|
|
5210
6322
|
}
|
|
6323
|
+
function electronRendererDevPath(renderer) {
|
|
6324
|
+
const normalized = renderer.split(path17.sep).join("/").replace(/^\.?\//, "");
|
|
6325
|
+
return normalized === "index.html" ? "/" : `/${normalized}`;
|
|
6326
|
+
}
|
|
5211
6327
|
function resolveElectronBinary(config) {
|
|
5212
|
-
if (config.electron.electronPath &&
|
|
6328
|
+
if (config.electron.electronPath && fs12.existsSync(config.electron.electronPath)) {
|
|
5213
6329
|
return config.electron.electronPath;
|
|
5214
6330
|
}
|
|
5215
6331
|
try {
|
|
5216
|
-
const require2 = createRequire5(
|
|
6332
|
+
const require2 = createRequire5(path17.resolve(config.root, "package.json"));
|
|
5217
6333
|
const pathFile = require2.resolve("electron");
|
|
5218
6334
|
const electronModule = require2(pathFile);
|
|
5219
|
-
if (typeof electronModule === "string" &&
|
|
6335
|
+
if (typeof electronModule === "string" && fs12.existsSync(electronModule)) {
|
|
5220
6336
|
return electronModule;
|
|
5221
6337
|
}
|
|
5222
6338
|
} catch {
|
|
@@ -5391,20 +6507,20 @@ cli.command("preview [root]", "Preview production build").option("--port <port>"
|
|
|
5391
6507
|
const logger = createCliLogger(options);
|
|
5392
6508
|
try {
|
|
5393
6509
|
const http2 = await import("http");
|
|
5394
|
-
const
|
|
6510
|
+
const path18 = await import("path");
|
|
5395
6511
|
const os2 = await import("os");
|
|
5396
6512
|
const sirv2 = (await import("sirv")).default;
|
|
5397
6513
|
const connect2 = (await import("connect")).default;
|
|
5398
6514
|
const { printServerUrls: printServerUrls2 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
|
|
5399
|
-
const resolvedRoot =
|
|
5400
|
-
const outDir =
|
|
6515
|
+
const resolvedRoot = path18.resolve(root ?? ".");
|
|
6516
|
+
const outDir = path18.resolve(resolvedRoot, options.outDir);
|
|
5401
6517
|
const app = connect2();
|
|
5402
6518
|
app.use(sirv2(outDir, { single: true, etag: true, gzip: true, brotli: true }));
|
|
5403
6519
|
const port = options.port;
|
|
5404
6520
|
const host = options.host === true ? "0.0.0.0" : options.host ?? "localhost";
|
|
5405
6521
|
http2.createServer(app).listen(port, host, () => {
|
|
5406
6522
|
logger.info(`
|
|
5407
|
-
${pc11.cyan(pc11.bold("NASTI"))} ${pc11.cyan(`v${"2.
|
|
6523
|
+
${pc11.cyan(pc11.bold("NASTI"))} ${pc11.cyan(`v${"2.4.0"}`)} ${pc11.dim("preview")}
|
|
5408
6524
|
`);
|
|
5409
6525
|
printServerUrls2(
|
|
5410
6526
|
{
|
|
@@ -5421,6 +6537,6 @@ cli.command("preview [root]", "Preview production build").option("--port <port>"
|
|
|
5421
6537
|
}
|
|
5422
6538
|
});
|
|
5423
6539
|
cli.help();
|
|
5424
|
-
cli.version("2.
|
|
6540
|
+
cli.version("2.4.0");
|
|
5425
6541
|
cli.parse();
|
|
5426
6542
|
//# sourceMappingURL=cli.js.map
|