@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/index.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) => (path19) => {
|
|
14
|
+
var fn = map[path19];
|
|
15
15
|
if (fn) return fn();
|
|
16
|
-
throw new Error("Module not found in bundle: " +
|
|
16
|
+
throw new Error("Module not found in bundle: " + path19);
|
|
17
17
|
};
|
|
18
18
|
var __esm = (fn, res) => function __init() {
|
|
19
19
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -225,6 +225,92 @@ var init_logger = __esm({
|
|
|
225
225
|
}
|
|
226
226
|
});
|
|
227
227
|
|
|
228
|
+
// src/core/plugin-api.ts
|
|
229
|
+
function orderPlugins(plugins) {
|
|
230
|
+
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);
|
|
231
|
+
const indexesByName = /* @__PURE__ */ new Map();
|
|
232
|
+
baseline.forEach((plugin, index2) => {
|
|
233
|
+
const indexes = indexesByName.get(plugin.name) ?? [];
|
|
234
|
+
indexes.push(index2);
|
|
235
|
+
indexesByName.set(plugin.name, indexes);
|
|
236
|
+
});
|
|
237
|
+
const edges = baseline.map(() => /* @__PURE__ */ new Set());
|
|
238
|
+
const indegree = baseline.map(() => 0);
|
|
239
|
+
const addEdge = (from, to) => {
|
|
240
|
+
if (from === to || edges[from].has(to)) return;
|
|
241
|
+
edges[from].add(to);
|
|
242
|
+
indegree[to]++;
|
|
243
|
+
};
|
|
244
|
+
baseline.forEach((plugin, current) => {
|
|
245
|
+
for (const dependency of plugin.pre ?? []) {
|
|
246
|
+
for (const before of indexesByName.get(dependency) ?? []) addEdge(before, current);
|
|
247
|
+
}
|
|
248
|
+
for (const dependency of plugin.post ?? []) {
|
|
249
|
+
for (const after of indexesByName.get(dependency) ?? []) addEdge(current, after);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
const ready = indegree.map((degree, index2) => ({ degree, index: index2 })).filter(({ degree }) => degree === 0).map(({ index: index2 }) => index2);
|
|
253
|
+
const ordered = [];
|
|
254
|
+
while (ready.length > 0) {
|
|
255
|
+
ready.sort((a, b) => a - b);
|
|
256
|
+
const current = ready.shift();
|
|
257
|
+
ordered.push(baseline[current]);
|
|
258
|
+
for (const next of edges[current]) {
|
|
259
|
+
indegree[next]--;
|
|
260
|
+
if (indegree[next] === 0) ready.push(next);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (ordered.length !== baseline.length) {
|
|
264
|
+
const cyclic = baseline.filter((_, index2) => indegree[index2] > 0).map((plugin) => plugin.name);
|
|
265
|
+
throw new Error(
|
|
266
|
+
`[nasti] circular plugin setup dependency: ${[...new Set(cyclic)].join(", ")}`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
return ordered;
|
|
270
|
+
}
|
|
271
|
+
async function setupPluginApi(config, plugins) {
|
|
272
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
273
|
+
const api = {
|
|
274
|
+
config,
|
|
275
|
+
logger: config.logger,
|
|
276
|
+
expose(key, value) {
|
|
277
|
+
if (exposed.has(key) && exposed.get(key) !== value) {
|
|
278
|
+
throw new Error(`[nasti] plugin API key already exposed: ${String(key)}`);
|
|
279
|
+
}
|
|
280
|
+
exposed.set(key, value);
|
|
281
|
+
},
|
|
282
|
+
useExposed(key) {
|
|
283
|
+
return exposed.get(key);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
apiByConfig.set(config, api);
|
|
287
|
+
for (const plugin of plugins) {
|
|
288
|
+
await plugin.setup?.(api);
|
|
289
|
+
}
|
|
290
|
+
return api;
|
|
291
|
+
}
|
|
292
|
+
function getPluginApi(config) {
|
|
293
|
+
const api = apiByConfig.get(config);
|
|
294
|
+
if (!api) {
|
|
295
|
+
throw new Error(
|
|
296
|
+
"[nasti] internal: plugin API requested before setup; getPluginApi requires the original ResolvedConfig reference registered by setupPluginApi, not a shallow copy"
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return api;
|
|
300
|
+
}
|
|
301
|
+
function enforceRank(plugin) {
|
|
302
|
+
if (plugin.enforce === "pre") return 0;
|
|
303
|
+
if (plugin.enforce === "post") return 2;
|
|
304
|
+
return 1;
|
|
305
|
+
}
|
|
306
|
+
var apiByConfig;
|
|
307
|
+
var init_plugin_api = __esm({
|
|
308
|
+
"src/core/plugin-api.ts"() {
|
|
309
|
+
"use strict";
|
|
310
|
+
apiByConfig = /* @__PURE__ */ new WeakMap();
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
228
314
|
// src/config/index.ts
|
|
229
315
|
import { pathToFileURL } from "url";
|
|
230
316
|
import path from "path";
|
|
@@ -265,6 +351,43 @@ async function loadConfigFromFile(root) {
|
|
|
265
351
|
}
|
|
266
352
|
return {};
|
|
267
353
|
}
|
|
354
|
+
function detectFramework(root) {
|
|
355
|
+
const sourceRoot = path.resolve(root, "src");
|
|
356
|
+
if (containsVueFile(sourceRoot)) return "vue";
|
|
357
|
+
const packagePath = path.resolve(root, "package.json");
|
|
358
|
+
if (fs.existsSync(packagePath)) {
|
|
359
|
+
try {
|
|
360
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
|
|
361
|
+
const dependencies = {
|
|
362
|
+
...pkg.dependencies ?? {},
|
|
363
|
+
...pkg.devDependencies ?? {},
|
|
364
|
+
...pkg.peerDependencies ?? {},
|
|
365
|
+
...pkg.optionalDependencies ?? {}
|
|
366
|
+
};
|
|
367
|
+
const hasVue = "vue" in dependencies || "@vue/runtime-dom" in dependencies;
|
|
368
|
+
const hasReact = "react" in dependencies || "react-dom" in dependencies;
|
|
369
|
+
if (hasVue && !hasReact) return "vue";
|
|
370
|
+
if (hasReact) return "react";
|
|
371
|
+
if (hasVue) return "vue";
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return "react";
|
|
376
|
+
}
|
|
377
|
+
function containsVueFile(dir, depth = 0) {
|
|
378
|
+
if (depth > 5 || !fs.existsSync(dir)) return false;
|
|
379
|
+
try {
|
|
380
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
381
|
+
if (entry.isFile() && entry.name.endsWith(".vue")) return true;
|
|
382
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && containsVueFile(path.join(dir, entry.name), depth + 1)) {
|
|
383
|
+
return true;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
} catch {
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
268
391
|
async function loadTsConfig(filePath) {
|
|
269
392
|
const { transformSync: transformSync2 } = await import("oxc-transform");
|
|
270
393
|
const code = fs.readFileSync(filePath, "utf-8");
|
|
@@ -311,7 +434,7 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
311
434
|
base: merged.base ?? defaults.base,
|
|
312
435
|
mode,
|
|
313
436
|
target: merged.target ?? defaults.target,
|
|
314
|
-
framework: merged.framework ?? defaults.framework,
|
|
437
|
+
framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
|
|
315
438
|
command,
|
|
316
439
|
resolve: {
|
|
317
440
|
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
@@ -358,7 +481,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
358
481
|
if (envOptions.build) Object.assign(resolved.build, envOptions.build);
|
|
359
482
|
resolved.environments.client = {
|
|
360
483
|
consumer,
|
|
361
|
-
|
|
484
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
485
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
486
|
+
html: path.resolve(
|
|
487
|
+
root,
|
|
488
|
+
envOptions.html ?? (resolved.target === "electron" ? resolved.electron.renderer : "index.html")
|
|
489
|
+
),
|
|
490
|
+
driver: envOptions.driver,
|
|
362
491
|
// 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
|
|
363
492
|
resolve: resolved.resolve,
|
|
364
493
|
build: resolved.build
|
|
@@ -367,7 +496,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
367
496
|
}
|
|
368
497
|
resolved.environments[name] = {
|
|
369
498
|
consumer,
|
|
370
|
-
|
|
499
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
500
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
501
|
+
html: envOptions.consumer === "client" && envOptions.html ? path.resolve(root, envOptions.html) : void 0,
|
|
502
|
+
driver: envOptions.driver,
|
|
371
503
|
resolve: {
|
|
372
504
|
alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
|
|
373
505
|
extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
|
|
@@ -386,12 +518,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
386
518
|
};
|
|
387
519
|
}
|
|
388
520
|
assertClientEnvironmentMirror(resolved);
|
|
389
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
521
|
+
const filteredPlugins = orderPlugins(rawPlugins.filter((p) => {
|
|
390
522
|
if (!p.apply) return true;
|
|
391
523
|
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
392
524
|
return p.apply === command;
|
|
393
|
-
});
|
|
525
|
+
}));
|
|
394
526
|
resolved.plugins = filteredPlugins;
|
|
527
|
+
await setupPluginApi(resolved, filteredPlugins);
|
|
395
528
|
if (resolved.target === "electron") {
|
|
396
529
|
const autoExternal = detectNativeDeps(root);
|
|
397
530
|
if (autoExternal.length > 0) {
|
|
@@ -407,6 +540,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
407
540
|
}
|
|
408
541
|
return resolved;
|
|
409
542
|
}
|
|
543
|
+
function normalizeEnvironmentEntries(entry, root) {
|
|
544
|
+
const entries = Array.isArray(entry) ? entry : entry ? [entry] : [];
|
|
545
|
+
return entries.map((item) => path.resolve(root, item));
|
|
546
|
+
}
|
|
410
547
|
function detectNativeDeps(root) {
|
|
411
548
|
const result = /* @__PURE__ */ new Set();
|
|
412
549
|
const pkgJsonPath = path.resolve(root, "package.json");
|
|
@@ -524,6 +661,7 @@ var init_config = __esm({
|
|
|
524
661
|
"use strict";
|
|
525
662
|
init_defaults();
|
|
526
663
|
init_logger();
|
|
664
|
+
init_plugin_api();
|
|
527
665
|
CONFIG_FILES = [
|
|
528
666
|
"nasti.config.ts",
|
|
529
667
|
"nasti.config.js",
|
|
@@ -585,6 +723,7 @@ function resolvePlugin(config) {
|
|
|
585
723
|
}
|
|
586
724
|
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
587
725
|
if (vueRuntimeEntry && source === "vue") return vueRuntimeEntry;
|
|
726
|
+
if (config.command === "build") return null;
|
|
588
727
|
try {
|
|
589
728
|
const resolved = require2.resolve(source, {
|
|
590
729
|
paths: [importer ? path2.dirname(importer) : config.root]
|
|
@@ -716,27 +855,27 @@ var require_process = __commonJS({
|
|
|
716
855
|
var require_filesystem = __commonJS({
|
|
717
856
|
"node_modules/detect-libc/lib/filesystem.js"(exports, module) {
|
|
718
857
|
"use strict";
|
|
719
|
-
var
|
|
858
|
+
var fs14 = __require("fs");
|
|
720
859
|
var LDD_PATH = "/usr/bin/ldd";
|
|
721
860
|
var SELF_PATH = "/proc/self/exe";
|
|
722
861
|
var MAX_LENGTH = 2048;
|
|
723
|
-
var readFileSync = (
|
|
724
|
-
const fd =
|
|
862
|
+
var readFileSync = (path19) => {
|
|
863
|
+
const fd = fs14.openSync(path19, "r");
|
|
725
864
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
726
|
-
const bytesRead =
|
|
727
|
-
|
|
865
|
+
const bytesRead = fs14.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
866
|
+
fs14.close(fd, () => {
|
|
728
867
|
});
|
|
729
868
|
return buffer.subarray(0, bytesRead);
|
|
730
869
|
};
|
|
731
|
-
var readFile = (
|
|
732
|
-
|
|
870
|
+
var readFile = (path19) => new Promise((resolve, reject) => {
|
|
871
|
+
fs14.open(path19, "r", (err, fd) => {
|
|
733
872
|
if (err) {
|
|
734
873
|
reject(err);
|
|
735
874
|
} else {
|
|
736
875
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
737
|
-
|
|
876
|
+
fs14.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
738
877
|
resolve(buffer.subarray(0, bytesRead));
|
|
739
|
-
|
|
878
|
+
fs14.close(fd, () => {
|
|
740
879
|
});
|
|
741
880
|
});
|
|
742
881
|
}
|
|
@@ -848,11 +987,11 @@ var require_detect_libc = __commonJS({
|
|
|
848
987
|
}
|
|
849
988
|
return null;
|
|
850
989
|
};
|
|
851
|
-
var familyFromInterpreterPath = (
|
|
852
|
-
if (
|
|
853
|
-
if (
|
|
990
|
+
var familyFromInterpreterPath = (path19) => {
|
|
991
|
+
if (path19) {
|
|
992
|
+
if (path19.includes("/ld-musl-")) {
|
|
854
993
|
return MUSL;
|
|
855
|
-
} else if (
|
|
994
|
+
} else if (path19.includes("/ld-linux-")) {
|
|
856
995
|
return GLIBC;
|
|
857
996
|
}
|
|
858
997
|
}
|
|
@@ -899,8 +1038,8 @@ var require_detect_libc = __commonJS({
|
|
|
899
1038
|
cachedFamilyInterpreter = null;
|
|
900
1039
|
try {
|
|
901
1040
|
const selfContent = await readFile(SELF_PATH);
|
|
902
|
-
const
|
|
903
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
1041
|
+
const path19 = interpreterPath(selfContent);
|
|
1042
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path19);
|
|
904
1043
|
} catch (e) {
|
|
905
1044
|
}
|
|
906
1045
|
return cachedFamilyInterpreter;
|
|
@@ -912,8 +1051,8 @@ var require_detect_libc = __commonJS({
|
|
|
912
1051
|
cachedFamilyInterpreter = null;
|
|
913
1052
|
try {
|
|
914
1053
|
const selfContent = readFileSync(SELF_PATH);
|
|
915
|
-
const
|
|
916
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
1054
|
+
const path19 = interpreterPath(selfContent);
|
|
1055
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path19);
|
|
917
1056
|
} catch (e) {
|
|
918
1057
|
}
|
|
919
1058
|
return cachedFamilyInterpreter;
|
|
@@ -1918,7 +2057,8 @@ function transformCode(filename, code, options = {}) {
|
|
|
1918
2057
|
importSource: options.jsxImportSource ?? "react",
|
|
1919
2058
|
refresh: options.reactRefresh ?? false
|
|
1920
2059
|
} : void 0,
|
|
1921
|
-
sourcemap: options.sourcemap ?? true
|
|
2060
|
+
sourcemap: options.sourcemap ?? true,
|
|
2061
|
+
target: options.target
|
|
1922
2062
|
});
|
|
1923
2063
|
if (result.errors && result.errors.length > 0) {
|
|
1924
2064
|
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
@@ -1976,8 +2116,8 @@ function vuePlugin(config) {
|
|
|
1976
2116
|
let descriptor = descriptorCache.get(filePath);
|
|
1977
2117
|
if (!descriptor) {
|
|
1978
2118
|
try {
|
|
1979
|
-
const
|
|
1980
|
-
const source =
|
|
2119
|
+
const fs14 = await import("fs");
|
|
2120
|
+
const source = fs14.readFileSync(filePath, "utf-8");
|
|
1981
2121
|
const parsed = sfc.parse(source, { filename: filePath });
|
|
1982
2122
|
if (parsed.errors.length) return null;
|
|
1983
2123
|
descriptor = parsed.descriptor;
|
|
@@ -2122,7 +2262,7 @@ function htmlPlugin(config) {
|
|
|
2122
2262
|
transformIndexHtml(html) {
|
|
2123
2263
|
const tags = [];
|
|
2124
2264
|
if (config.command === "serve") {
|
|
2125
|
-
const isReactLike = config.framework === "react"
|
|
2265
|
+
const isReactLike = config.framework === "react";
|
|
2126
2266
|
if (isReactLike) {
|
|
2127
2267
|
tags.push({
|
|
2128
2268
|
tag: "script",
|
|
@@ -2176,8 +2316,8 @@ function serializeTag(tag) {
|
|
|
2176
2316
|
}
|
|
2177
2317
|
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
2178
2318
|
}
|
|
2179
|
-
async function readHtmlFile(root) {
|
|
2180
|
-
const htmlPath = path6.resolve(root,
|
|
2319
|
+
async function readHtmlFile(root, htmlFile = "index.html") {
|
|
2320
|
+
const htmlPath = path6.isAbsolute(htmlFile) ? htmlFile : path6.resolve(root, htmlFile);
|
|
2181
2321
|
if (!fs4.existsSync(htmlPath)) return null;
|
|
2182
2322
|
return fs4.readFileSync(htmlPath, "utf-8");
|
|
2183
2323
|
}
|
|
@@ -2198,16 +2338,27 @@ window.__vite_plugin_react_preamble_installed__ = true;
|
|
|
2198
2338
|
// src/plugins/builtins.ts
|
|
2199
2339
|
function resolvePluginList(config, userPlugins, opts = {}) {
|
|
2200
2340
|
const isServe = config.command === "serve";
|
|
2341
|
+
let environmentOptions;
|
|
2342
|
+
if (opts.environmentName) {
|
|
2343
|
+
environmentOptions = config.environments[opts.environmentName];
|
|
2344
|
+
if (!environmentOptions) {
|
|
2345
|
+
throw new Error(
|
|
2346
|
+
`[nasti] unknown environment "${opts.environmentName}" \u2014 declare it in config.environments`
|
|
2347
|
+
);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
const pluginConfig = environmentOptions ? { ...config, resolve: environmentOptions.resolve, build: environmentOptions.build } : config;
|
|
2351
|
+
const consumer = opts.consumer ?? environmentOptions?.consumer;
|
|
2201
2352
|
return [
|
|
2202
2353
|
// vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
|
|
2203
|
-
...config.framework === "vue" ? [vuePlugin(
|
|
2204
|
-
resolvePlugin(
|
|
2205
|
-
cssPlugin(
|
|
2206
|
-
assetsPlugin(
|
|
2207
|
-
...isServe ? [htmlPlugin(
|
|
2354
|
+
...config.framework === "vue" ? [vuePlugin(pluginConfig)] : [],
|
|
2355
|
+
resolvePlugin(pluginConfig),
|
|
2356
|
+
cssPlugin(pluginConfig, opts.cssEngine, consumer),
|
|
2357
|
+
assetsPlugin(pluginConfig),
|
|
2358
|
+
...isServe ? [htmlPlugin(pluginConfig)] : [],
|
|
2208
2359
|
...userPlugins,
|
|
2209
2360
|
// cssPostPlugin 最后(enforce: 'post' 语义):renderChunk 聚合抽取
|
|
2210
|
-
...!isServe && opts.cssEngine ? [cssPostPlugin(
|
|
2361
|
+
...!isServe && opts.cssEngine ? [cssPostPlugin(pluginConfig, opts.cssEngine)] : []
|
|
2211
2362
|
];
|
|
2212
2363
|
}
|
|
2213
2364
|
var init_builtins = __esm({
|
|
@@ -2223,21 +2374,11 @@ var init_builtins = __esm({
|
|
|
2223
2374
|
});
|
|
2224
2375
|
|
|
2225
2376
|
// src/core/plugin-container.ts
|
|
2226
|
-
function sortPlugins(plugins) {
|
|
2227
|
-
const pre = [];
|
|
2228
|
-
const normal = [];
|
|
2229
|
-
const post = [];
|
|
2230
|
-
for (const plugin of plugins) {
|
|
2231
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
2232
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
2233
|
-
else normal.push(plugin);
|
|
2234
|
-
}
|
|
2235
|
-
return [...pre, ...normal, ...post];
|
|
2236
|
-
}
|
|
2237
2377
|
var PluginContainer;
|
|
2238
2378
|
var init_plugin_container = __esm({
|
|
2239
2379
|
"src/core/plugin-container.ts"() {
|
|
2240
2380
|
"use strict";
|
|
2381
|
+
init_plugin_api();
|
|
2241
2382
|
PluginContainer = class {
|
|
2242
2383
|
plugins;
|
|
2243
2384
|
config;
|
|
@@ -2248,7 +2389,7 @@ var init_plugin_container = __esm({
|
|
|
2248
2389
|
constructor(config, environment) {
|
|
2249
2390
|
this.config = config;
|
|
2250
2391
|
this.environment = environment;
|
|
2251
|
-
this.plugins =
|
|
2392
|
+
this.plugins = orderPlugins(config.plugins);
|
|
2252
2393
|
this.ctx = this.createContext();
|
|
2253
2394
|
}
|
|
2254
2395
|
createContext() {
|
|
@@ -2347,17 +2488,35 @@ var init_plugin_container = __esm({
|
|
|
2347
2488
|
}
|
|
2348
2489
|
});
|
|
2349
2490
|
|
|
2491
|
+
// src/core/url.ts
|
|
2492
|
+
function removeTimestampQuery(url) {
|
|
2493
|
+
const hashIndex = url.indexOf("#");
|
|
2494
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
2495
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
2496
|
+
const queryIndex = withoutHash.indexOf("?");
|
|
2497
|
+
if (queryIndex < 0) return url;
|
|
2498
|
+
const pathname = withoutHash.slice(0, queryIndex);
|
|
2499
|
+
const query = withoutHash.slice(queryIndex + 1).split("&").filter((part) => !/^t=\d+$/.test(part)).join("&");
|
|
2500
|
+
return pathname + (query ? `?${query}` : "") + hash;
|
|
2501
|
+
}
|
|
2502
|
+
var init_url = __esm({
|
|
2503
|
+
"src/core/url.ts"() {
|
|
2504
|
+
"use strict";
|
|
2505
|
+
}
|
|
2506
|
+
});
|
|
2507
|
+
|
|
2350
2508
|
// src/core/module-graph.ts
|
|
2351
2509
|
var ModuleGraph;
|
|
2352
2510
|
var init_module_graph = __esm({
|
|
2353
2511
|
"src/core/module-graph.ts"() {
|
|
2354
2512
|
"use strict";
|
|
2513
|
+
init_url();
|
|
2355
2514
|
ModuleGraph = class {
|
|
2356
2515
|
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
2357
2516
|
idToModuleMap = /* @__PURE__ */ new Map();
|
|
2358
2517
|
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
2359
2518
|
getModuleByUrl(url) {
|
|
2360
|
-
return this.urlToModuleMap.get(url);
|
|
2519
|
+
return this.urlToModuleMap.get(removeTimestampQuery(url));
|
|
2361
2520
|
}
|
|
2362
2521
|
getModuleById(id) {
|
|
2363
2522
|
return this.idToModuleMap.get(id);
|
|
@@ -2366,10 +2525,11 @@ var init_module_graph = __esm({
|
|
|
2366
2525
|
return this.fileToModulesMap.get(file);
|
|
2367
2526
|
}
|
|
2368
2527
|
async ensureEntryFromUrl(url) {
|
|
2369
|
-
|
|
2528
|
+
const normalizedUrl = removeTimestampQuery(url);
|
|
2529
|
+
let mod = this.urlToModuleMap.get(normalizedUrl);
|
|
2370
2530
|
if (mod) return mod;
|
|
2371
|
-
mod = this.createModule(
|
|
2372
|
-
this.urlToModuleMap.set(
|
|
2531
|
+
mod = this.createModule(normalizedUrl);
|
|
2532
|
+
this.urlToModuleMap.set(normalizedUrl, mod);
|
|
2373
2533
|
return mod;
|
|
2374
2534
|
}
|
|
2375
2535
|
createModule(url, id) {
|
|
@@ -2383,6 +2543,7 @@ var init_module_graph = __esm({
|
|
|
2383
2543
|
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
2384
2544
|
transformResult: null,
|
|
2385
2545
|
lastHMRTimestamp: 0,
|
|
2546
|
+
invalidationVersion: 0,
|
|
2386
2547
|
isSelfAccepting: false
|
|
2387
2548
|
};
|
|
2388
2549
|
this.idToModuleMap.set(mod.id, mod);
|
|
@@ -2425,10 +2586,64 @@ var init_module_graph = __esm({
|
|
|
2425
2586
|
}
|
|
2426
2587
|
}
|
|
2427
2588
|
}
|
|
2589
|
+
/**
|
|
2590
|
+
* 用一次转换得到的信息原子更新 import 与 HMR accept 关系。
|
|
2591
|
+
* 依赖节点会在真正被浏览器请求前预先创建,这样入口模块先转换时也能建立完整图。
|
|
2592
|
+
*/
|
|
2593
|
+
async updateModuleInfo(mod, importedUrls, acceptedUrls, isSelfAccepting, expectedInvalidationVersion) {
|
|
2594
|
+
const importedModules = await Promise.all(
|
|
2595
|
+
[...importedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
2596
|
+
);
|
|
2597
|
+
const acceptedModules = await Promise.all(
|
|
2598
|
+
[...acceptedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
2599
|
+
);
|
|
2600
|
+
if (expectedInvalidationVersion !== void 0 && mod.invalidationVersion !== expectedInvalidationVersion) {
|
|
2601
|
+
return null;
|
|
2602
|
+
}
|
|
2603
|
+
const previousImports = new Set(mod.importedModules);
|
|
2604
|
+
for (const imported of previousImports) {
|
|
2605
|
+
imported.importers.delete(mod);
|
|
2606
|
+
}
|
|
2607
|
+
mod.importedModules.clear();
|
|
2608
|
+
mod.acceptedHmrDeps.clear();
|
|
2609
|
+
for (const imported of importedModules) {
|
|
2610
|
+
mod.importedModules.add(imported);
|
|
2611
|
+
imported.importers.add(mod);
|
|
2612
|
+
}
|
|
2613
|
+
for (const accepted of acceptedModules) {
|
|
2614
|
+
mod.acceptedHmrDeps.add(accepted);
|
|
2615
|
+
}
|
|
2616
|
+
mod.isSelfAccepting = isSelfAccepting;
|
|
2617
|
+
const pruned = /* @__PURE__ */ new Set();
|
|
2618
|
+
for (const imported of previousImports) {
|
|
2619
|
+
if (!mod.importedModules.has(imported) && imported.importers.size === 0) {
|
|
2620
|
+
pruned.add(imported);
|
|
2621
|
+
}
|
|
2622
|
+
}
|
|
2623
|
+
return pruned;
|
|
2624
|
+
}
|
|
2428
2625
|
/** 使模块的转换缓存失效 */
|
|
2429
|
-
invalidateModule(mod) {
|
|
2626
|
+
invalidateModule(mod, timestamp = Date.now()) {
|
|
2430
2627
|
mod.transformResult = null;
|
|
2431
|
-
mod.lastHMRTimestamp =
|
|
2628
|
+
mod.lastHMRTimestamp = timestamp;
|
|
2629
|
+
mod.invalidationVersion++;
|
|
2630
|
+
}
|
|
2631
|
+
/**
|
|
2632
|
+
* 仅失效到 HMR 边界:显式接受依赖的模块本身不会重执行;自接受模块需要失效,
|
|
2633
|
+
* 但不再继续影响其 importer。这样既能传播依赖时间戳,也不会隐式重复副作用。
|
|
2634
|
+
*/
|
|
2635
|
+
invalidateModuleAndImporters(mod, timestamp = Date.now(), seen = /* @__PURE__ */ new Set()) {
|
|
2636
|
+
if (seen.has(mod)) return;
|
|
2637
|
+
seen.add(mod);
|
|
2638
|
+
this.invalidateModule(mod, timestamp);
|
|
2639
|
+
for (const importer of mod.importers) {
|
|
2640
|
+
if (importer.acceptedHmrDeps.has(mod)) continue;
|
|
2641
|
+
if (importer.isSelfAccepting) {
|
|
2642
|
+
this.invalidateModule(importer, timestamp);
|
|
2643
|
+
continue;
|
|
2644
|
+
}
|
|
2645
|
+
this.invalidateModuleAndImporters(importer, timestamp, seen);
|
|
2646
|
+
}
|
|
2432
2647
|
}
|
|
2433
2648
|
/** 使所有模块缓存失效 */
|
|
2434
2649
|
invalidateAll() {
|
|
@@ -2439,34 +2654,32 @@ var init_module_graph = __esm({
|
|
|
2439
2654
|
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
2440
2655
|
getHmrBoundaries(mod) {
|
|
2441
2656
|
const boundaries = [];
|
|
2442
|
-
const
|
|
2443
|
-
const
|
|
2444
|
-
if (
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
boundaries.push({ boundary
|
|
2448
|
-
return true;
|
|
2657
|
+
const traversed = /* @__PURE__ */ new Set();
|
|
2658
|
+
const addBoundary = (boundary, acceptedVia) => {
|
|
2659
|
+
if (!boundaries.some(
|
|
2660
|
+
(item) => item.boundary === boundary && item.acceptedVia === acceptedVia
|
|
2661
|
+
)) {
|
|
2662
|
+
boundaries.push({ boundary, acceptedVia });
|
|
2449
2663
|
}
|
|
2450
|
-
|
|
2451
|
-
|
|
2664
|
+
};
|
|
2665
|
+
const propagate = (node) => {
|
|
2666
|
+
if (traversed.has(node)) return true;
|
|
2667
|
+
traversed.add(node);
|
|
2668
|
+
if (node.isSelfAccepting) {
|
|
2669
|
+
addBoundary(node, node);
|
|
2452
2670
|
return true;
|
|
2453
2671
|
}
|
|
2454
2672
|
if (node.importers.size === 0) return false;
|
|
2455
2673
|
for (const importer of node.importers) {
|
|
2456
|
-
if (
|
|
2674
|
+
if (importer.acceptedHmrDeps.has(node)) {
|
|
2675
|
+
addBoundary(importer, node);
|
|
2676
|
+
continue;
|
|
2677
|
+
}
|
|
2678
|
+
if (!propagate(importer)) return false;
|
|
2457
2679
|
}
|
|
2458
2680
|
return true;
|
|
2459
2681
|
};
|
|
2460
|
-
|
|
2461
|
-
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
2462
|
-
return boundaries;
|
|
2463
|
-
}
|
|
2464
|
-
for (const importer of mod.importers) {
|
|
2465
|
-
if (!propagate(importer, mod)) {
|
|
2466
|
-
return [];
|
|
2467
|
-
}
|
|
2468
|
-
}
|
|
2469
|
-
return boundaries;
|
|
2682
|
+
return propagate(mod) ? boundaries : [];
|
|
2470
2683
|
}
|
|
2471
2684
|
};
|
|
2472
2685
|
}
|
|
@@ -2544,6 +2757,7 @@ var init_environment = __esm({
|
|
|
2544
2757
|
init_module_graph();
|
|
2545
2758
|
init_hot_channel();
|
|
2546
2759
|
init_debug();
|
|
2760
|
+
init_plugin_api();
|
|
2547
2761
|
debug2 = createDebugger("nasti:environment");
|
|
2548
2762
|
NastiEnvironment = class {
|
|
2549
2763
|
name;
|
|
@@ -2552,6 +2766,7 @@ var init_environment = __esm({
|
|
|
2552
2766
|
config;
|
|
2553
2767
|
options;
|
|
2554
2768
|
hot;
|
|
2769
|
+
driver;
|
|
2555
2770
|
/** applyToEnvironment 过滤后的插件(init() 后可用) */
|
|
2556
2771
|
plugins = [];
|
|
2557
2772
|
/** per-env 插件容器(init() 后可用;dev 管线使用) */
|
|
@@ -2559,6 +2774,8 @@ var init_environment = __esm({
|
|
|
2559
2774
|
/** per-env 模块图(dev 管线使用) */
|
|
2560
2775
|
moduleGraph;
|
|
2561
2776
|
candidatePlugins;
|
|
2777
|
+
pluginApi;
|
|
2778
|
+
buildMetadata = {};
|
|
2562
2779
|
initialized = false;
|
|
2563
2780
|
constructor(name, config, init = {}) {
|
|
2564
2781
|
const options = config.environments[name];
|
|
@@ -2575,6 +2792,7 @@ var init_environment = __esm({
|
|
|
2575
2792
|
this.hot = init.hot ?? createNoopHotChannel();
|
|
2576
2793
|
this.moduleGraph = new ModuleGraph();
|
|
2577
2794
|
this.candidatePlugins = init.plugins ?? config.plugins;
|
|
2795
|
+
this.pluginApi = init.pluginApi ?? getPluginApi(config);
|
|
2578
2796
|
}
|
|
2579
2797
|
/** 过滤插件并建 per-env PluginContainer */
|
|
2580
2798
|
async init() {
|
|
@@ -2585,10 +2803,57 @@ var init_environment = __esm({
|
|
|
2585
2803
|
{ ...this.config, plugins: this.plugins },
|
|
2586
2804
|
this
|
|
2587
2805
|
);
|
|
2806
|
+
if (this.options.driver) {
|
|
2807
|
+
const claimed = [];
|
|
2808
|
+
for (const plugin of this.plugins) {
|
|
2809
|
+
const driver = await plugin.createEnvironmentDriver?.(this, this.pluginApi);
|
|
2810
|
+
if (driver) claimed.push({ plugin, driver });
|
|
2811
|
+
}
|
|
2812
|
+
if (claimed.length === 0) {
|
|
2813
|
+
throw new Error(
|
|
2814
|
+
`[nasti] environment "${this.name}" requested driver "${this.options.driver}", but no plugin provided it`
|
|
2815
|
+
);
|
|
2816
|
+
}
|
|
2817
|
+
if (claimed.length > 1) {
|
|
2818
|
+
throw new Error(
|
|
2819
|
+
`[nasti] environment "${this.name}" was claimed by multiple drivers: ` + claimed.map(({ plugin, driver }) => `${plugin.name} (${driver.name})`).join(", ")
|
|
2820
|
+
);
|
|
2821
|
+
}
|
|
2822
|
+
this.driver = claimed[0].driver;
|
|
2823
|
+
debug2?.(`env "${this.name}" uses driver "${this.driver.name}"`);
|
|
2824
|
+
}
|
|
2588
2825
|
debug2?.(`env "${this.name}" initialized (${this.plugins.length} plugins)`);
|
|
2589
2826
|
}
|
|
2827
|
+
getDriverContext() {
|
|
2828
|
+
return {
|
|
2829
|
+
environment: this,
|
|
2830
|
+
config: this.config,
|
|
2831
|
+
api: this.pluginApi,
|
|
2832
|
+
logger: this.config.logger
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
setBuildMetadata(metadata) {
|
|
2836
|
+
const { entries: currentEntries, ...currentMetadata } = this.buildMetadata;
|
|
2837
|
+
const { entries, ...nextMetadata } = metadata;
|
|
2838
|
+
this.buildMetadata = {
|
|
2839
|
+
...currentMetadata,
|
|
2840
|
+
...nextMetadata,
|
|
2841
|
+
...currentEntries || entries ? { entries: { ...currentEntries, ...entries } } : {}
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
getBuildMetadata() {
|
|
2845
|
+
const { entries, ...metadata } = this.buildMetadata;
|
|
2846
|
+
return {
|
|
2847
|
+
...metadata,
|
|
2848
|
+
...entries ? { entries: { ...entries } } : {}
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2590
2851
|
async close() {
|
|
2591
|
-
|
|
2852
|
+
try {
|
|
2853
|
+
await this.driver?.close?.(this.getDriverContext());
|
|
2854
|
+
} finally {
|
|
2855
|
+
await this.hot.close?.();
|
|
2856
|
+
}
|
|
2592
2857
|
}
|
|
2593
2858
|
};
|
|
2594
2859
|
}
|
|
@@ -2747,16 +3012,145 @@ var init_reporter = __esm({
|
|
|
2747
3012
|
}
|
|
2748
3013
|
});
|
|
2749
3014
|
|
|
3015
|
+
// src/core/build-app-context.ts
|
|
3016
|
+
import fs6 from "fs";
|
|
3017
|
+
import path9 from "path";
|
|
3018
|
+
function createBuildAppContext(config, results) {
|
|
3019
|
+
const output = [];
|
|
3020
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
3021
|
+
const outDir = path9.resolve(config.root, config.build.outDir);
|
|
3022
|
+
let environmentArtifacts;
|
|
3023
|
+
return {
|
|
3024
|
+
config,
|
|
3025
|
+
results,
|
|
3026
|
+
get output() {
|
|
3027
|
+
return Object.freeze([...output]);
|
|
3028
|
+
},
|
|
3029
|
+
getResult(environmentName) {
|
|
3030
|
+
return results[environmentName];
|
|
3031
|
+
},
|
|
3032
|
+
getArtifact(environmentName, fileName) {
|
|
3033
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3034
|
+
return results[environmentName]?.output.find(
|
|
3035
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalized
|
|
3036
|
+
);
|
|
3037
|
+
},
|
|
3038
|
+
getEntry(environmentName, entryName) {
|
|
3039
|
+
const result = results[environmentName];
|
|
3040
|
+
const fileName = result?.entries?.[entryName];
|
|
3041
|
+
if (!fileName) return void 0;
|
|
3042
|
+
return result.output.find(
|
|
3043
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalizeEnvironmentFileName(fileName)
|
|
3044
|
+
);
|
|
3045
|
+
},
|
|
3046
|
+
getManifest(environmentName) {
|
|
3047
|
+
return results[environmentName]?.manifest;
|
|
3048
|
+
},
|
|
3049
|
+
emitFile(file) {
|
|
3050
|
+
const fileName = normalizeAppFileName(file.fileName);
|
|
3051
|
+
const collisionKey = artifactCollisionKey(fileName);
|
|
3052
|
+
if (emitted.has(collisionKey)) {
|
|
3053
|
+
throw new Error(`[nasti] app artifact already emitted: ${fileName}`);
|
|
3054
|
+
}
|
|
3055
|
+
environmentArtifacts ??= collectEnvironmentArtifacts(config, results, outDir);
|
|
3056
|
+
if (environmentArtifacts.has(collisionKey)) {
|
|
3057
|
+
throw new Error(`[nasti] app artifact conflicts with environment output: ${fileName}`);
|
|
3058
|
+
}
|
|
3059
|
+
const target = path9.resolve(outDir, ...fileName.split("/"));
|
|
3060
|
+
const relative = path9.relative(outDir, target);
|
|
3061
|
+
if (relative.startsWith("..") || path9.isAbsolute(relative)) {
|
|
3062
|
+
throw new Error(`[nasti] app artifact must stay inside build.outDir: ${file.fileName}`);
|
|
3063
|
+
}
|
|
3064
|
+
assertNoSymlinkComponents(outDir, fileName);
|
|
3065
|
+
fs6.mkdirSync(path9.dirname(target), { recursive: true });
|
|
3066
|
+
fs6.writeFileSync(target, file.source);
|
|
3067
|
+
const artifact = {
|
|
3068
|
+
...file,
|
|
3069
|
+
fileName,
|
|
3070
|
+
type: "asset"
|
|
3071
|
+
};
|
|
3072
|
+
emitted.add(collisionKey);
|
|
3073
|
+
output.push(artifact);
|
|
3074
|
+
return fileName;
|
|
3075
|
+
}
|
|
3076
|
+
};
|
|
3077
|
+
}
|
|
3078
|
+
function normalizeEnvironmentFileName(fileName) {
|
|
3079
|
+
return path9.posix.normalize(fileName.replace(/\\/g, "/").replace(/^\.\//, ""));
|
|
3080
|
+
}
|
|
3081
|
+
function isInvalidEnvironmentFileName(fileName) {
|
|
3082
|
+
return !fileName || fileName === "." || fileName === ".." || fileName.startsWith("../") || path9.posix.isAbsolute(fileName) || /^[A-Za-z]:\//.test(fileName);
|
|
3083
|
+
}
|
|
3084
|
+
function normalizeAppFileName(fileName) {
|
|
3085
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3086
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
3087
|
+
throw new Error(`[nasti] invalid app artifact fileName: ${fileName}`);
|
|
3088
|
+
}
|
|
3089
|
+
return normalized;
|
|
3090
|
+
}
|
|
3091
|
+
function artifactCollisionKey(fileName) {
|
|
3092
|
+
return normalizeEnvironmentFileName(fileName).toLowerCase();
|
|
3093
|
+
}
|
|
3094
|
+
function collectEnvironmentArtifacts(config, results, appOutDir) {
|
|
3095
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
3096
|
+
for (const [environmentName, result] of Object.entries(results)) {
|
|
3097
|
+
const environment = config.environments[environmentName];
|
|
3098
|
+
if (!environment) continue;
|
|
3099
|
+
const environmentOutDir = path9.resolve(config.root, environment.build.outDir);
|
|
3100
|
+
for (const artifact of result.output) {
|
|
3101
|
+
const artifactPath = path9.resolve(
|
|
3102
|
+
environmentOutDir,
|
|
3103
|
+
...normalizeEnvironmentFileName(artifact.fileName).split("/")
|
|
3104
|
+
);
|
|
3105
|
+
const relative = path9.relative(appOutDir, artifactPath);
|
|
3106
|
+
if (!relative.startsWith("..") && !path9.isAbsolute(relative)) {
|
|
3107
|
+
occupied.add(artifactCollisionKey(relative));
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
return occupied;
|
|
3112
|
+
}
|
|
3113
|
+
function assertNoSymlinkComponents(outDir, fileName) {
|
|
3114
|
+
let current = outDir;
|
|
3115
|
+
for (const segment of fileName.split("/")) {
|
|
3116
|
+
current = path9.join(current, segment);
|
|
3117
|
+
let stats;
|
|
3118
|
+
try {
|
|
3119
|
+
stats = fs6.lstatSync(current);
|
|
3120
|
+
} catch (error) {
|
|
3121
|
+
if (error.code === "ENOENT") continue;
|
|
3122
|
+
throw error;
|
|
3123
|
+
}
|
|
3124
|
+
if (stats.isSymbolicLink()) {
|
|
3125
|
+
throw new Error(`[nasti] app artifact path cannot traverse a symlink: ${fileName}`);
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
}
|
|
3129
|
+
function inferEnvironmentEntries(output) {
|
|
3130
|
+
const entries = {};
|
|
3131
|
+
for (const artifact of output) {
|
|
3132
|
+
if (artifact.type !== "chunk" || !artifact.isEntry || !artifact.name) continue;
|
|
3133
|
+
entries[artifact.name] = normalizeEnvironmentFileName(artifact.fileName);
|
|
3134
|
+
}
|
|
3135
|
+
return Object.keys(entries).length > 0 ? entries : void 0;
|
|
3136
|
+
}
|
|
3137
|
+
var init_build_app_context = __esm({
|
|
3138
|
+
"src/core/build-app-context.ts"() {
|
|
3139
|
+
"use strict";
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
|
|
2750
3143
|
// src/build/index.ts
|
|
2751
3144
|
var build_exports = {};
|
|
2752
3145
|
__export(build_exports, {
|
|
2753
3146
|
build: () => build,
|
|
2754
3147
|
getRolldownOptions: () => getRolldownOptions,
|
|
3148
|
+
replaceEntryScript: () => replaceEntryScript,
|
|
2755
3149
|
resolveClientEntries: () => resolveClientEntries,
|
|
2756
3150
|
toRolldownPlugins: () => toRolldownPlugins
|
|
2757
3151
|
});
|
|
2758
|
-
import
|
|
2759
|
-
import
|
|
3152
|
+
import path10 from "path";
|
|
3153
|
+
import fs7 from "fs";
|
|
2760
3154
|
import { builtinModules } from "module";
|
|
2761
3155
|
import { rolldown } from "rolldown";
|
|
2762
3156
|
import pc4 from "picocolors";
|
|
@@ -2764,9 +3158,14 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2764
3158
|
const config = environment.config;
|
|
2765
3159
|
const envOptions = environment.options;
|
|
2766
3160
|
const isServer = environment.consumer === "server";
|
|
2767
|
-
const outDir =
|
|
3161
|
+
const outDir = path10.resolve(config.root, envOptions.build.outDir);
|
|
2768
3162
|
const assetsDir = envOptions.build.assetsDir;
|
|
2769
|
-
const {
|
|
3163
|
+
const {
|
|
3164
|
+
output: userOutput,
|
|
3165
|
+
transform: userTransform,
|
|
3166
|
+
resolve: userResolve,
|
|
3167
|
+
...restInputOptions
|
|
3168
|
+
} = envOptions.build.rolldownOptions;
|
|
2770
3169
|
const vueDefine = config.framework === "vue" ? {
|
|
2771
3170
|
__VUE_OPTIONS_API__: "true",
|
|
2772
3171
|
__VUE_PROD_DEVTOOLS__: "false",
|
|
@@ -2780,19 +3179,22 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2780
3179
|
input: entryPoints,
|
|
2781
3180
|
transform: { ...userTransform, define: mergedDefine },
|
|
2782
3181
|
plugins: rolldownPlugins,
|
|
3182
|
+
// client/server consumer 都必须使用当前环境的 conditions/mainFields;Lynx
|
|
3183
|
+
// BG/MT 通常同为 client consumer,但仍可能声明不同的运行时条件。
|
|
3184
|
+
resolve: {
|
|
3185
|
+
...userResolve ?? {},
|
|
3186
|
+
// Environment API 是条件解析的唯一高层入口,优先于继承来的底层选项。
|
|
3187
|
+
conditionNames: envOptions.resolve.conditions,
|
|
3188
|
+
mainFields: envOptions.resolve.mainFields
|
|
3189
|
+
},
|
|
2783
3190
|
...isServer ? {
|
|
2784
3191
|
platform: restInputOptions.platform ?? "node",
|
|
2785
|
-
resolve: {
|
|
2786
|
-
conditionNames: envOptions.resolve.conditions,
|
|
2787
|
-
mainFields: envOptions.resolve.mainFields,
|
|
2788
|
-
...restInputOptions.resolve
|
|
2789
|
-
},
|
|
2790
3192
|
// server 产物:node 内建恒外部化;bare specifier 默认外部化
|
|
2791
3193
|
//(同 Vite ssr.external 默认 —— 依赖由 node_modules 运行时解析),
|
|
2792
3194
|
// 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
|
|
2793
3195
|
external: restInputOptions.external ?? ((id) => {
|
|
2794
3196
|
if (NODE_BUILTINS.has(id)) return true;
|
|
2795
|
-
return !id.startsWith(".") && !
|
|
3197
|
+
return !id.startsWith(".") && !path10.isAbsolute(id) && !id.startsWith("\0");
|
|
2796
3198
|
})
|
|
2797
3199
|
} : {}
|
|
2798
3200
|
};
|
|
@@ -2819,37 +3221,139 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2819
3221
|
};
|
|
2820
3222
|
return { inputOptions, outputOptions, outDir };
|
|
2821
3223
|
}
|
|
2822
|
-
function toRolldownPlugins(plugins) {
|
|
3224
|
+
function toRolldownPlugins(plugins, environment) {
|
|
3225
|
+
const wrap = (hook) => {
|
|
3226
|
+
if (!hook) return hook;
|
|
3227
|
+
return function(...args) {
|
|
3228
|
+
return hook.apply(attachEnvironment(this, environment), args);
|
|
3229
|
+
};
|
|
3230
|
+
};
|
|
2823
3231
|
return plugins.map((p) => ({
|
|
2824
3232
|
name: p.name,
|
|
2825
|
-
resolveId: p.resolveId,
|
|
2826
|
-
load: p.load,
|
|
2827
|
-
transform: p.transform,
|
|
2828
|
-
buildStart: p.buildStart,
|
|
2829
|
-
buildEnd: p.buildEnd,
|
|
3233
|
+
resolveId: wrap(p.resolveId),
|
|
3234
|
+
load: wrap(p.load),
|
|
3235
|
+
transform: wrap(p.transform),
|
|
3236
|
+
buildStart: wrap(p.buildStart),
|
|
3237
|
+
buildEnd: wrap(p.buildEnd),
|
|
2830
3238
|
// closeBundle 在 bundle.close() 时触发 —— PWA manifest/SW 等终态产物依赖
|
|
2831
|
-
closeBundle: p.closeBundle,
|
|
2832
|
-
renderChunk: p.renderChunk,
|
|
2833
|
-
augmentChunkHash: p.augmentChunkHash,
|
|
2834
|
-
generateBundle: p.generateBundle
|
|
3239
|
+
closeBundle: wrap(p.closeBundle),
|
|
3240
|
+
renderChunk: wrap(p.renderChunk),
|
|
3241
|
+
augmentChunkHash: wrap(p.augmentChunkHash),
|
|
3242
|
+
generateBundle: wrap(p.generateBundle)
|
|
2835
3243
|
}));
|
|
2836
3244
|
}
|
|
3245
|
+
function attachEnvironment(context, environment) {
|
|
3246
|
+
if (context?.environment === environment) return context;
|
|
3247
|
+
try {
|
|
3248
|
+
Object.defineProperty(context, "environment", {
|
|
3249
|
+
configurable: true,
|
|
3250
|
+
enumerable: false,
|
|
3251
|
+
writable: false,
|
|
3252
|
+
value: environment
|
|
3253
|
+
});
|
|
3254
|
+
return context;
|
|
3255
|
+
} catch {
|
|
3256
|
+
return new Proxy(context, {
|
|
3257
|
+
get(target, property) {
|
|
3258
|
+
if (property === "environment") return environment;
|
|
3259
|
+
const value = Reflect.get(target, property, target);
|
|
3260
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
3261
|
+
},
|
|
3262
|
+
set(target, property, value) {
|
|
3263
|
+
return Reflect.set(target, property, value, target);
|
|
3264
|
+
}
|
|
3265
|
+
});
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
function finalizeEnvironmentResult(environment, result) {
|
|
3269
|
+
const metadata = environment.getBuildMetadata();
|
|
3270
|
+
const inferredEntries = inferEnvironmentEntries(result.output);
|
|
3271
|
+
const entries = {
|
|
3272
|
+
...inferredEntries,
|
|
3273
|
+
...metadata.entries,
|
|
3274
|
+
...result.entries
|
|
3275
|
+
};
|
|
3276
|
+
const normalizedEntries = Object.fromEntries(
|
|
3277
|
+
Object.entries(entries).map(([name, fileName]) => {
|
|
3278
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3279
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
3280
|
+
throw new Error(
|
|
3281
|
+
`[nasti] environment "${environment.name}" returned invalid entry "${name}": ${fileName}`
|
|
3282
|
+
);
|
|
3283
|
+
}
|
|
3284
|
+
return [name, normalized];
|
|
3285
|
+
})
|
|
3286
|
+
);
|
|
3287
|
+
return {
|
|
3288
|
+
...metadata,
|
|
3289
|
+
...result,
|
|
3290
|
+
output: result.output,
|
|
3291
|
+
...Object.keys(normalizedEntries).length > 0 ? { entries: normalizedEntries } : {}
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3294
|
+
function prepareBuildOutputDirectories(config, buildableNames) {
|
|
3295
|
+
const directories = /* @__PURE__ */ new Set();
|
|
3296
|
+
const protectedPaths = /* @__PURE__ */ new Set();
|
|
3297
|
+
const clientIsBuilt = buildableNames.includes("client");
|
|
3298
|
+
if (!clientIsBuilt && config.build.emptyOutDir) {
|
|
3299
|
+
directories.add(path10.resolve(config.root, config.build.outDir));
|
|
3300
|
+
}
|
|
3301
|
+
for (const name of buildableNames) {
|
|
3302
|
+
const environment = config.environments[name];
|
|
3303
|
+
const outDir = path10.resolve(config.root, environment.build.outDir);
|
|
3304
|
+
if (!environment.build.emptyOutDir) {
|
|
3305
|
+
protectedPaths.add(outDir);
|
|
3306
|
+
continue;
|
|
3307
|
+
}
|
|
3308
|
+
if (!environment.driver) directories.add(outDir);
|
|
3309
|
+
}
|
|
3310
|
+
const containsPath = (parent, child) => {
|
|
3311
|
+
const relative = path10.relative(parent, child);
|
|
3312
|
+
return relative === "" || !relative.startsWith("..") && !path10.isAbsolute(relative);
|
|
3313
|
+
};
|
|
3314
|
+
const roots = [...directories].filter(
|
|
3315
|
+
(directory) => ![...protectedPaths].some((protectedPath) => containsPath(directory, protectedPath))
|
|
3316
|
+
).sort((a, b) => a.length - b.length).filter(
|
|
3317
|
+
(directory, index2, all) => !all.slice(0, index2).some((parent) => containsPath(parent, directory))
|
|
3318
|
+
);
|
|
3319
|
+
for (const directory of roots) {
|
|
3320
|
+
if (fs7.existsSync(directory)) fs7.rmSync(directory, { recursive: true, force: true });
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
function assertDriverBuildResult(environment, result) {
|
|
3324
|
+
const output = result != null && typeof result === "object" ? result.output : void 0;
|
|
3325
|
+
const hasValidOutput = Array.isArray(output) && output.every(
|
|
3326
|
+
(artifact) => artifact != null && typeof artifact === "object" && typeof artifact.fileName === "string" && typeof artifact.type === "string"
|
|
3327
|
+
);
|
|
3328
|
+
if (!hasValidOutput) {
|
|
3329
|
+
throw new Error(
|
|
3330
|
+
`[nasti] environment "${environment.name}" driver "${environment.driver?.name}" returned an invalid build result; expected { output: EnvironmentBuildOutput[] }`
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
2837
3334
|
function resolveClientEntries(config, html) {
|
|
3335
|
+
const configuredEntries = config.environments.client?.entry ?? [];
|
|
3336
|
+
if (configuredEntries.length > 0) return configuredEntries;
|
|
2838
3337
|
const entryPoints = [];
|
|
3338
|
+
const htmlFile = config.environments.client?.html;
|
|
3339
|
+
const htmlDir = htmlFile ? path10.dirname(htmlFile) : config.root;
|
|
2839
3340
|
if (html) {
|
|
2840
3341
|
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
2841
3342
|
for (const match of scriptMatches) {
|
|
2842
3343
|
const src = match[1];
|
|
2843
3344
|
if (src && !src.startsWith("http")) {
|
|
2844
|
-
|
|
3345
|
+
const cleanSrc = src.split(/[?#]/, 1)[0];
|
|
3346
|
+
entryPoints.push(
|
|
3347
|
+
cleanSrc.startsWith("/") ? path10.resolve(config.root, cleanSrc.replace(/^\//, "")) : path10.resolve(htmlDir, cleanSrc)
|
|
3348
|
+
);
|
|
2845
3349
|
}
|
|
2846
3350
|
}
|
|
2847
3351
|
}
|
|
2848
3352
|
if (entryPoints.length === 0) {
|
|
2849
3353
|
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
2850
3354
|
for (const entry of fallbackEntries) {
|
|
2851
|
-
const fullPath =
|
|
2852
|
-
if (
|
|
3355
|
+
const fullPath = path10.resolve(config.root, entry);
|
|
3356
|
+
if (fs7.existsSync(fullPath)) {
|
|
2853
3357
|
entryPoints.push(fullPath);
|
|
2854
3358
|
break;
|
|
2855
3359
|
}
|
|
@@ -2877,130 +3381,229 @@ async function build(inlineConfig = {}) {
|
|
|
2877
3381
|
const startTime = performance.now();
|
|
2878
3382
|
logger.info(
|
|
2879
3383
|
pc4.cyan(`
|
|
2880
|
-
nasti v${"2.
|
|
3384
|
+
nasti v${"2.4.0"} `) + pc4.green(`building for ${config.mode}...`)
|
|
2881
3385
|
);
|
|
2882
3386
|
debug4?.(`root: ${config.root}`);
|
|
2883
|
-
const buildableNames = Object.keys(config.environments).filter(
|
|
2884
|
-
|
|
2885
|
-
|
|
3387
|
+
const buildableNames = Object.keys(config.environments).filter((name) => {
|
|
3388
|
+
const environment = config.environments[name];
|
|
3389
|
+
if (!environment.buildEnabled) return false;
|
|
3390
|
+
return name === "client" || environment.entry.length > 0 || !!environment.driver;
|
|
3391
|
+
});
|
|
2886
3392
|
buildableNames.sort((a, b) => a === "client" ? -1 : b === "client" ? 1 : 0);
|
|
3393
|
+
prepareBuildOutputDirectories(config, buildableNames);
|
|
2887
3394
|
const environments = {};
|
|
3395
|
+
const environmentResults = {};
|
|
3396
|
+
const initializedEnvironments = [];
|
|
3397
|
+
const buildAppContext = createBuildAppContext(config, environmentResults);
|
|
2888
3398
|
let clientOutput = [];
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
3399
|
+
let buildFailed = false;
|
|
3400
|
+
try {
|
|
3401
|
+
for (const name of buildableNames) {
|
|
3402
|
+
const built = name === "client" ? await buildClientEnvironment(config) : await buildServerEnvironment(config, name);
|
|
3403
|
+
initializedEnvironments.push(built.environment);
|
|
3404
|
+
environments[name] = built.result.output;
|
|
3405
|
+
environmentResults[name] = built.result;
|
|
3406
|
+
if (name === "client") clientOutput = built.result.output;
|
|
3407
|
+
if (buildableNames.length > 1) {
|
|
3408
|
+
debug4?.(`environment "${name}" built (${built.result.output.length} files)`);
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
const pluginApi = getPluginApi(config);
|
|
3412
|
+
for (const plugin of config.plugins) {
|
|
3413
|
+
await plugin.afterBuildApp?.(environmentResults, pluginApi, buildAppContext);
|
|
3414
|
+
}
|
|
3415
|
+
} catch (error) {
|
|
3416
|
+
buildFailed = true;
|
|
3417
|
+
throw error;
|
|
3418
|
+
} finally {
|
|
3419
|
+
let closeFailed = false;
|
|
3420
|
+
let firstCloseError;
|
|
3421
|
+
for (const environment of [...initializedEnvironments].reverse()) {
|
|
3422
|
+
try {
|
|
3423
|
+
await environment.close();
|
|
3424
|
+
} catch (error) {
|
|
3425
|
+
if (!closeFailed) {
|
|
3426
|
+
closeFailed = true;
|
|
3427
|
+
firstCloseError = error;
|
|
3428
|
+
}
|
|
3429
|
+
const closeError = error instanceof Error ? error : new Error(String(error));
|
|
3430
|
+
logger.error(`[nasti] failed to close environment "${environment.name}"`, {
|
|
3431
|
+
error: closeError
|
|
3432
|
+
});
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
if (closeFailed && !buildFailed) {
|
|
3436
|
+
throw firstCloseError;
|
|
2895
3437
|
}
|
|
2896
3438
|
}
|
|
2897
3439
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
2898
|
-
const
|
|
3440
|
+
const allOutput = [...Object.values(environments).flat(), ...buildAppContext.output];
|
|
3441
|
+
const totalSize = allOutput.reduce((sum, chunk) => {
|
|
2899
3442
|
const content = chunk.type === "chunk" ? chunk.code : chunk.source;
|
|
2900
3443
|
if (content == null) return sum;
|
|
2901
3444
|
return sum + (typeof content === "string" ? Buffer.byteLength(content) : content.byteLength);
|
|
2902
3445
|
}, 0);
|
|
2903
|
-
const fileCount =
|
|
3446
|
+
const fileCount = allOutput.length;
|
|
2904
3447
|
const envSuffix = buildableNames.length > 1 ? ` (${buildableNames.join(" + ")})` : "";
|
|
2905
3448
|
logger.info(pc4.green(`\u2713 built in ${elapsed}s`) + pc4.dim(envSuffix));
|
|
2906
3449
|
logger.info(pc4.dim(` ${fileCount} files, ${displaySize(totalSize)} total \u2192 ${config.build.outDir}/`));
|
|
2907
|
-
return {
|
|
3450
|
+
return {
|
|
3451
|
+
output: clientOutput,
|
|
3452
|
+
environments,
|
|
3453
|
+
environmentResults,
|
|
3454
|
+
appOutput: [...buildAppContext.output]
|
|
3455
|
+
};
|
|
2908
3456
|
}
|
|
2909
3457
|
async function buildClientEnvironment(config) {
|
|
2910
3458
|
const logger = config.logger;
|
|
2911
|
-
const outDir =
|
|
2912
|
-
if (config.build.emptyOutDir && fs6.existsSync(outDir)) {
|
|
2913
|
-
fs6.rmSync(outDir, { recursive: true, force: true });
|
|
2914
|
-
}
|
|
2915
|
-
fs6.mkdirSync(outDir, { recursive: true });
|
|
2916
|
-
const html = await readHtmlFile(config.root);
|
|
2917
|
-
const entryPoints = resolveClientEntries(config, html);
|
|
2918
|
-
if (entryPoints.length === 0) {
|
|
2919
|
-
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
2920
|
-
}
|
|
3459
|
+
const outDir = path10.resolve(config.root, config.build.outDir);
|
|
2921
3460
|
const cssEngine = createCssEngine();
|
|
2922
|
-
const pluginList = resolvePluginList(config, config.plugins, {
|
|
2923
|
-
|
|
3461
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
3462
|
+
cssEngine,
|
|
3463
|
+
environmentName: "client"
|
|
3464
|
+
});
|
|
3465
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
2924
3466
|
mode: "build",
|
|
2925
|
-
plugins: pluginList
|
|
3467
|
+
plugins: pluginList,
|
|
3468
|
+
pluginApi: getPluginApi(config)
|
|
2926
3469
|
});
|
|
2927
3470
|
await clientEnv.init();
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
...nativeReporter ? [nativeReporter] : []
|
|
2934
|
-
];
|
|
2935
|
-
const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
|
|
2936
|
-
const bundle2 = await rolldown(inputOptions);
|
|
2937
|
-
const { output } = await bundle2.write(outputOptions);
|
|
2938
|
-
await bundle2.close();
|
|
2939
|
-
if (html) {
|
|
2940
|
-
let processedHtml = html;
|
|
2941
|
-
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
2942
|
-
for (const p of htmlPlugins) {
|
|
2943
|
-
const result = await p.transformIndexHtml(processedHtml);
|
|
2944
|
-
if (typeof result === "string") {
|
|
2945
|
-
processedHtml = result;
|
|
2946
|
-
} else if (result && "html" in result) {
|
|
2947
|
-
processedHtml = processHtml(result.html, result.tags);
|
|
2948
|
-
} else if (Array.isArray(result)) {
|
|
2949
|
-
processedHtml = processHtml(processedHtml, result);
|
|
2950
|
-
}
|
|
2951
|
-
}
|
|
2952
|
-
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
2953
|
-
for (const chunk of output) {
|
|
2954
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
2955
|
-
const originalEntry = path9.relative(config.root, chunk.facadeModuleId);
|
|
2956
|
-
processedHtml = processedHtml.replace(
|
|
2957
|
-
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
2958
|
-
`$1${config.base}${chunk.fileName}$3`
|
|
3471
|
+
try {
|
|
3472
|
+
if (clientEnv.driver) {
|
|
3473
|
+
if (!clientEnv.driver.build) {
|
|
3474
|
+
throw new Error(
|
|
3475
|
+
`[nasti] environment "client" driver "${clientEnv.driver.name}" does not implement build()`
|
|
2959
3476
|
);
|
|
2960
3477
|
}
|
|
3478
|
+
const result = await clientEnv.driver.build(clientEnv.getDriverContext());
|
|
3479
|
+
assertDriverBuildResult(clientEnv, result);
|
|
3480
|
+
return { environment: clientEnv, result: finalizeEnvironmentResult(clientEnv, result) };
|
|
2961
3481
|
}
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3482
|
+
fs7.mkdirSync(outDir, { recursive: true });
|
|
3483
|
+
const htmlFile = config.environments.client.html ?? path10.resolve(config.root, "index.html");
|
|
3484
|
+
const html = await readHtmlFile(config.root, htmlFile);
|
|
3485
|
+
const entryPoints = resolveClientEntries(config, html);
|
|
3486
|
+
if (entryPoints.length === 0) {
|
|
3487
|
+
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
3488
|
+
}
|
|
3489
|
+
const allPlugins = clientEnv.plugins;
|
|
3490
|
+
const nativeReporter = config.logLevel === "silent" ? null : await tryNativeReporterPlugin(config, logger);
|
|
3491
|
+
const rolldownPlugins = [
|
|
3492
|
+
createOxcTransformPlugin(config, clientEnv),
|
|
3493
|
+
...toRolldownPlugins(allPlugins, clientEnv),
|
|
3494
|
+
...nativeReporter ? [nativeReporter] : []
|
|
3495
|
+
];
|
|
3496
|
+
const { inputOptions, outputOptions } = getRolldownOptions(
|
|
3497
|
+
clientEnv,
|
|
3498
|
+
entryPoints,
|
|
3499
|
+
rolldownPlugins
|
|
3500
|
+
);
|
|
3501
|
+
const bundle2 = await rolldown(inputOptions);
|
|
3502
|
+
const { output } = await bundle2.write(outputOptions);
|
|
3503
|
+
await bundle2.close();
|
|
3504
|
+
if (html) {
|
|
3505
|
+
let processedHtml = html;
|
|
3506
|
+
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
3507
|
+
for (const p of htmlPlugins) {
|
|
3508
|
+
const result = await p.transformIndexHtml(processedHtml);
|
|
3509
|
+
if (typeof result === "string") {
|
|
3510
|
+
processedHtml = result;
|
|
3511
|
+
} else if (result && "html" in result) {
|
|
3512
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
3513
|
+
} else if (Array.isArray(result)) {
|
|
3514
|
+
processedHtml = processHtml(processedHtml, result);
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
3518
|
+
for (const chunk of output) {
|
|
3519
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
3520
|
+
processedHtml = replaceEntryScript(
|
|
3521
|
+
processedHtml,
|
|
3522
|
+
chunk.facadeModuleId,
|
|
3523
|
+
chunk.fileName,
|
|
3524
|
+
config,
|
|
3525
|
+
htmlFile,
|
|
3526
|
+
config.base
|
|
3527
|
+
);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
fs7.writeFileSync(path10.resolve(outDir, "index.html"), processedHtml);
|
|
3531
|
+
}
|
|
3532
|
+
if (!nativeReporter && config.logLevel !== "silent") {
|
|
3533
|
+
reportBuildOutput(output, config, logger);
|
|
3534
|
+
}
|
|
3535
|
+
warnLargeChunks(output, config, logger);
|
|
3536
|
+
return {
|
|
3537
|
+
environment: clientEnv,
|
|
3538
|
+
result: finalizeEnvironmentResult(clientEnv, { output })
|
|
3539
|
+
};
|
|
3540
|
+
} catch (error) {
|
|
3541
|
+
try {
|
|
3542
|
+
await clientEnv.close();
|
|
3543
|
+
} catch (closeError) {
|
|
3544
|
+
const normalized = closeError instanceof Error ? closeError : new Error(String(closeError));
|
|
3545
|
+
logger.error("[nasti] failed to close client environment after build failure", {
|
|
3546
|
+
error: normalized
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
throw error;
|
|
2966
3550
|
}
|
|
2967
|
-
warnLargeChunks(output, config, logger);
|
|
2968
|
-
return output;
|
|
2969
3551
|
}
|
|
2970
3552
|
async function buildServerEnvironment(config, name) {
|
|
2971
3553
|
const envOptions = config.environments[name];
|
|
2972
3554
|
const logger = config.logger;
|
|
3555
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
3556
|
+
consumer: envOptions.consumer,
|
|
3557
|
+
environmentName: name
|
|
3558
|
+
});
|
|
3559
|
+
const environment = new NastiEnvironment(name, config, {
|
|
3560
|
+
mode: "build",
|
|
3561
|
+
plugins: pluginList,
|
|
3562
|
+
pluginApi: getPluginApi(config)
|
|
3563
|
+
});
|
|
3564
|
+
await environment.init();
|
|
3565
|
+
if (environment.driver) {
|
|
3566
|
+
if (!environment.driver.build) {
|
|
3567
|
+
await environment.close();
|
|
3568
|
+
throw new Error(
|
|
3569
|
+
`[nasti] environment "${name}" driver "${environment.driver.name}" does not implement build()`
|
|
3570
|
+
);
|
|
3571
|
+
}
|
|
3572
|
+
try {
|
|
3573
|
+
const result = await environment.driver.build(environment.getDriverContext());
|
|
3574
|
+
assertDriverBuildResult(environment, result);
|
|
3575
|
+
return { environment, result: finalizeEnvironmentResult(environment, result) };
|
|
3576
|
+
} catch (error) {
|
|
3577
|
+
await environment.close();
|
|
3578
|
+
throw error;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
2973
3581
|
for (const entry of envOptions.entry) {
|
|
2974
|
-
if (!
|
|
3582
|
+
if (!fs7.existsSync(entry)) {
|
|
3583
|
+
await environment.close();
|
|
2975
3584
|
throw new Error(`[nasti] environment "${name}" entry not found: ${entry}`);
|
|
2976
3585
|
}
|
|
2977
3586
|
}
|
|
2978
|
-
const pluginList = resolvePluginList(config, config.plugins, { consumer: envOptions.consumer });
|
|
2979
|
-
const environment = new NastiEnvironment(name, { ...config, plugins: pluginList }, {
|
|
2980
|
-
mode: "build",
|
|
2981
|
-
plugins: pluginList
|
|
2982
|
-
});
|
|
2983
|
-
await environment.init();
|
|
2984
3587
|
const rolldownPlugins = [
|
|
2985
3588
|
createOxcTransformPlugin(config, environment),
|
|
2986
|
-
...toRolldownPlugins(environment.plugins)
|
|
3589
|
+
...toRolldownPlugins(environment.plugins, environment)
|
|
2987
3590
|
];
|
|
2988
3591
|
const { inputOptions, outputOptions, outDir } = getRolldownOptions(
|
|
2989
3592
|
environment,
|
|
2990
3593
|
envOptions.entry,
|
|
2991
3594
|
rolldownPlugins
|
|
2992
3595
|
);
|
|
2993
|
-
|
|
2994
|
-
fs6.rmSync(outDir, { recursive: true, force: true });
|
|
2995
|
-
}
|
|
2996
|
-
fs6.mkdirSync(outDir, { recursive: true });
|
|
3596
|
+
fs7.mkdirSync(outDir, { recursive: true });
|
|
2997
3597
|
const bundle2 = await rolldown(inputOptions);
|
|
2998
3598
|
const { output } = await bundle2.write(outputOptions);
|
|
2999
3599
|
await bundle2.close();
|
|
3000
3600
|
logger.info(
|
|
3001
|
-
pc4.dim(` [${name}] `) + output.map((o) =>
|
|
3601
|
+
pc4.dim(` [${name}] `) + output.map((o) => path10.join(envOptions.build.outDir, o.fileName)).join(pc4.dim(", "))
|
|
3002
3602
|
);
|
|
3003
|
-
return
|
|
3603
|
+
return {
|
|
3604
|
+
environment,
|
|
3605
|
+
result: finalizeEnvironmentResult(environment, { output })
|
|
3606
|
+
};
|
|
3004
3607
|
}
|
|
3005
3608
|
function injectCssLinks(html, cssEngine, config) {
|
|
3006
3609
|
const cssLinkTags = [];
|
|
@@ -3026,6 +3629,25 @@ function injectCssLinks(html, cssEngine, config) {
|
|
|
3026
3629
|
function escapeRegExp(string) {
|
|
3027
3630
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3028
3631
|
}
|
|
3632
|
+
function replaceEntryScript(html, facadeModuleId, fileName, config, htmlFile, urlPrefix) {
|
|
3633
|
+
const rootRelative = path10.relative(config.root, facadeModuleId).split(path10.sep).join("/");
|
|
3634
|
+
const resolvedHtmlFile = path10.resolve(config.root, htmlFile);
|
|
3635
|
+
const htmlRelative = path10.relative(path10.dirname(resolvedHtmlFile), facadeModuleId).split(path10.sep).join("/");
|
|
3636
|
+
const candidates = /* @__PURE__ */ new Set([
|
|
3637
|
+
rootRelative,
|
|
3638
|
+
`/${rootRelative}`,
|
|
3639
|
+
htmlRelative,
|
|
3640
|
+
`./${htmlRelative}`
|
|
3641
|
+
]);
|
|
3642
|
+
let processed = html;
|
|
3643
|
+
for (const candidate of candidates) {
|
|
3644
|
+
processed = processed.replace(
|
|
3645
|
+
new RegExp(`(src=["'])${escapeRegExp(candidate)}([?#][^"']*)?(["'])`, "g"),
|
|
3646
|
+
`$1${urlPrefix}${fileName}$3`
|
|
3647
|
+
);
|
|
3648
|
+
}
|
|
3649
|
+
return processed;
|
|
3650
|
+
}
|
|
3029
3651
|
var debug4, NODE_BUILTINS;
|
|
3030
3652
|
var init_build = __esm({
|
|
3031
3653
|
"src/build/index.ts"() {
|
|
@@ -3039,6 +3661,8 @@ var init_build = __esm({
|
|
|
3039
3661
|
init_env();
|
|
3040
3662
|
init_reporter();
|
|
3041
3663
|
init_debug();
|
|
3664
|
+
init_plugin_api();
|
|
3665
|
+
init_build_app_context();
|
|
3042
3666
|
debug4 = createDebugger("nasti:build");
|
|
3043
3667
|
NODE_BUILTINS = /* @__PURE__ */ new Set([...builtinModules, ...builtinModules.map((m) => `node:${m}`)]);
|
|
3044
3668
|
}
|
|
@@ -3096,20 +3720,22 @@ __export(middleware_exports, {
|
|
|
3096
3720
|
transformMiddleware: () => transformMiddleware,
|
|
3097
3721
|
transformRequest: () => transformRequest
|
|
3098
3722
|
});
|
|
3099
|
-
import
|
|
3100
|
-
import
|
|
3723
|
+
import path12 from "path";
|
|
3724
|
+
import fs9 from "fs";
|
|
3101
3725
|
import { createRequire as createRequire3 } from "module";
|
|
3102
3726
|
import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "url";
|
|
3103
3727
|
import pc6 from "picocolors";
|
|
3104
|
-
function getReactRefreshRuntimeEsm() {
|
|
3105
|
-
if (__refreshRuntimeCache)
|
|
3728
|
+
function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
|
|
3729
|
+
if (__refreshRuntimeCache) {
|
|
3730
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
3731
|
+
}
|
|
3106
3732
|
let cjsPath;
|
|
3107
3733
|
try {
|
|
3108
3734
|
const pkgPath = __require2.resolve("react-refresh/package.json");
|
|
3109
|
-
cjsPath =
|
|
3735
|
+
cjsPath = path12.join(path12.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
|
|
3110
3736
|
} catch (err) {
|
|
3111
|
-
cjsPath =
|
|
3112
|
-
if (!
|
|
3737
|
+
cjsPath = path12.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
|
|
3738
|
+
if (!fs9.existsSync(cjsPath)) {
|
|
3113
3739
|
const origMsg = err instanceof Error ? err.message : String(err);
|
|
3114
3740
|
throw new Error(
|
|
3115
3741
|
`[nasti] Missing dependency "react-refresh". Install it with: npm install react-refresh
|
|
@@ -3117,7 +3743,7 @@ Original resolve error: ${origMsg}`
|
|
|
3117
3743
|
);
|
|
3118
3744
|
}
|
|
3119
3745
|
}
|
|
3120
|
-
const cjsSource =
|
|
3746
|
+
const cjsSource = fs9.readFileSync(cjsPath, "utf-8");
|
|
3121
3747
|
__refreshRuntimeCache = `// Wrapped react-refresh runtime -> ESM
|
|
3122
3748
|
const exports = {};
|
|
3123
3749
|
const module = { exports };
|
|
@@ -3137,7 +3763,7 @@ export const findAffectedHostInstances = __rt.findAffectedHostInstances;
|
|
|
3137
3763
|
export const collectCustomHooksForSignature = __rt.collectCustomHooksForSignature;
|
|
3138
3764
|
export default __rt;
|
|
3139
3765
|
`;
|
|
3140
|
-
return __refreshRuntimeCache;
|
|
3766
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
3141
3767
|
}
|
|
3142
3768
|
function buildReactRefreshWrapper(moduleUrl, transformedCode) {
|
|
3143
3769
|
const urlLit = JSON.stringify(moduleUrl);
|
|
@@ -3163,22 +3789,40 @@ window.$RefreshReg$ = prevRefreshReg;
|
|
|
3163
3789
|
window.$RefreshSig$ = prevRefreshSig;
|
|
3164
3790
|
|
|
3165
3791
|
if (__nasti_hot__) {
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3792
|
+
let __nasti_current_exports__;
|
|
3793
|
+
__nasti_hot__.accept((nextExports) => {
|
|
3794
|
+
if (!nextExports) return;
|
|
3795
|
+
if (!__nasti_current_exports__) {
|
|
3796
|
+
__nasti_hot__.invalidate('Could not Fast Refresh (previous exports unavailable)');
|
|
3797
|
+
return;
|
|
3798
|
+
}
|
|
3799
|
+
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(
|
|
3800
|
+
${urlLit},
|
|
3801
|
+
__nasti_current_exports__,
|
|
3802
|
+
nextExports,
|
|
3803
|
+
);
|
|
3804
|
+
if (invalidateMessage) __nasti_hot__.invalidate(invalidateMessage);
|
|
3805
|
+
});
|
|
3806
|
+
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
|
|
3807
|
+
__nasti_current_exports__ = currentExports;
|
|
3808
|
+
RefreshRuntime.registerExportsForReactRefresh(${urlLit}, currentExports);
|
|
3171
3809
|
});
|
|
3172
3810
|
}
|
|
3173
3811
|
`;
|
|
3174
3812
|
}
|
|
3175
3813
|
function injectImportMetaHot(code, moduleUrl) {
|
|
3176
|
-
|
|
3814
|
+
const hotRE = /\bimport\.meta\.hot\b/g;
|
|
3815
|
+
const matches = [...maskStringsAndComments(code).matchAll(hotRE)];
|
|
3816
|
+
if (matches.length === 0) return code;
|
|
3817
|
+
for (const match of matches.reverse()) {
|
|
3818
|
+
const start = match.index;
|
|
3819
|
+
code = code.slice(0, start) + "__nasti_hot__" + code.slice(start + match[0].length);
|
|
3820
|
+
}
|
|
3177
3821
|
const urlLit = JSON.stringify(moduleUrl);
|
|
3178
3822
|
const header = `import { createHotContext as __nasti_createHotContext__ } from "/@nasti/client";
|
|
3179
3823
|
const __nasti_hot__ = __nasti_createHotContext__(${urlLit});
|
|
3180
3824
|
`;
|
|
3181
|
-
return header + code
|
|
3825
|
+
return header + code;
|
|
3182
3826
|
}
|
|
3183
3827
|
function transformMiddleware(ctx) {
|
|
3184
3828
|
ctx.envDefine = buildEnvDefine(
|
|
@@ -3205,7 +3849,10 @@ function transformMiddleware(ctx) {
|
|
|
3205
3849
|
return;
|
|
3206
3850
|
}
|
|
3207
3851
|
if (url === "/" || url.endsWith(".html")) {
|
|
3208
|
-
const html = await readHtmlFile(
|
|
3852
|
+
const html = await readHtmlFile(
|
|
3853
|
+
ctx.config.root,
|
|
3854
|
+
ctx.config.environments.client?.html
|
|
3855
|
+
);
|
|
3209
3856
|
if (html) {
|
|
3210
3857
|
let processedHtml = html;
|
|
3211
3858
|
for (const plugin of ctx.config.plugins) {
|
|
@@ -3251,13 +3898,14 @@ function transformMiddleware(ctx) {
|
|
|
3251
3898
|
}
|
|
3252
3899
|
async function transformRequest(url, ctx) {
|
|
3253
3900
|
const { config, pluginContainer, moduleGraph } = ctx;
|
|
3901
|
+
url = removeTimestampQuery(url);
|
|
3254
3902
|
const cleanReqUrl = url.split("?")[0];
|
|
3255
3903
|
const cached2 = moduleGraph.getModuleByUrl(url);
|
|
3256
3904
|
if (cached2?.transformResult) {
|
|
3257
3905
|
return cached2.transformResult;
|
|
3258
3906
|
}
|
|
3259
3907
|
if (cleanReqUrl === "/@react-refresh") {
|
|
3260
|
-
return { code: getReactRefreshRuntimeEsm() };
|
|
3908
|
+
return { code: getReactRefreshRuntimeEsm(true) };
|
|
3261
3909
|
}
|
|
3262
3910
|
if (cleanReqUrl.startsWith("/@modules/") && url.includes("?")) {
|
|
3263
3911
|
const idParam = new URLSearchParams(url.slice(url.indexOf("?") + 1)).get("id");
|
|
@@ -3265,8 +3913,8 @@ async function transformRequest(url, ctx) {
|
|
|
3265
3913
|
let realIdValid = false;
|
|
3266
3914
|
try {
|
|
3267
3915
|
if (idParam) {
|
|
3268
|
-
realId =
|
|
3269
|
-
realIdValid =
|
|
3916
|
+
realId = fs9.realpathSync(idParam);
|
|
3917
|
+
realIdValid = fs9.statSync(realId).isFile() && (realId.includes(`${path12.sep}node_modules${path12.sep}`) || isUnderRoot(realId, config.root));
|
|
3270
3918
|
}
|
|
3271
3919
|
} catch {
|
|
3272
3920
|
realId = null;
|
|
@@ -3293,6 +3941,8 @@ async function transformRequest(url, ctx) {
|
|
|
3293
3941
|
}
|
|
3294
3942
|
const rawQuery = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
|
|
3295
3943
|
if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
|
|
3944
|
+
const mod2 = await moduleGraph.ensureEntryFromUrl(url);
|
|
3945
|
+
const transformVersion2 = mod2.invalidationVersion;
|
|
3296
3946
|
const loaded = await pluginContainer.load(url);
|
|
3297
3947
|
if (loaded != null) {
|
|
3298
3948
|
let code2 = typeof loaded === "string" ? loaded : loaded.code;
|
|
@@ -3300,30 +3950,43 @@ async function transformRequest(url, ctx) {
|
|
|
3300
3950
|
if (transformed != null) {
|
|
3301
3951
|
code2 = typeof transformed === "string" ? transformed : transformed.code;
|
|
3302
3952
|
}
|
|
3303
|
-
const
|
|
3304
|
-
moduleGraph.registerModule(mod2,
|
|
3305
|
-
|
|
3953
|
+
const parentFile = resolveUrlToFile(cleanReqUrl, config.root) ?? cleanReqUrl;
|
|
3954
|
+
moduleGraph.registerModule(mod2, parentFile);
|
|
3955
|
+
const hotInfo2 = rewriteHotAcceptDeps(code2, config, parentFile);
|
|
3956
|
+
code2 = injectImportMetaHot(hotInfo2.code, url);
|
|
3306
3957
|
code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
|
|
3307
3958
|
loadEnv(config.mode, config.root, config.envPrefix),
|
|
3308
3959
|
config.mode
|
|
3309
3960
|
));
|
|
3310
|
-
|
|
3961
|
+
const importedUrls2 = /* @__PURE__ */ new Set();
|
|
3962
|
+
code2 = rewriteImports(code2, config, parentFile, importedUrls2, moduleGraph);
|
|
3963
|
+
const pruned2 = await moduleGraph.updateModuleInfo(
|
|
3964
|
+
mod2,
|
|
3965
|
+
importedUrls2,
|
|
3966
|
+
hotInfo2.acceptedUrls,
|
|
3967
|
+
hotInfo2.isSelfAccepting,
|
|
3968
|
+
transformVersion2
|
|
3969
|
+
);
|
|
3311
3970
|
const transformResult2 = { code: code2 };
|
|
3312
|
-
|
|
3971
|
+
if (pruned2) {
|
|
3972
|
+
if (pruned2.size > 0) ctx.onPrune?.([...pruned2].map((item) => item.url));
|
|
3973
|
+
mod2.transformResult = transformResult2;
|
|
3974
|
+
}
|
|
3313
3975
|
return transformResult2;
|
|
3314
3976
|
}
|
|
3315
3977
|
}
|
|
3316
3978
|
const filePath = resolveUrlToFile(url, config.root);
|
|
3317
|
-
if (!filePath || !
|
|
3979
|
+
if (!filePath || !fs9.existsSync(filePath)) return null;
|
|
3318
3980
|
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
3319
3981
|
moduleGraph.registerModule(mod, filePath);
|
|
3982
|
+
const transformVersion = mod.invalidationVersion;
|
|
3320
3983
|
if (cleanReqUrl.startsWith("/@modules/")) {
|
|
3321
3984
|
const code2 = await bundlePackageAsEsm(filePath, config.root);
|
|
3322
3985
|
const transformResult2 = { code: code2 };
|
|
3323
3986
|
mod.transformResult = transformResult2;
|
|
3324
3987
|
return transformResult2;
|
|
3325
3988
|
}
|
|
3326
|
-
let code =
|
|
3989
|
+
let code = fs9.readFileSync(filePath, "utf-8");
|
|
3327
3990
|
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
3328
3991
|
if (pluginResult) {
|
|
3329
3992
|
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
@@ -3343,9 +4006,10 @@ async function transformRequest(url, ctx) {
|
|
|
3343
4006
|
if (useRefresh) {
|
|
3344
4007
|
code = buildReactRefreshWrapper(stableUrl, code);
|
|
3345
4008
|
wrappedWithRefresh = true;
|
|
3346
|
-
mod.isSelfAccepting = true;
|
|
3347
4009
|
}
|
|
3348
4010
|
}
|
|
4011
|
+
const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
|
|
4012
|
+
code = hotInfo.code;
|
|
3349
4013
|
if (!wrappedWithRefresh) {
|
|
3350
4014
|
code = injectImportMetaHot(code, stableUrl);
|
|
3351
4015
|
}
|
|
@@ -3354,9 +4018,20 @@ async function transformRequest(url, ctx) {
|
|
|
3354
4018
|
config.mode
|
|
3355
4019
|
);
|
|
3356
4020
|
code = replaceEnvInCode(code, envDefine);
|
|
3357
|
-
|
|
4021
|
+
const importedUrls = /* @__PURE__ */ new Set();
|
|
4022
|
+
code = rewriteImports(code, config, filePath, importedUrls, moduleGraph);
|
|
4023
|
+
const pruned = await moduleGraph.updateModuleInfo(
|
|
4024
|
+
mod,
|
|
4025
|
+
importedUrls,
|
|
4026
|
+
hotInfo.acceptedUrls,
|
|
4027
|
+
wrappedWithRefresh || hotInfo.isSelfAccepting,
|
|
4028
|
+
transformVersion
|
|
4029
|
+
);
|
|
3358
4030
|
const transformResult = { code };
|
|
3359
|
-
|
|
4031
|
+
if (pruned) {
|
|
4032
|
+
if (pruned.size > 0) ctx.onPrune?.([...pruned].map((item) => item.url));
|
|
4033
|
+
mod.transformResult = transformResult;
|
|
4034
|
+
}
|
|
3360
4035
|
return transformResult;
|
|
3361
4036
|
}
|
|
3362
4037
|
async function loadVirtualModule(spec, ctx) {
|
|
@@ -3364,7 +4039,7 @@ async function loadVirtualModule(spec, ctx) {
|
|
|
3364
4039
|
const resolved = await pluginContainer.resolveId(spec);
|
|
3365
4040
|
if (resolved == null) return null;
|
|
3366
4041
|
const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
|
|
3367
|
-
const looksVirtual = resolvedId.startsWith("\0") || !
|
|
4042
|
+
const looksVirtual = resolvedId.startsWith("\0") || !fs9.existsSync(resolvedId);
|
|
3368
4043
|
if (!looksVirtual) return null;
|
|
3369
4044
|
const loadResult = await pluginContainer.load(resolvedId);
|
|
3370
4045
|
if (loadResult == null) return null;
|
|
@@ -3377,7 +4052,7 @@ async function loadVirtualModule(spec, ctx) {
|
|
|
3377
4052
|
loadEnv(config.mode, config.root, config.envPrefix),
|
|
3378
4053
|
config.mode
|
|
3379
4054
|
));
|
|
3380
|
-
const anchor =
|
|
4055
|
+
const anchor = path12.join(config.root, "__nasti_virtual__.ts");
|
|
3381
4056
|
code = rewriteImports(code, config, anchor);
|
|
3382
4057
|
return { id: resolvedId, result: { code } };
|
|
3383
4058
|
}
|
|
@@ -3403,7 +4078,7 @@ async function doBundlePackage(entryFile, root) {
|
|
|
3403
4078
|
await bundle2.close();
|
|
3404
4079
|
let code = result.output[0].code;
|
|
3405
4080
|
code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
|
|
3406
|
-
const externalBaseDir =
|
|
4081
|
+
const externalBaseDir = path12.dirname(entryFile);
|
|
3407
4082
|
code = code.replace(
|
|
3408
4083
|
/^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
3409
4084
|
(_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir, root)}${q}`
|
|
@@ -3421,16 +4096,16 @@ async function doBundlePackage(entryFile, root) {
|
|
|
3421
4096
|
return code;
|
|
3422
4097
|
}
|
|
3423
4098
|
async function tryGenerateSubpathShim(entryFile, root) {
|
|
3424
|
-
const NM = `${
|
|
4099
|
+
const NM = `${path12.sep}node_modules${path12.sep}`;
|
|
3425
4100
|
if (!entryFile.includes(NM)) return null;
|
|
3426
4101
|
let pkgDir = null;
|
|
3427
4102
|
let pkgName = null;
|
|
3428
|
-
let dir =
|
|
4103
|
+
let dir = path12.dirname(entryFile);
|
|
3429
4104
|
while (true) {
|
|
3430
|
-
const pkgJsonPath =
|
|
3431
|
-
if (
|
|
4105
|
+
const pkgJsonPath = path12.join(dir, "package.json");
|
|
4106
|
+
if (fs9.existsSync(pkgJsonPath)) {
|
|
3432
4107
|
try {
|
|
3433
|
-
const pkg = JSON.parse(
|
|
4108
|
+
const pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
|
|
3434
4109
|
if (typeof pkg?.name === "string" && pkg.name) {
|
|
3435
4110
|
pkgDir = dir;
|
|
3436
4111
|
pkgName = pkg.name;
|
|
@@ -3439,16 +4114,16 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3439
4114
|
} catch {
|
|
3440
4115
|
}
|
|
3441
4116
|
}
|
|
3442
|
-
const parent =
|
|
4117
|
+
const parent = path12.dirname(dir);
|
|
3443
4118
|
if (parent === dir) return null;
|
|
3444
4119
|
dir = parent;
|
|
3445
4120
|
if (!dir.includes(NM)) return null;
|
|
3446
4121
|
}
|
|
3447
4122
|
if (!pkgDir || !pkgName) return null;
|
|
3448
|
-
const entryExt =
|
|
4123
|
+
const entryExt = path12.extname(entryFile);
|
|
3449
4124
|
const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
|
|
3450
4125
|
if (!mainEntry) return null;
|
|
3451
|
-
if (
|
|
4126
|
+
if (path12.resolve(mainEntry) === path12.resolve(entryFile)) return null;
|
|
3452
4127
|
let mainNs;
|
|
3453
4128
|
let subNs;
|
|
3454
4129
|
try {
|
|
@@ -3472,7 +4147,7 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3472
4147
|
if (mainNs["default"] !== subNs["default"]) return null;
|
|
3473
4148
|
}
|
|
3474
4149
|
const rootMain = resolveNodeModule(root, pkgName);
|
|
3475
|
-
const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir +
|
|
4150
|
+
const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + path12.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
|
|
3476
4151
|
const lines = [
|
|
3477
4152
|
`// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
|
|
3478
4153
|
`import * as __pkg from "${mainEntryUrl}";`
|
|
@@ -3486,10 +4161,10 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3486
4161
|
return lines.join("\n") + "\n";
|
|
3487
4162
|
}
|
|
3488
4163
|
function pickMainEntryByExtension(pkgDir, preferredExt) {
|
|
3489
|
-
const pkgJsonPath =
|
|
4164
|
+
const pkgJsonPath = path12.join(pkgDir, "package.json");
|
|
3490
4165
|
let pkg;
|
|
3491
4166
|
try {
|
|
3492
|
-
pkg = JSON.parse(
|
|
4167
|
+
pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
|
|
3493
4168
|
} catch {
|
|
3494
4169
|
return null;
|
|
3495
4170
|
}
|
|
@@ -3508,14 +4183,14 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
|
|
|
3508
4183
|
if (typeof pkg.module === "string") candidates.push(pkg.module);
|
|
3509
4184
|
if (typeof pkg.main === "string") candidates.push(pkg.main);
|
|
3510
4185
|
for (const cand of candidates) {
|
|
3511
|
-
if (
|
|
3512
|
-
const full =
|
|
3513
|
-
if (
|
|
4186
|
+
if (path12.extname(cand) === preferredExt) {
|
|
4187
|
+
const full = path12.resolve(pkgDir, cand);
|
|
4188
|
+
if (fs9.existsSync(full)) return full;
|
|
3514
4189
|
}
|
|
3515
4190
|
}
|
|
3516
4191
|
for (const cand of candidates) {
|
|
3517
|
-
const full =
|
|
3518
|
-
if (
|
|
4192
|
+
const full = path12.resolve(pkgDir, cand);
|
|
4193
|
+
if (fs9.existsSync(full)) return full;
|
|
3519
4194
|
}
|
|
3520
4195
|
return null;
|
|
3521
4196
|
}
|
|
@@ -3561,72 +4236,231 @@ async function injectCjsNamedExports(code, entryFile) {
|
|
|
3561
4236
|
return code;
|
|
3562
4237
|
}
|
|
3563
4238
|
}
|
|
3564
|
-
function rewriteImports(code, config, filePath) {
|
|
4239
|
+
function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
|
|
4240
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
4241
|
+
const transformSpec = (spec) => {
|
|
4242
|
+
const resolved = removeTimestampQuery(resolveSpec(spec));
|
|
4243
|
+
importedUrls?.add(resolved);
|
|
4244
|
+
const timestamp = moduleGraph?.getModuleByUrl(resolved)?.lastHMRTimestamp ?? 0;
|
|
4245
|
+
return timestamp > 0 ? appendTimestampQuery(resolved, timestamp) : resolved;
|
|
4246
|
+
};
|
|
4247
|
+
return code.replace(
|
|
4248
|
+
/\bfrom\s+(['"])([^'"]+)\1/g,
|
|
4249
|
+
(_m, q, s) => `from ${q}${transformSpec(s)}${q}`
|
|
4250
|
+
).replace(
|
|
4251
|
+
/\bimport\s+(['"])([^'"]+)\1/g,
|
|
4252
|
+
(_m, q, s) => `import ${q}${transformSpec(s)}${q}`
|
|
4253
|
+
).replace(
|
|
4254
|
+
/\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g,
|
|
4255
|
+
(_m, q, s) => `import(${q}${transformSpec(s)}${q})`
|
|
4256
|
+
);
|
|
4257
|
+
}
|
|
4258
|
+
function createModuleSpecifierResolver(config, filePath) {
|
|
3565
4259
|
const root = config.root;
|
|
3566
|
-
const fileDir =
|
|
4260
|
+
const fileDir = path12.dirname(filePath);
|
|
3567
4261
|
const aliasEntries = Object.entries(config.resolve.alias).sort(
|
|
3568
4262
|
([a], [b]) => b.length - a.length
|
|
3569
4263
|
);
|
|
3570
|
-
const toRootUrl = (abs) => "/" +
|
|
3571
|
-
|
|
3572
|
-
const suffixMatch =
|
|
4264
|
+
const toRootUrl = (abs) => "/" + path12.relative(root, abs).replace(/\\/g, "/");
|
|
4265
|
+
return (specifier) => {
|
|
4266
|
+
const suffixMatch = specifier.match(/[?#].*$/);
|
|
3573
4267
|
const suffix = suffixMatch ? suffixMatch[0] : "";
|
|
3574
|
-
const baseSpec = suffix ?
|
|
4268
|
+
const baseSpec = suffix ? specifier.slice(0, -suffix.length) : specifier;
|
|
3575
4269
|
for (const [key, value] of aliasEntries) {
|
|
3576
4270
|
if (baseSpec === key || baseSpec.startsWith(key + "/")) {
|
|
3577
4271
|
const aliasBase = resolveAliasTarget2(value, root);
|
|
3578
4272
|
const sub = baseSpec.slice(key.length).replace(/^\//, "");
|
|
3579
|
-
const target = sub ?
|
|
4273
|
+
const target = sub ? path12.join(aliasBase, sub) : aliasBase;
|
|
3580
4274
|
const resolved = tryResolveDiskPath(target);
|
|
3581
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix :
|
|
4275
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
3582
4276
|
}
|
|
3583
4277
|
}
|
|
3584
4278
|
if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3587
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
|
|
4279
|
+
const resolved = tryResolveDiskPath(path12.resolve(fileDir, baseSpec));
|
|
4280
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
3588
4281
|
}
|
|
3589
4282
|
if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
|
|
3590
|
-
const
|
|
3591
|
-
|
|
3592
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
|
|
4283
|
+
const resolved = tryResolveDiskPath(path12.join(root, baseSpec.replace(/^\//, "")));
|
|
4284
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
3593
4285
|
}
|
|
3594
|
-
if (baseSpec.startsWith("/")) return
|
|
3595
|
-
return `/@modules/${
|
|
4286
|
+
if (baseSpec.startsWith("/")) return specifier;
|
|
4287
|
+
return `/@modules/${specifier}`;
|
|
3596
4288
|
};
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
)
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
)
|
|
4289
|
+
}
|
|
4290
|
+
function rewriteHotAcceptDeps(code, config, filePath) {
|
|
4291
|
+
const acceptedUrls = /* @__PURE__ */ new Set();
|
|
4292
|
+
const edits = [];
|
|
4293
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
4294
|
+
const acceptRE = /(?:\bimport\.meta\.hot|\b__nasti_hot__)(?:(?:\?\.)|\.)accept\s*\(/g;
|
|
4295
|
+
const searchableCode = maskStringsAndComments(code);
|
|
4296
|
+
let isSelfAccepting = false;
|
|
4297
|
+
let match;
|
|
4298
|
+
while (match = acceptRE.exec(searchableCode)) {
|
|
4299
|
+
let cursor = match.index + match[0].length;
|
|
4300
|
+
const skipTrivia = () => {
|
|
4301
|
+
while (cursor < code.length) {
|
|
4302
|
+
if (/\s/.test(code[cursor])) {
|
|
4303
|
+
cursor++;
|
|
4304
|
+
continue;
|
|
4305
|
+
}
|
|
4306
|
+
if (code[cursor] === "/" && code[cursor + 1] === "/") {
|
|
4307
|
+
cursor += 2;
|
|
4308
|
+
while (cursor < code.length && code[cursor] !== "\n") cursor++;
|
|
4309
|
+
continue;
|
|
4310
|
+
}
|
|
4311
|
+
if (code[cursor] === "/" && code[cursor + 1] === "*") {
|
|
4312
|
+
cursor += 2;
|
|
4313
|
+
while (cursor < code.length && !(code[cursor] === "*" && code[cursor + 1] === "/")) cursor++;
|
|
4314
|
+
cursor += 2;
|
|
4315
|
+
continue;
|
|
4316
|
+
}
|
|
4317
|
+
break;
|
|
4318
|
+
}
|
|
4319
|
+
};
|
|
4320
|
+
skipTrivia();
|
|
4321
|
+
const first = code[cursor];
|
|
4322
|
+
if (!first || first === ")" || first !== "[" && first !== "'" && first !== '"' && first !== "`") {
|
|
4323
|
+
isSelfAccepting = true;
|
|
4324
|
+
continue;
|
|
4325
|
+
}
|
|
4326
|
+
const readLiteral = () => {
|
|
4327
|
+
const quote = code[cursor];
|
|
4328
|
+
if (quote !== "'" && quote !== '"' && quote !== "`") return;
|
|
4329
|
+
const start = cursor;
|
|
4330
|
+
cursor++;
|
|
4331
|
+
let raw = "";
|
|
4332
|
+
while (cursor < code.length) {
|
|
4333
|
+
const char = code[cursor];
|
|
4334
|
+
if (char === "\\") {
|
|
4335
|
+
raw += code[cursor + 1] ?? "";
|
|
4336
|
+
cursor += 2;
|
|
4337
|
+
continue;
|
|
4338
|
+
}
|
|
4339
|
+
if (char === quote) {
|
|
4340
|
+
cursor++;
|
|
4341
|
+
const resolved = removeTimestampQuery(resolveSpec(raw));
|
|
4342
|
+
acceptedUrls.add(resolved);
|
|
4343
|
+
edits.push({ start, end: cursor, value: JSON.stringify(resolved) });
|
|
4344
|
+
return;
|
|
4345
|
+
}
|
|
4346
|
+
if (quote === "`" && char === "$" && code[cursor + 1] === "{") return;
|
|
4347
|
+
raw += char;
|
|
4348
|
+
cursor++;
|
|
4349
|
+
}
|
|
4350
|
+
};
|
|
4351
|
+
if (first === "[") {
|
|
4352
|
+
cursor++;
|
|
4353
|
+
while (cursor < code.length) {
|
|
4354
|
+
skipTrivia();
|
|
4355
|
+
if (code[cursor] === ",") {
|
|
4356
|
+
cursor++;
|
|
4357
|
+
skipTrivia();
|
|
4358
|
+
}
|
|
4359
|
+
if (code[cursor] === "]") break;
|
|
4360
|
+
const before = cursor;
|
|
4361
|
+
readLiteral();
|
|
4362
|
+
if (cursor === before) break;
|
|
4363
|
+
}
|
|
4364
|
+
} else {
|
|
4365
|
+
readLiteral();
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
4369
|
+
code = code.slice(0, edit.start) + edit.value + code.slice(edit.end);
|
|
4370
|
+
}
|
|
4371
|
+
return { code, acceptedUrls, isSelfAccepting };
|
|
4372
|
+
}
|
|
4373
|
+
function maskStringsAndComments(code) {
|
|
4374
|
+
const masked = code.split("");
|
|
4375
|
+
let state = "code";
|
|
4376
|
+
const isRegexStart = (index2) => {
|
|
4377
|
+
let previous = index2 - 1;
|
|
4378
|
+
while (previous >= 0 && /\s/.test(code[previous])) previous--;
|
|
4379
|
+
return previous < 0 || "=(:,!&|?{};[]+-*%^~<>".includes(code[previous]);
|
|
4380
|
+
};
|
|
4381
|
+
for (let i = 0; i < code.length; i++) {
|
|
4382
|
+
const char = code[i];
|
|
4383
|
+
const next = code[i + 1];
|
|
4384
|
+
if (state === "code") {
|
|
4385
|
+
if (char === "'") state = "single";
|
|
4386
|
+
else if (char === '"') state = "double";
|
|
4387
|
+
else if (char === "`") state = "template";
|
|
4388
|
+
else if (char === "/" && next === "/") state = "line-comment";
|
|
4389
|
+
else if (char === "/" && next === "*") state = "block-comment";
|
|
4390
|
+
else if (char === "/" && isRegexStart(i)) state = "regex";
|
|
4391
|
+
else continue;
|
|
4392
|
+
masked[i] = " ";
|
|
4393
|
+
continue;
|
|
4394
|
+
}
|
|
4395
|
+
if (state === "line-comment") {
|
|
4396
|
+
if (char === "\n") {
|
|
4397
|
+
state = "code";
|
|
4398
|
+
} else {
|
|
4399
|
+
masked[i] = " ";
|
|
4400
|
+
}
|
|
4401
|
+
continue;
|
|
4402
|
+
}
|
|
4403
|
+
if (state === "block-comment") {
|
|
4404
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4405
|
+
if (char === "*" && next === "/") {
|
|
4406
|
+
masked[i + 1] = " ";
|
|
4407
|
+
i++;
|
|
4408
|
+
state = "code";
|
|
4409
|
+
}
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
if (state === "regex" || state === "regex-class") {
|
|
4413
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4414
|
+
if (char === "\\") {
|
|
4415
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
4416
|
+
} else if (state === "regex" && char === "[") {
|
|
4417
|
+
state = "regex-class";
|
|
4418
|
+
} else if (state === "regex-class" && char === "]") {
|
|
4419
|
+
state = "regex";
|
|
4420
|
+
} else if (state === "regex" && char === "/") {
|
|
4421
|
+
state = "code";
|
|
4422
|
+
}
|
|
4423
|
+
continue;
|
|
4424
|
+
}
|
|
4425
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4426
|
+
if (char === "\\") {
|
|
4427
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
4428
|
+
continue;
|
|
4429
|
+
}
|
|
4430
|
+
if (state === "single" && char === "'" || state === "double" && char === '"' || state === "template" && char === "`") {
|
|
4431
|
+
state = "code";
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
return masked.join("");
|
|
3607
4435
|
}
|
|
3608
4436
|
function resolveAliasTarget2(value, root) {
|
|
3609
|
-
if (
|
|
3610
|
-
if (value.startsWith("/")) return
|
|
3611
|
-
return
|
|
4437
|
+
if (path12.isAbsolute(value) && fs9.existsSync(value)) return value;
|
|
4438
|
+
if (value.startsWith("/")) return path12.join(root, value.slice(1));
|
|
4439
|
+
return path12.resolve(root, value);
|
|
3612
4440
|
}
|
|
3613
4441
|
function tryResolveDiskPath(target) {
|
|
3614
|
-
if (
|
|
4442
|
+
if (fs9.existsSync(target) && fs9.statSync(target).isFile()) return target;
|
|
3615
4443
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3616
4444
|
const withExt = target + ext;
|
|
3617
|
-
if (
|
|
4445
|
+
if (fs9.existsSync(withExt) && fs9.statSync(withExt).isFile()) return withExt;
|
|
3618
4446
|
}
|
|
3619
|
-
if (
|
|
4447
|
+
if (fs9.existsSync(target) && fs9.statSync(target).isDirectory()) {
|
|
3620
4448
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3621
|
-
const idx =
|
|
3622
|
-
if (
|
|
4449
|
+
const idx = path12.join(target, "index" + ext);
|
|
4450
|
+
if (fs9.existsSync(idx) && fs9.statSync(idx).isFile()) return idx;
|
|
3623
4451
|
}
|
|
3624
4452
|
}
|
|
3625
4453
|
return null;
|
|
3626
4454
|
}
|
|
3627
4455
|
function isUnderRoot(abs, root) {
|
|
3628
|
-
const rel =
|
|
3629
|
-
return !!rel && !rel.startsWith("..") && !
|
|
4456
|
+
const rel = path12.relative(root, abs);
|
|
4457
|
+
return !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
|
|
4458
|
+
}
|
|
4459
|
+
function appendTimestampQuery(url, timestamp) {
|
|
4460
|
+
const hashIndex = url.indexOf("#");
|
|
4461
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
4462
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
4463
|
+
return `${withoutHash}${withoutHash.includes("?") ? "&" : "?"}t=${timestamp}${hash}`;
|
|
3630
4464
|
}
|
|
3631
4465
|
function externalSpecToModuleUrl(spec, baseDir, root) {
|
|
3632
4466
|
const resolved = resolveNodeModule(baseDir, spec);
|
|
@@ -3639,7 +4473,7 @@ function resolveNodeModule(baseDir, moduleName) {
|
|
|
3639
4473
|
const resolved = resolveNodeModuleEntry(baseDir, moduleName);
|
|
3640
4474
|
if (!resolved) return null;
|
|
3641
4475
|
try {
|
|
3642
|
-
return
|
|
4476
|
+
return fs9.realpathSync(resolved);
|
|
3643
4477
|
} catch {
|
|
3644
4478
|
return resolved;
|
|
3645
4479
|
}
|
|
@@ -3659,21 +4493,21 @@ function resolveNodeModuleEntry(root, moduleName) {
|
|
|
3659
4493
|
let pkgDir = null;
|
|
3660
4494
|
let dir = root;
|
|
3661
4495
|
for (; ; ) {
|
|
3662
|
-
const candidate =
|
|
3663
|
-
if (
|
|
4496
|
+
const candidate = path12.join(dir, "node_modules", pkgName);
|
|
4497
|
+
if (fs9.existsSync(candidate)) {
|
|
3664
4498
|
pkgDir = candidate;
|
|
3665
4499
|
break;
|
|
3666
4500
|
}
|
|
3667
|
-
const parent =
|
|
4501
|
+
const parent = path12.dirname(dir);
|
|
3668
4502
|
if (parent === dir) break;
|
|
3669
4503
|
dir = parent;
|
|
3670
4504
|
}
|
|
3671
4505
|
if (!pkgDir) return null;
|
|
3672
|
-
const pkgJsonPath =
|
|
3673
|
-
if (!
|
|
4506
|
+
const pkgJsonPath = path12.join(pkgDir, "package.json");
|
|
4507
|
+
if (!fs9.existsSync(pkgJsonPath)) return null;
|
|
3674
4508
|
let pkg;
|
|
3675
4509
|
try {
|
|
3676
|
-
pkg = JSON.parse(
|
|
4510
|
+
pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
|
|
3677
4511
|
} catch {
|
|
3678
4512
|
return null;
|
|
3679
4513
|
}
|
|
@@ -3686,32 +4520,32 @@ function resolveNodeModuleEntry(root, moduleName) {
|
|
|
3686
4520
|
const subDirs = [""];
|
|
3687
4521
|
for (const field of ["module", "main"]) {
|
|
3688
4522
|
if (typeof pkg[field] === "string") {
|
|
3689
|
-
const dir2 =
|
|
4523
|
+
const dir2 = path12.dirname(pkg[field]);
|
|
3690
4524
|
if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
|
|
3691
4525
|
}
|
|
3692
4526
|
}
|
|
3693
4527
|
for (const dir2 of subDirs) {
|
|
3694
|
-
const direct =
|
|
3695
|
-
if (
|
|
4528
|
+
const direct = path12.join(pkgDir, dir2, subpath);
|
|
4529
|
+
if (fs9.existsSync(direct) && fs9.statSync(direct).isFile()) return direct;
|
|
3696
4530
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3697
|
-
if (
|
|
4531
|
+
if (fs9.existsSync(direct + ext)) return direct + ext;
|
|
3698
4532
|
}
|
|
3699
4533
|
}
|
|
3700
4534
|
return null;
|
|
3701
4535
|
}
|
|
3702
4536
|
for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
|
|
3703
4537
|
if (typeof pkg[field] === "string") {
|
|
3704
|
-
const entry =
|
|
3705
|
-
if (
|
|
4538
|
+
const entry = path12.join(pkgDir, pkg[field]);
|
|
4539
|
+
if (fs9.existsSync(entry)) return entry;
|
|
3706
4540
|
}
|
|
3707
4541
|
}
|
|
3708
|
-
const indexFallback =
|
|
3709
|
-
if (
|
|
4542
|
+
const indexFallback = path12.join(pkgDir, "index.js");
|
|
4543
|
+
if (fs9.existsSync(indexFallback)) return indexFallback;
|
|
3710
4544
|
return null;
|
|
3711
4545
|
}
|
|
3712
4546
|
function resolvePackageExports(exports, key, pkgDir) {
|
|
3713
4547
|
if (typeof exports === "string") {
|
|
3714
|
-
return key === "." ?
|
|
4548
|
+
return key === "." ? path12.join(pkgDir, exports) : null;
|
|
3715
4549
|
}
|
|
3716
4550
|
const entry = exports[key];
|
|
3717
4551
|
if (entry === void 0) {
|
|
@@ -3723,7 +4557,7 @@ function resolvePackageExports(exports, key, pkgDir) {
|
|
|
3723
4557
|
return resolveExportValue(entry, pkgDir);
|
|
3724
4558
|
}
|
|
3725
4559
|
function resolveExportValue(value, pkgDir) {
|
|
3726
|
-
if (typeof value === "string") return
|
|
4560
|
+
if (typeof value === "string") return path12.join(pkgDir, value);
|
|
3727
4561
|
if (Array.isArray(value)) {
|
|
3728
4562
|
for (const item of value) {
|
|
3729
4563
|
const r = resolveExportValue(item, pkgDir);
|
|
@@ -3747,17 +4581,17 @@ function resolveUrlToFile(url, root) {
|
|
|
3747
4581
|
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
3748
4582
|
return resolveNodeModule(root, moduleName);
|
|
3749
4583
|
}
|
|
3750
|
-
const filePath =
|
|
3751
|
-
if (
|
|
4584
|
+
const filePath = path12.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
4585
|
+
if (fs9.existsSync(filePath) && fs9.statSync(filePath).isFile()) {
|
|
3752
4586
|
return filePath;
|
|
3753
4587
|
}
|
|
3754
4588
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3755
4589
|
const withExt = filePath + ext;
|
|
3756
|
-
if (
|
|
4590
|
+
if (fs9.existsSync(withExt)) return withExt;
|
|
3757
4591
|
}
|
|
3758
4592
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3759
|
-
const indexFile =
|
|
3760
|
-
if (
|
|
4593
|
+
const indexFile = path12.join(filePath, "index" + ext);
|
|
4594
|
+
if (fs9.existsSync(indexFile)) return indexFile;
|
|
3761
4595
|
}
|
|
3762
4596
|
return null;
|
|
3763
4597
|
}
|
|
@@ -3765,36 +4599,35 @@ function isModuleRequest(url) {
|
|
|
3765
4599
|
const cleanUrl = url.split("?")[0];
|
|
3766
4600
|
if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
|
|
3767
4601
|
if (cleanUrl.startsWith("/@modules/")) return true;
|
|
3768
|
-
if (!
|
|
4602
|
+
if (!path12.extname(cleanUrl)) return true;
|
|
3769
4603
|
return false;
|
|
3770
4604
|
}
|
|
3771
4605
|
function getHmrClientCode() {
|
|
3772
4606
|
return `
|
|
3773
4607
|
// Nasti HMR Client
|
|
3774
|
-
const
|
|
4608
|
+
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
|
4609
|
+
const socket = new WebSocket(socketProtocol + '://' + location.host, 'nasti-hmr');
|
|
3775
4610
|
const hotModulesMap = new Map();
|
|
3776
4611
|
const disposeMap = new Map();
|
|
3777
4612
|
const pruneMap = new Map();
|
|
4613
|
+
const dataMap = new Map();
|
|
4614
|
+
let updateQueue = [];
|
|
4615
|
+
let pendingUpdateQueue = false;
|
|
3778
4616
|
|
|
3779
4617
|
socket.addEventListener('message', async ({ data }) => {
|
|
3780
4618
|
const payload = JSON.parse(data);
|
|
3781
4619
|
switch (payload.type) {
|
|
3782
4620
|
case 'connected':
|
|
3783
|
-
console.
|
|
4621
|
+
console.debug('[nasti] connected.');
|
|
3784
4622
|
clearErrorOverlay();
|
|
3785
4623
|
break;
|
|
3786
4624
|
case 'update':
|
|
3787
4625
|
try {
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
} else if (update.type === 'css-update') {
|
|
3792
|
-
return updateCss(update.path);
|
|
3793
|
-
}
|
|
3794
|
-
}));
|
|
4626
|
+
// CSS \u5728 unbundled \u6A21\u5F0F\u4E0B\u4E5F\u662F\u4F1A\u6CE8\u5165 <style> \u7684 JS \u6A21\u5757\uFF0C\u548C\u666E\u901A JS
|
|
4627
|
+
// \u4E00\u6837\u91CD\u65B0 import \u624D\u80FD\u6267\u884C dispose/accept \u5E76\u4FDD\u6301\u9875\u9762\u72B6\u6001\u3002
|
|
4628
|
+
await Promise.all(payload.updates.map(queueUpdate));
|
|
3795
4629
|
clearErrorOverlay();
|
|
3796
|
-
console.
|
|
3797
|
-
location.reload();
|
|
4630
|
+
console.debug('[nasti] HMR update complete.');
|
|
3798
4631
|
} catch (err) {
|
|
3799
4632
|
console.error('[nasti] HMR update failed:', err);
|
|
3800
4633
|
showErrorOverlay(err);
|
|
@@ -3805,10 +4638,17 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
3805
4638
|
location.reload();
|
|
3806
4639
|
break;
|
|
3807
4640
|
case 'prune':
|
|
3808
|
-
payload.paths.
|
|
3809
|
-
const
|
|
3810
|
-
|
|
3811
|
-
|
|
4641
|
+
await Promise.all(payload.paths.map(async (path) => {
|
|
4642
|
+
const data = dataMap.get(path);
|
|
4643
|
+
const dispose = disposeMap.get(path);
|
|
4644
|
+
const prune = pruneMap.get(path);
|
|
4645
|
+
if (dispose) await dispose(data);
|
|
4646
|
+
if (prune) await prune(data);
|
|
4647
|
+
hotModulesMap.delete(path);
|
|
4648
|
+
disposeMap.delete(path);
|
|
4649
|
+
pruneMap.delete(path);
|
|
4650
|
+
dataMap.delete(path);
|
|
4651
|
+
}));
|
|
3812
4652
|
break;
|
|
3813
4653
|
case 'error':
|
|
3814
4654
|
console.error('[nasti] error:', payload.err.message);
|
|
@@ -3817,33 +4657,64 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
3817
4657
|
}
|
|
3818
4658
|
});
|
|
3819
4659
|
|
|
3820
|
-
// \
|
|
4660
|
+
// \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
|
|
3821
4661
|
let reconnectTimer = 0;
|
|
3822
4662
|
socket.addEventListener('close', () => {
|
|
3823
4663
|
clearTimeout(reconnectTimer);
|
|
3824
4664
|
reconnectTimer = setTimeout(() => location.reload(), 1000);
|
|
3825
4665
|
});
|
|
3826
4666
|
|
|
4667
|
+
/**
|
|
4668
|
+
* \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
|
|
4669
|
+
* \u6539\u53D8\u6A21\u5757\u5E94\u7528\u987A\u5E8F\u3002\u8FD9\u4E0E Vite HMRClient \u7684 fetch/apply \u4E24\u9636\u6BB5\u4E00\u81F4\u3002
|
|
4670
|
+
*/
|
|
4671
|
+
async function queueUpdate(update) {
|
|
4672
|
+
updateQueue.push(fetchUpdate(update));
|
|
4673
|
+
if (pendingUpdateQueue) return;
|
|
4674
|
+
|
|
4675
|
+
pendingUpdateQueue = true;
|
|
4676
|
+
await Promise.resolve();
|
|
4677
|
+
pendingUpdateQueue = false;
|
|
4678
|
+
const loading = updateQueue;
|
|
4679
|
+
updateQueue = [];
|
|
4680
|
+
const applyUpdates = await Promise.all(loading);
|
|
4681
|
+
for (const apply of applyUpdates) {
|
|
4682
|
+
if (apply) apply();
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
|
|
3827
4686
|
async function fetchUpdate(update) {
|
|
3828
4687
|
const mod = hotModulesMap.get(update.path);
|
|
3829
|
-
// \
|
|
3830
|
-
|
|
3831
|
-
if (dispose) dispose();
|
|
4688
|
+
// \u5C1A\u672A\u5728\u5F53\u524D\u9875\u9762\u52A0\u8F7D\u7684\u52A8\u6001\u6A21\u5757\u4E0D\u9700\u8981\u66F4\u65B0\u3002
|
|
4689
|
+
if (!mod) return;
|
|
3832
4690
|
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
4691
|
+
// \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
|
|
4692
|
+
const qualifiedCallbacks = mod.callbacks.filter(({ deps }) =>
|
|
4693
|
+
deps.includes(update.acceptedPath)
|
|
4694
|
+
);
|
|
4695
|
+
const isSelfUpdate = update.path === update.acceptedPath;
|
|
4696
|
+
if (!isSelfUpdate && qualifiedCallbacks.length === 0) return;
|
|
4697
|
+
|
|
4698
|
+
const dispose = disposeMap.get(update.acceptedPath);
|
|
4699
|
+
if (dispose) await dispose(dataMap.get(update.acceptedPath));
|
|
4700
|
+
const newMod = await import(appendTimestampQuery(update.acceptedPath, update.timestamp));
|
|
4701
|
+
|
|
4702
|
+
return () => {
|
|
4703
|
+
for (const { deps, fn } of qualifiedCallbacks) {
|
|
4704
|
+
fn(deps.map((dep) => dep === update.acceptedPath ? newMod : undefined));
|
|
4705
|
+
}
|
|
4706
|
+
const detail = isSelfUpdate
|
|
4707
|
+
? update.path
|
|
4708
|
+
: update.acceptedPath + ' via ' + update.path;
|
|
4709
|
+
console.debug('[nasti] hot updated:', detail);
|
|
4710
|
+
};
|
|
3838
4711
|
}
|
|
3839
4712
|
|
|
3840
|
-
function
|
|
3841
|
-
const
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
.then(css => { el.textContent = css; });
|
|
3846
|
-
}
|
|
4713
|
+
function appendTimestampQuery(url, timestamp) {
|
|
4714
|
+
const hashIndex = url.indexOf('#');
|
|
4715
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : '';
|
|
4716
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
4717
|
+
return withoutHash + (withoutHash.includes('?') ? '&' : '?') + 't=' + timestamp + hash;
|
|
3847
4718
|
}
|
|
3848
4719
|
|
|
3849
4720
|
function clearErrorOverlay() {
|
|
@@ -3871,23 +4742,30 @@ function showErrorOverlay(err) {
|
|
|
3871
4742
|
document.body.appendChild(overlay);
|
|
3872
4743
|
}
|
|
3873
4744
|
|
|
3874
|
-
/**
|
|
3875
|
-
* \u751F\u6210 import.meta.hot \u7684 hot context\u3002
|
|
3876
|
-
* \u5173\u952E\u7EA6\u675F\uFF1A\u540C\u4E00 ownerPath \u7684 accept \u56DE\u8C03\u5FC5\u987B\u66FF\u6362\uFF08\u4E0D\u662F append\uFF09\u3002
|
|
3877
|
-
* \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
|
|
3878
|
-
* \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
|
|
3879
|
-
*/
|
|
3880
4745
|
export function createHotContext(ownerPath) {
|
|
4746
|
+
if (!dataMap.has(ownerPath)) dataMap.set(ownerPath, {});
|
|
4747
|
+
|
|
4748
|
+
// \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
|
|
4749
|
+
const existing = hotModulesMap.get(ownerPath);
|
|
4750
|
+
if (existing) existing.callbacks = [];
|
|
4751
|
+
|
|
4752
|
+
const acceptDeps = (deps, callback = () => {}) => {
|
|
4753
|
+
const mod = hotModulesMap.get(ownerPath) || { id: ownerPath, callbacks: [] };
|
|
4754
|
+
mod.callbacks.push({ deps, fn: callback });
|
|
4755
|
+
hotModulesMap.set(ownerPath, mod);
|
|
4756
|
+
};
|
|
4757
|
+
|
|
3881
4758
|
return {
|
|
3882
4759
|
accept(deps, callback) {
|
|
3883
|
-
// \u81EA\u63A5\u53D7: hot.accept() \u6216 hot.accept(callback)
|
|
3884
4760
|
if (typeof deps === 'function' || deps === undefined) {
|
|
3885
|
-
|
|
3886
|
-
|
|
4761
|
+
acceptDeps([ownerPath], ([mod]) => deps?.(mod));
|
|
4762
|
+
} else if (typeof deps === 'string') {
|
|
4763
|
+
acceptDeps([deps], ([mod]) => callback?.(mod));
|
|
4764
|
+
} else if (Array.isArray(deps)) {
|
|
4765
|
+
acceptDeps(deps, callback);
|
|
4766
|
+
} else {
|
|
4767
|
+
throw new Error('invalid hot.accept() usage');
|
|
3887
4768
|
}
|
|
3888
|
-
// \u4F9D\u8D56\u63A5\u53D7: hot.accept(deps, callback)\uFF0C\u591A\u6B21\u8C03\u7528\u8FFD\u52A0
|
|
3889
|
-
const existing = hotModulesMap.get(ownerPath)?.callbacks ?? [];
|
|
3890
|
-
hotModulesMap.set(ownerPath, { callbacks: [...existing, callback] });
|
|
3891
4769
|
},
|
|
3892
4770
|
prune(callback) {
|
|
3893
4771
|
pruneMap.set(ownerPath, callback);
|
|
@@ -3898,21 +4776,85 @@ export function createHotContext(ownerPath) {
|
|
|
3898
4776
|
invalidate() {
|
|
3899
4777
|
location.reload();
|
|
3900
4778
|
},
|
|
3901
|
-
data:
|
|
4779
|
+
data: dataMap.get(ownerPath),
|
|
3902
4780
|
};
|
|
3903
4781
|
}
|
|
3904
4782
|
`;
|
|
3905
4783
|
}
|
|
3906
|
-
var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
4784
|
+
var __dirname_esm, __require2, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
3907
4785
|
var init_middleware = __esm({
|
|
3908
4786
|
"src/server/middleware.ts"() {
|
|
3909
4787
|
"use strict";
|
|
3910
4788
|
init_transformer();
|
|
3911
4789
|
init_html();
|
|
3912
4790
|
init_env();
|
|
3913
|
-
|
|
4791
|
+
init_url();
|
|
4792
|
+
__dirname_esm = path12.dirname(fileURLToPath(import.meta.url));
|
|
3914
4793
|
__require2 = createRequire3(import.meta.url);
|
|
3915
4794
|
__refreshRuntimeCache = null;
|
|
4795
|
+
REACT_REFRESH_BOUNDARY_HELPERS = `
|
|
4796
|
+
function __nastiIsPlainObject(obj) {
|
|
4797
|
+
return Object.prototype.toString.call(obj) === '[object Object]' &&
|
|
4798
|
+
(obj.constructor === Object || obj.constructor === undefined);
|
|
4799
|
+
}
|
|
4800
|
+
function __nastiIsCompoundComponent(type) {
|
|
4801
|
+
if (!__nastiIsPlainObject(type)) return false;
|
|
4802
|
+
for (const key in type) {
|
|
4803
|
+
if (!isLikelyComponentType(type[key])) return false;
|
|
4804
|
+
}
|
|
4805
|
+
return true;
|
|
4806
|
+
}
|
|
4807
|
+
export function registerExportsForReactRefresh(filename, moduleExports) {
|
|
4808
|
+
for (const key in moduleExports) {
|
|
4809
|
+
if (key === '__esModule') continue;
|
|
4810
|
+
const value = moduleExports[key];
|
|
4811
|
+
if (isLikelyComponentType(value)) {
|
|
4812
|
+
register(value, filename + ' export ' + key);
|
|
4813
|
+
} else if (__nastiIsCompoundComponent(value)) {
|
|
4814
|
+
for (const subKey in value) {
|
|
4815
|
+
register(value[subKey], filename + ' export ' + key + '-' + subKey);
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
let __nastiRefreshTimer;
|
|
4821
|
+
function __nastiEnqueueRefresh() {
|
|
4822
|
+
clearTimeout(__nastiRefreshTimer);
|
|
4823
|
+
__nastiRefreshTimer = setTimeout(() => performReactRefresh(), 16);
|
|
4824
|
+
}
|
|
4825
|
+
function __nastiCheckExports(ignored, exports, predicate) {
|
|
4826
|
+
for (const key in exports) {
|
|
4827
|
+
if (ignored.includes(key)) continue;
|
|
4828
|
+
if (!predicate(key, exports[key])) return key;
|
|
4829
|
+
}
|
|
4830
|
+
return true;
|
|
4831
|
+
}
|
|
4832
|
+
export function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
|
|
4833
|
+
const ignored = window.__getReactRefreshIgnoredExports?.({ id }) ?? [];
|
|
4834
|
+
if (__nastiCheckExports(ignored, prevExports, (key) => key in nextExports) !== true) {
|
|
4835
|
+
return 'Could not Fast Refresh (export removed)';
|
|
4836
|
+
}
|
|
4837
|
+
if (__nastiCheckExports(ignored, nextExports, (key) => key in prevExports) !== true) {
|
|
4838
|
+
return 'Could not Fast Refresh (new export)';
|
|
4839
|
+
}
|
|
4840
|
+
let hasExports = false;
|
|
4841
|
+
const compatible = __nastiCheckExports(ignored, nextExports, (key, value) => {
|
|
4842
|
+
hasExports = true;
|
|
4843
|
+
return isLikelyComponentType(value) ||
|
|
4844
|
+
__nastiIsCompoundComponent(value) ||
|
|
4845
|
+
prevExports[key] === value;
|
|
4846
|
+
});
|
|
4847
|
+
if (!hasExports) {
|
|
4848
|
+
return 'Could not Fast Refresh (no exports)';
|
|
4849
|
+
}
|
|
4850
|
+
if (compatible === true) {
|
|
4851
|
+
__nastiEnqueueRefresh();
|
|
4852
|
+
return;
|
|
4853
|
+
}
|
|
4854
|
+
return 'Could not Fast Refresh ("' + compatible + '" export is incompatible)';
|
|
4855
|
+
}
|
|
4856
|
+
export const __hmr_import = (module) => import(module);
|
|
4857
|
+
`;
|
|
3916
4858
|
REACT_REFRESH_GLOBAL_PREAMBLE = `
|
|
3917
4859
|
import RefreshRuntime from "/@react-refresh";
|
|
3918
4860
|
RefreshRuntime.injectIntoGlobalHook(window);
|
|
@@ -3928,27 +4870,29 @@ window.__vite_plugin_react_preamble_installed__ = true;
|
|
|
3928
4870
|
});
|
|
3929
4871
|
|
|
3930
4872
|
// src/server/hmr.ts
|
|
3931
|
-
import
|
|
3932
|
-
import
|
|
4873
|
+
import path13 from "path";
|
|
4874
|
+
import fs10 from "fs";
|
|
3933
4875
|
import pc7 from "picocolors";
|
|
3934
4876
|
async function handleFileChange(file, server) {
|
|
3935
4877
|
const { moduleGraph, ws, config } = server;
|
|
3936
4878
|
const logger = config.logger;
|
|
3937
|
-
const relativePath = "/" +
|
|
3938
|
-
const shortFile =
|
|
4879
|
+
const relativePath = "/" + path13.relative(config.root, file);
|
|
4880
|
+
const shortFile = path13.relative(config.root, file);
|
|
3939
4881
|
const mods = moduleGraph.getModulesByFile(file);
|
|
3940
4882
|
if (!mods || mods.size === 0) {
|
|
3941
4883
|
return;
|
|
3942
4884
|
}
|
|
3943
4885
|
const updates = [];
|
|
3944
4886
|
const timestamp = Date.now();
|
|
4887
|
+
const graph = moduleGraph;
|
|
4888
|
+
const invalidatedModules = /* @__PURE__ */ new Set();
|
|
3945
4889
|
for (const mod of mods) {
|
|
3946
|
-
|
|
4890
|
+
graph.invalidateModuleAndImporters(mod, timestamp, invalidatedModules);
|
|
3947
4891
|
const ctx = {
|
|
3948
4892
|
file,
|
|
3949
4893
|
timestamp,
|
|
3950
4894
|
modules: [mod],
|
|
3951
|
-
read: () =>
|
|
4895
|
+
read: () => fs10.readFileSync(file, "utf-8"),
|
|
3952
4896
|
server
|
|
3953
4897
|
};
|
|
3954
4898
|
let affectedModules = [mod];
|
|
@@ -3961,19 +4905,25 @@ async function handleFileChange(file, server) {
|
|
|
3961
4905
|
}
|
|
3962
4906
|
}
|
|
3963
4907
|
for (const affected of affectedModules) {
|
|
3964
|
-
|
|
4908
|
+
graph.invalidateModuleAndImporters(affected, timestamp, invalidatedModules);
|
|
4909
|
+
const boundaries = graph.getHmrBoundaries(affected);
|
|
3965
4910
|
if (boundaries.length === 0) {
|
|
3966
4911
|
logger.info(pc7.green("page reload ") + pc7.dim(shortFile), { timestamp: true });
|
|
3967
4912
|
ws.send({ type: "full-reload", path: relativePath });
|
|
3968
4913
|
return;
|
|
3969
4914
|
}
|
|
3970
|
-
for (const { boundary } of boundaries) {
|
|
3971
|
-
|
|
4915
|
+
for (const { boundary, acceptedVia } of boundaries) {
|
|
4916
|
+
const update = {
|
|
3972
4917
|
type: boundary.type === "css" ? "css-update" : "js-update",
|
|
3973
4918
|
path: boundary.url,
|
|
3974
|
-
acceptedPath:
|
|
4919
|
+
acceptedPath: acceptedVia.url,
|
|
3975
4920
|
timestamp
|
|
3976
|
-
}
|
|
4921
|
+
};
|
|
4922
|
+
if (!updates.some(
|
|
4923
|
+
(existing) => existing.type === update.type && existing.path === update.path && existing.acceptedPath === update.acceptedPath
|
|
4924
|
+
)) {
|
|
4925
|
+
updates.push(update);
|
|
4926
|
+
}
|
|
3977
4927
|
}
|
|
3978
4928
|
}
|
|
3979
4929
|
}
|
|
@@ -3997,8 +4947,8 @@ __export(runnable_environment_exports, {
|
|
|
3997
4947
|
NastiModuleRunner: () => NastiModuleRunner,
|
|
3998
4948
|
createModuleRunner: () => createModuleRunner
|
|
3999
4949
|
});
|
|
4000
|
-
import
|
|
4001
|
-
import
|
|
4950
|
+
import path14 from "path";
|
|
4951
|
+
import fs11 from "fs";
|
|
4002
4952
|
import { builtinModules as builtinModules3, createRequire as createRequire4 } from "module";
|
|
4003
4953
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
4004
4954
|
function createModuleRunner(environment) {
|
|
@@ -4032,7 +4982,7 @@ var init_runnable_environment = __esm({
|
|
|
4032
4982
|
this.config.mode,
|
|
4033
4983
|
ssrDefineOverrides(environment.consumer)
|
|
4034
4984
|
);
|
|
4035
|
-
this.require = createRequire4(
|
|
4985
|
+
this.require = createRequire4(path14.join(this.config.root, "package.json"));
|
|
4036
4986
|
const handlers = {
|
|
4037
4987
|
fetchModule: async (id, importer) => this.fetchModule(id, importer),
|
|
4038
4988
|
getBuiltins: () => [/^node:/, ...builtinModules3]
|
|
@@ -4056,9 +5006,9 @@ var init_runnable_environment = __esm({
|
|
|
4056
5006
|
this.cache.clear();
|
|
4057
5007
|
}
|
|
4058
5008
|
resolveToId(rawUrl) {
|
|
4059
|
-
if (
|
|
5009
|
+
if (path14.isAbsolute(rawUrl) && fs11.existsSync(rawUrl.split("?")[0])) return rawUrl;
|
|
4060
5010
|
const clean = rawUrl.replace(/^\//, "");
|
|
4061
|
-
return
|
|
5011
|
+
return path14.resolve(this.config.root, clean);
|
|
4062
5012
|
}
|
|
4063
5013
|
/**
|
|
4064
5014
|
* fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
|
|
@@ -4067,14 +5017,14 @@ var init_runnable_environment = __esm({
|
|
|
4067
5017
|
*/
|
|
4068
5018
|
async fetchModule(id, importer) {
|
|
4069
5019
|
if (NODE_BUILTINS3.has(id)) return { externalize: id };
|
|
4070
|
-
if (!id.startsWith(".") && !
|
|
5020
|
+
if (!id.startsWith(".") && !path14.isAbsolute(id) && !id.startsWith("\0")) {
|
|
4071
5021
|
return { externalize: id };
|
|
4072
5022
|
}
|
|
4073
5023
|
const container = this.environment.pluginContainer;
|
|
4074
5024
|
let resolvedId = id;
|
|
4075
5025
|
if (id.startsWith(".") && importer) {
|
|
4076
5026
|
const resolved = await container.resolveId(id, importer);
|
|
4077
|
-
resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id :
|
|
5027
|
+
resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : path14.resolve(path14.dirname(importer.split("?")[0]), id);
|
|
4078
5028
|
}
|
|
4079
5029
|
resolvedId = this.completeExtension(resolvedId);
|
|
4080
5030
|
const cleanId = resolvedId.split("?")[0];
|
|
@@ -4082,8 +5032,8 @@ var init_runnable_environment = __esm({
|
|
|
4082
5032
|
const loaded = await container.load(resolvedId);
|
|
4083
5033
|
if (loaded != null) {
|
|
4084
5034
|
code = typeof loaded === "string" ? loaded : loaded.code;
|
|
4085
|
-
} else if (
|
|
4086
|
-
code =
|
|
5035
|
+
} else if (fs11.existsSync(cleanId)) {
|
|
5036
|
+
code = fs11.readFileSync(cleanId, "utf-8");
|
|
4087
5037
|
} else {
|
|
4088
5038
|
throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
|
|
4089
5039
|
}
|
|
@@ -4116,19 +5066,19 @@ var init_runnable_environment = __esm({
|
|
|
4116
5066
|
completeExtension(id) {
|
|
4117
5067
|
const clean = id.split("?")[0];
|
|
4118
5068
|
const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
|
|
4119
|
-
if (
|
|
5069
|
+
if (fs11.existsSync(clean) && fs11.statSync(clean).isFile()) return id;
|
|
4120
5070
|
const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
|
|
4121
5071
|
if (jsMatch) {
|
|
4122
5072
|
for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
|
|
4123
|
-
if (
|
|
5073
|
+
if (fs11.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
|
|
4124
5074
|
}
|
|
4125
5075
|
}
|
|
4126
5076
|
for (const ext of this.config.resolve.extensions) {
|
|
4127
|
-
if (
|
|
5077
|
+
if (fs11.existsSync(clean + ext)) return clean + ext + query;
|
|
4128
5078
|
}
|
|
4129
5079
|
for (const ext of this.config.resolve.extensions) {
|
|
4130
|
-
const indexPath =
|
|
4131
|
-
if (
|
|
5080
|
+
const indexPath = path14.join(clean, `index${ext}`);
|
|
5081
|
+
if (fs11.existsSync(indexPath)) return indexPath;
|
|
4132
5082
|
}
|
|
4133
5083
|
return id;
|
|
4134
5084
|
}
|
|
@@ -4155,10 +5105,10 @@ var init_runnable_environment = __esm({
|
|
|
4155
5105
|
return;
|
|
4156
5106
|
}
|
|
4157
5107
|
const ssrImport = async (dep) => {
|
|
4158
|
-
if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !
|
|
5108
|
+
if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !path14.isAbsolute(dep) && !dep.startsWith("\0")) {
|
|
4159
5109
|
return this.importExternal(dep);
|
|
4160
5110
|
}
|
|
4161
|
-
const depId = dep.startsWith(".") ? this.completeExtension(
|
|
5111
|
+
const depId = dep.startsWith(".") ? this.completeExtension(path14.resolve(path14.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
|
|
4162
5112
|
return this.instantiate(depId);
|
|
4163
5113
|
};
|
|
4164
5114
|
const ssrExportAll = (sourceModule) => {
|
|
@@ -4190,7 +5140,7 @@ var init_runnable_environment = __esm({
|
|
|
4190
5140
|
}
|
|
4191
5141
|
async importExternal(spec) {
|
|
4192
5142
|
try {
|
|
4193
|
-
return await (spec.startsWith("node:") || !
|
|
5143
|
+
return await (spec.startsWith("node:") || !path14.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import(pathToFileURL4(spec).href));
|
|
4194
5144
|
} catch (err) {
|
|
4195
5145
|
throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
|
|
4196
5146
|
}
|
|
@@ -4216,7 +5166,7 @@ var dev_engine_exports = {};
|
|
|
4216
5166
|
__export(dev_engine_exports, {
|
|
4217
5167
|
createBundledDevServer: () => createBundledDevServer
|
|
4218
5168
|
});
|
|
4219
|
-
import
|
|
5169
|
+
import path15 from "path";
|
|
4220
5170
|
import crypto3 from "crypto";
|
|
4221
5171
|
import { WebSocketServer as WsServer2 } from "ws";
|
|
4222
5172
|
import pc8 from "picocolors";
|
|
@@ -4237,7 +5187,7 @@ async function createBundledDevServer(opts) {
|
|
|
4237
5187
|
`[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.`
|
|
4238
5188
|
);
|
|
4239
5189
|
}
|
|
4240
|
-
const html = await readHtmlFile(config.root);
|
|
5190
|
+
const html = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4241
5191
|
const entryPoints = resolveClientEntries(config, html);
|
|
4242
5192
|
if (entryPoints.length === 0) {
|
|
4243
5193
|
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
@@ -4252,7 +5202,7 @@ async function createBundledDevServer(opts) {
|
|
|
4252
5202
|
createReactRefreshRuntimePlugin(entryPoints),
|
|
4253
5203
|
createBundledOxcRefreshPlugin()
|
|
4254
5204
|
] : [],
|
|
4255
|
-
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins)),
|
|
5205
|
+
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
|
|
4256
5206
|
...useReactRefresh ? [
|
|
4257
5207
|
refreshWrapperFn({
|
|
4258
5208
|
cwd: config.root,
|
|
@@ -4301,7 +5251,7 @@ async function createBundledDevServer(opts) {
|
|
|
4301
5251
|
}
|
|
4302
5252
|
const url = `/${patchPath}`;
|
|
4303
5253
|
logger.info(
|
|
4304
|
-
pc8.green("hmr update ") + pc8.dim(changedFiles.map((f) =>
|
|
5254
|
+
pc8.green("hmr update ") + pc8.dim(changedFiles.map((f) => path15.relative(config.root, f)).join(", ")),
|
|
4305
5255
|
{ timestamp: true }
|
|
4306
5256
|
);
|
|
4307
5257
|
sendTo(clientId, { type: "hmr:update", path: url, url });
|
|
@@ -4437,13 +5387,13 @@ async function createBundledDevServer(opts) {
|
|
|
4437
5387
|
return;
|
|
4438
5388
|
}
|
|
4439
5389
|
res.setHeader("ETag", hit.etag);
|
|
4440
|
-
res.setHeader("Content-Type", MIME_TYPES[
|
|
5390
|
+
res.setHeader("Content-Type", MIME_TYPES[path15.extname(fileName)] ?? "application/octet-stream");
|
|
4441
5391
|
res.setHeader("Cache-Control", "no-cache");
|
|
4442
5392
|
res.end(hit.content);
|
|
4443
5393
|
return;
|
|
4444
5394
|
}
|
|
4445
5395
|
if (pathname === "/" || pathname.endsWith(".html")) {
|
|
4446
|
-
const rawHtml = await readHtmlFile(config.root);
|
|
5396
|
+
const rawHtml = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4447
5397
|
if (rawHtml) {
|
|
4448
5398
|
res.setHeader("Content-Type", "text/html");
|
|
4449
5399
|
res.setHeader("Cache-Control", "no-store");
|
|
@@ -4473,7 +5423,7 @@ function stripCatchAllLoad(plugins) {
|
|
|
4473
5423
|
);
|
|
4474
5424
|
}
|
|
4475
5425
|
function createReactRefreshRuntimePlugin(entryPoints) {
|
|
4476
|
-
const entryIds = new Set(entryPoints.map((p) =>
|
|
5426
|
+
const entryIds = new Set(entryPoints.map((p) => path15.resolve(p)));
|
|
4477
5427
|
return {
|
|
4478
5428
|
name: "nasti:bundled-react-refresh",
|
|
4479
5429
|
resolveId(source) {
|
|
@@ -4491,7 +5441,7 @@ function createReactRefreshRuntimePlugin(entryPoints) {
|
|
|
4491
5441
|
return null;
|
|
4492
5442
|
},
|
|
4493
5443
|
transform(code, id) {
|
|
4494
|
-
if (!entryIds.has(
|
|
5444
|
+
if (!entryIds.has(path15.resolve(id.split("?")[0]))) return null;
|
|
4495
5445
|
return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
|
|
4496
5446
|
${code}`, map: null };
|
|
4497
5447
|
}
|
|
@@ -4527,10 +5477,13 @@ async function renderBundledIndexHtml(html, config, entryFileNames) {
|
|
|
4527
5477
|
}
|
|
4528
5478
|
}
|
|
4529
5479
|
for (const [facadeModuleId, fileName] of entryFileNames) {
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
5480
|
+
processed = replaceEntryScript(
|
|
5481
|
+
processed,
|
|
5482
|
+
facadeModuleId,
|
|
5483
|
+
fileName,
|
|
5484
|
+
config,
|
|
5485
|
+
config.environments.client?.html ?? "index.html",
|
|
5486
|
+
"/"
|
|
4534
5487
|
);
|
|
4535
5488
|
}
|
|
4536
5489
|
return processed;
|
|
@@ -4659,7 +5612,7 @@ __export(server_exports, {
|
|
|
4659
5612
|
createServer: () => createServer
|
|
4660
5613
|
});
|
|
4661
5614
|
import http from "http";
|
|
4662
|
-
import
|
|
5615
|
+
import path16 from "path";
|
|
4663
5616
|
import os from "os";
|
|
4664
5617
|
import connect from "connect";
|
|
4665
5618
|
import sirv from "sirv";
|
|
@@ -4669,27 +5622,38 @@ async function createServer(inlineConfig = {}) {
|
|
|
4669
5622
|
const startTime = performance.now();
|
|
4670
5623
|
const config = await resolveConfig(inlineConfig, "serve");
|
|
4671
5624
|
const logger = config.logger;
|
|
4672
|
-
const allPlugins = resolvePluginList(config, config.plugins
|
|
5625
|
+
const allPlugins = resolvePluginList(config, config.plugins, {
|
|
5626
|
+
environmentName: "client"
|
|
5627
|
+
});
|
|
4673
5628
|
const configWithPlugins = { ...config, plugins: allPlugins };
|
|
4674
5629
|
const app = connect();
|
|
4675
5630
|
const httpServer = http.createServer(app);
|
|
4676
5631
|
const ws = createWebSocketServer(httpServer);
|
|
4677
|
-
const
|
|
5632
|
+
const pluginApi = getPluginApi(config);
|
|
5633
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
4678
5634
|
hot: createWsHotChannel(ws),
|
|
4679
5635
|
mode: "dev",
|
|
4680
|
-
plugins: allPlugins
|
|
5636
|
+
plugins: allPlugins,
|
|
5637
|
+
pluginApi
|
|
4681
5638
|
});
|
|
4682
5639
|
await clientEnv.init();
|
|
4683
5640
|
const environments = { client: clientEnv };
|
|
4684
5641
|
for (const name of Object.keys(config.environments)) {
|
|
4685
5642
|
if (name === "client") continue;
|
|
4686
5643
|
const consumer = config.environments[name].consumer;
|
|
4687
|
-
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
4688
|
-
|
|
5644
|
+
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
5645
|
+
consumer,
|
|
5646
|
+
environmentName: name
|
|
5647
|
+
});
|
|
5648
|
+
environments[name] = new NastiEnvironment(name, config, {
|
|
4689
5649
|
mode: "dev",
|
|
4690
|
-
plugins: envPlugins
|
|
5650
|
+
plugins: envPlugins,
|
|
5651
|
+
pluginApi
|
|
4691
5652
|
});
|
|
4692
5653
|
}
|
|
5654
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5655
|
+
if (name !== "client" && environment.options.driver) await environment.init();
|
|
5656
|
+
}
|
|
4693
5657
|
let ssrRunner = null;
|
|
4694
5658
|
async function getSsrRunner() {
|
|
4695
5659
|
if (ssrRunner) return ssrRunner;
|
|
@@ -4714,23 +5678,15 @@ async function createServer(inlineConfig = {}) {
|
|
|
4714
5678
|
});
|
|
4715
5679
|
app.use(bundledServer.middleware);
|
|
4716
5680
|
}
|
|
4717
|
-
app.use(transformMiddleware({
|
|
4718
|
-
config: configWithPlugins,
|
|
4719
|
-
pluginContainer,
|
|
4720
|
-
moduleGraph
|
|
4721
|
-
}));
|
|
4722
|
-
const publicDir = path15.resolve(config.root, "public");
|
|
4723
|
-
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
4724
|
-
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
4725
5681
|
const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
|
|
4726
|
-
const outDirAbs =
|
|
5682
|
+
const outDirAbs = path16.resolve(config.root, config.build.outDir);
|
|
4727
5683
|
const watcher = watch(config.root, {
|
|
4728
5684
|
ignored: (filePath) => {
|
|
4729
5685
|
if (filePath === config.root) return false;
|
|
4730
|
-
if (filePath === outDirAbs || filePath.startsWith(outDirAbs +
|
|
4731
|
-
const rel =
|
|
4732
|
-
if (!rel || rel.startsWith("..") ||
|
|
4733
|
-
for (const seg of rel.split(
|
|
5686
|
+
if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path16.sep)) return true;
|
|
5687
|
+
const rel = path16.relative(config.root, filePath);
|
|
5688
|
+
if (!rel || rel.startsWith("..") || path16.isAbsolute(rel)) return false;
|
|
5689
|
+
for (const seg of rel.split(path16.sep)) {
|
|
4734
5690
|
if (ignoredSegments.has(seg)) return true;
|
|
4735
5691
|
}
|
|
4736
5692
|
return false;
|
|
@@ -4738,13 +5694,72 @@ async function createServer(inlineConfig = {}) {
|
|
|
4738
5694
|
ignoreInitial: true
|
|
4739
5695
|
});
|
|
4740
5696
|
let server;
|
|
5697
|
+
const environmentServices = {};
|
|
5698
|
+
let environmentDriversStarted = false;
|
|
5699
|
+
const logCloseError = (target, error) => {
|
|
5700
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
5701
|
+
logger.error(`[nasti] failed to close ${target}`, { error: normalized });
|
|
5702
|
+
};
|
|
5703
|
+
const startEnvironmentDrivers = async () => {
|
|
5704
|
+
if (environmentDriversStarted) return;
|
|
5705
|
+
environmentDriversStarted = true;
|
|
5706
|
+
const started = [];
|
|
5707
|
+
const attempted = [];
|
|
5708
|
+
try {
|
|
5709
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5710
|
+
if (!environment.driver?.serve) continue;
|
|
5711
|
+
attempted.push(environment);
|
|
5712
|
+
const result = await environment.driver.serve({
|
|
5713
|
+
...environment.getDriverContext(),
|
|
5714
|
+
server
|
|
5715
|
+
});
|
|
5716
|
+
started.push({ name, environment, service: result ?? {} });
|
|
5717
|
+
}
|
|
5718
|
+
for (const { name, service } of started) {
|
|
5719
|
+
environmentServices[name] = service;
|
|
5720
|
+
if (service.middleware) app.use(service.middleware);
|
|
5721
|
+
}
|
|
5722
|
+
} catch (error) {
|
|
5723
|
+
environmentDriversStarted = false;
|
|
5724
|
+
for (const { name } of started) {
|
|
5725
|
+
delete environmentServices[name];
|
|
5726
|
+
}
|
|
5727
|
+
for (const environment of attempted.reverse()) {
|
|
5728
|
+
try {
|
|
5729
|
+
await environment.driver?.close?.(environment.getDriverContext());
|
|
5730
|
+
} catch (closeError) {
|
|
5731
|
+
logCloseError(`environment driver "${environment.driver.name}"`, closeError);
|
|
5732
|
+
}
|
|
5733
|
+
}
|
|
5734
|
+
throw error;
|
|
5735
|
+
}
|
|
5736
|
+
};
|
|
5737
|
+
const notifyEnvironmentDrivers = (file, event) => {
|
|
5738
|
+
for (const environment of Object.values(environments)) {
|
|
5739
|
+
if (!environment.driver?.watchChange) continue;
|
|
5740
|
+
void Promise.resolve(
|
|
5741
|
+
environment.driver.watchChange(file, event, environment.getDriverContext())
|
|
5742
|
+
).catch((error) => {
|
|
5743
|
+
logger.error(
|
|
5744
|
+
`[nasti] environment driver "${environment.driver.name}" watchChange failed`,
|
|
5745
|
+
{ error }
|
|
5746
|
+
);
|
|
5747
|
+
});
|
|
5748
|
+
}
|
|
5749
|
+
};
|
|
4741
5750
|
watcher.on("change", (file) => {
|
|
4742
5751
|
ssrRunner?.invalidateFile(file);
|
|
4743
5752
|
handleFileChange(file, server);
|
|
5753
|
+
notifyEnvironmentDrivers(file, "change");
|
|
4744
5754
|
});
|
|
4745
5755
|
watcher.on("add", (file) => {
|
|
4746
5756
|
ssrRunner?.invalidateFile(file);
|
|
4747
5757
|
handleFileChange(file, server);
|
|
5758
|
+
notifyEnvironmentDrivers(file, "add");
|
|
5759
|
+
});
|
|
5760
|
+
watcher.on("unlink", (file) => {
|
|
5761
|
+
ssrRunner?.invalidateFile(file);
|
|
5762
|
+
notifyEnvironmentDrivers(file, "unlink");
|
|
4748
5763
|
});
|
|
4749
5764
|
server = {
|
|
4750
5765
|
config: configWithPlugins,
|
|
@@ -4753,10 +5768,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4753
5768
|
watcher,
|
|
4754
5769
|
ws,
|
|
4755
5770
|
environments,
|
|
5771
|
+
environmentServices,
|
|
4756
5772
|
async listen(port) {
|
|
4757
5773
|
const finalPort = port ?? config.server.port;
|
|
4758
5774
|
const host = config.server.host === true ? "0.0.0.0" : config.server.host;
|
|
4759
5775
|
await pluginContainer.buildStart();
|
|
5776
|
+
await startEnvironmentDrivers();
|
|
4760
5777
|
return new Promise((resolve, reject) => {
|
|
4761
5778
|
let currentPort = finalPort;
|
|
4762
5779
|
const onListening = () => {
|
|
@@ -4764,15 +5781,20 @@ async function createServer(inlineConfig = {}) {
|
|
|
4764
5781
|
config.server.port = actualPort;
|
|
4765
5782
|
const localUrl = `http://localhost:${actualPort}/`;
|
|
4766
5783
|
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}/` : null;
|
|
5784
|
+
const driverLocalUrls = Object.values(environmentServices).flatMap((service) => service.localUrls ?? []);
|
|
5785
|
+
const driverNetworkUrls = Object.values(environmentServices).flatMap((service) => service.networkUrls ?? []);
|
|
4767
5786
|
logger.clearScreen("info");
|
|
4768
5787
|
const readyIn = Math.ceil(performance.now() - startTime);
|
|
4769
5788
|
logger.info(
|
|
4770
5789
|
`
|
|
4771
|
-
${pc9.cyan(pc9.bold("NASTI"))} ${pc9.cyan(`v${"2.
|
|
5790
|
+
${pc9.cyan(pc9.bold("NASTI"))} ${pc9.cyan(`v${"2.4.0"}`)} ${pc9.dim("ready in")} ${pc9.bold(readyIn)} ${pc9.dim("ms")}
|
|
4772
5791
|
`
|
|
4773
5792
|
);
|
|
4774
5793
|
printServerUrls(
|
|
4775
|
-
{
|
|
5794
|
+
{
|
|
5795
|
+
local: [localUrl, ...driverLocalUrls],
|
|
5796
|
+
network: [...networkUrl ? [networkUrl] : [], ...driverNetworkUrls]
|
|
5797
|
+
},
|
|
4776
5798
|
logger.info
|
|
4777
5799
|
);
|
|
4778
5800
|
logger.info("");
|
|
@@ -4793,7 +5815,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4793
5815
|
},
|
|
4794
5816
|
async transformRequest(url) {
|
|
4795
5817
|
const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
|
|
4796
|
-
return transformRequest2(url, {
|
|
5818
|
+
return transformRequest2(url, {
|
|
5819
|
+
config: configWithPlugins,
|
|
5820
|
+
pluginContainer,
|
|
5821
|
+
moduleGraph,
|
|
5822
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5823
|
+
});
|
|
4797
5824
|
},
|
|
4798
5825
|
async ssrLoadModule(url) {
|
|
4799
5826
|
const runner = await getSsrRunner();
|
|
@@ -4802,11 +5829,63 @@ async function createServer(inlineConfig = {}) {
|
|
|
4802
5829
|
async close() {
|
|
4803
5830
|
await pluginContainer.buildEnd();
|
|
4804
5831
|
await bundledServer?.close();
|
|
4805
|
-
|
|
5832
|
+
let environmentCloseFailed = false;
|
|
5833
|
+
let firstEnvironmentCloseError;
|
|
5834
|
+
for (const environment of Object.values(environments).reverse()) {
|
|
5835
|
+
try {
|
|
5836
|
+
await environment.close();
|
|
5837
|
+
} catch (error) {
|
|
5838
|
+
if (!environmentCloseFailed) {
|
|
5839
|
+
environmentCloseFailed = true;
|
|
5840
|
+
firstEnvironmentCloseError = error;
|
|
5841
|
+
}
|
|
5842
|
+
logCloseError(`environment "${environment.name}"`, error);
|
|
5843
|
+
}
|
|
5844
|
+
}
|
|
5845
|
+
await watcher.close();
|
|
4806
5846
|
ws.close();
|
|
4807
5847
|
httpServer.close();
|
|
5848
|
+
if (environmentCloseFailed) {
|
|
5849
|
+
throw firstEnvironmentCloseError;
|
|
5850
|
+
}
|
|
4808
5851
|
}
|
|
4809
5852
|
};
|
|
5853
|
+
try {
|
|
5854
|
+
await startEnvironmentDrivers();
|
|
5855
|
+
} catch (error) {
|
|
5856
|
+
if (bundledServer) {
|
|
5857
|
+
try {
|
|
5858
|
+
await bundledServer.close();
|
|
5859
|
+
} catch (closeError) {
|
|
5860
|
+
logCloseError("bundled dev server after driver startup failure", closeError);
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
try {
|
|
5864
|
+
await watcher.close();
|
|
5865
|
+
} catch (closeError) {
|
|
5866
|
+
logCloseError("file watcher after driver startup failure", closeError);
|
|
5867
|
+
}
|
|
5868
|
+
try {
|
|
5869
|
+
ws.close();
|
|
5870
|
+
} catch (closeError) {
|
|
5871
|
+
logCloseError("WebSocket server after driver startup failure", closeError);
|
|
5872
|
+
}
|
|
5873
|
+
try {
|
|
5874
|
+
httpServer.close();
|
|
5875
|
+
} catch (closeError) {
|
|
5876
|
+
logCloseError("HTTP server after driver startup failure", closeError);
|
|
5877
|
+
}
|
|
5878
|
+
throw error;
|
|
5879
|
+
}
|
|
5880
|
+
app.use(transformMiddleware({
|
|
5881
|
+
config: configWithPlugins,
|
|
5882
|
+
pluginContainer,
|
|
5883
|
+
moduleGraph,
|
|
5884
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5885
|
+
}));
|
|
5886
|
+
const publicDir = path16.resolve(config.root, "public");
|
|
5887
|
+
app.use(sirv(publicDir, { dev: true, etag: true }));
|
|
5888
|
+
app.use(sirv(config.root, { dev: true, etag: true }));
|
|
4810
5889
|
const postMiddlewares = [];
|
|
4811
5890
|
for (const plugin of allPlugins) {
|
|
4812
5891
|
if (plugin.configureServer) {
|
|
@@ -4841,6 +5920,7 @@ var init_server = __esm({
|
|
|
4841
5920
|
init_middleware();
|
|
4842
5921
|
init_hmr();
|
|
4843
5922
|
init_builtins();
|
|
5923
|
+
init_plugin_api();
|
|
4844
5924
|
}
|
|
4845
5925
|
});
|
|
4846
5926
|
|
|
@@ -4851,8 +5931,8 @@ init_build();
|
|
|
4851
5931
|
// src/build/electron.ts
|
|
4852
5932
|
init_config();
|
|
4853
5933
|
init_resolve();
|
|
4854
|
-
import
|
|
4855
|
-
import
|
|
5934
|
+
import path11 from "path";
|
|
5935
|
+
import fs8 from "fs";
|
|
4856
5936
|
import { rolldown as rolldown2 } from "rolldown";
|
|
4857
5937
|
import pc5 from "picocolors";
|
|
4858
5938
|
|
|
@@ -4896,28 +5976,26 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4896
5976
|
const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
|
|
4897
5977
|
const startTime = performance.now();
|
|
4898
5978
|
assertElectronVersion(config);
|
|
4899
|
-
console.log(pc5.cyan("\n\u26A1 nasti build (electron)") + pc5.dim(` v${"2.
|
|
5979
|
+
console.log(pc5.cyan("\n\u26A1 nasti build (electron)") + pc5.dim(` v${"2.4.0"}`));
|
|
4900
5980
|
console.log(pc5.dim(` root: ${config.root}`));
|
|
4901
5981
|
console.log(pc5.dim(` mode: ${config.mode}`));
|
|
4902
5982
|
console.log(pc5.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
|
|
4903
|
-
const outDir =
|
|
4904
|
-
if (config.build.emptyOutDir &&
|
|
4905
|
-
|
|
5983
|
+
const outDir = path11.resolve(config.root, config.build.outDir);
|
|
5984
|
+
if (config.build.emptyOutDir && fs8.existsSync(outDir)) {
|
|
5985
|
+
fs8.rmSync(outDir, { recursive: true, force: true });
|
|
4906
5986
|
}
|
|
4907
|
-
|
|
4908
|
-
const rendererOutDir =
|
|
5987
|
+
fs8.mkdirSync(outDir, { recursive: true });
|
|
5988
|
+
const rendererOutDir = path11.join(outDir, "renderer");
|
|
4909
5989
|
const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
4910
|
-
await build2({
|
|
4911
|
-
...inlineConfig,
|
|
4912
|
-
target: "web",
|
|
5990
|
+
await build2(createElectronRendererConfig(config, inlineConfig, {
|
|
4913
5991
|
build: {
|
|
4914
5992
|
...inlineConfig.build,
|
|
4915
5993
|
outDir: rendererOutDir,
|
|
4916
5994
|
emptyOutDir: false
|
|
4917
5995
|
}
|
|
4918
|
-
});
|
|
4919
|
-
const mainEntry =
|
|
4920
|
-
if (!
|
|
5996
|
+
}));
|
|
5997
|
+
const mainEntry = path11.resolve(config.root, config.electron.main);
|
|
5998
|
+
if (!fs8.existsSync(mainEntry)) {
|
|
4921
5999
|
throw new Error(
|
|
4922
6000
|
`Electron main entry not found: ${config.electron.main}
|
|
4923
6001
|
\u5728 nasti.config.ts \u7684 electron.main \u6307\u5B9A\u4E3B\u8FDB\u7A0B\u5165\u53E3\u6587\u4EF6\u3002`
|
|
@@ -4931,11 +6009,11 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4931
6009
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
4932
6010
|
const preloadFiles = [];
|
|
4933
6011
|
for (const entry of preloadEntries) {
|
|
4934
|
-
if (!
|
|
6012
|
+
if (!fs8.existsSync(entry)) {
|
|
4935
6013
|
console.warn(pc5.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
|
|
4936
6014
|
continue;
|
|
4937
6015
|
}
|
|
4938
|
-
const base =
|
|
6016
|
+
const base = path11.basename(entry).replace(/\.[^.]+$/, "");
|
|
4939
6017
|
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
4940
6018
|
await bundleNode(config, entry, {
|
|
4941
6019
|
outFile: out,
|
|
@@ -4947,10 +6025,10 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4947
6025
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
4948
6026
|
console.log(pc5.green(`
|
|
4949
6027
|
\u2713 Electron build complete in ${elapsed}s`));
|
|
4950
|
-
console.log(pc5.dim(` renderer: ${
|
|
4951
|
-
console.log(pc5.dim(` main: ${
|
|
6028
|
+
console.log(pc5.dim(` renderer: ${path11.relative(config.root, rendererOutDir)}/`));
|
|
6029
|
+
console.log(pc5.dim(` main: ${path11.relative(config.root, mainFile)}`));
|
|
4952
6030
|
for (const pf of preloadFiles) {
|
|
4953
|
-
console.log(pc5.dim(` preload: ${
|
|
6031
|
+
console.log(pc5.dim(` preload: ${path11.relative(config.root, pf)}`));
|
|
4954
6032
|
}
|
|
4955
6033
|
console.log();
|
|
4956
6034
|
return { rendererOutDir, mainFile, preloadFiles };
|
|
@@ -4969,7 +6047,8 @@ async function bundleNode(config, entry, opts) {
|
|
|
4969
6047
|
const result = transformCode(id, code, {
|
|
4970
6048
|
sourcemap: !!config.build.sourcemap,
|
|
4971
6049
|
jsxRuntime: "automatic",
|
|
4972
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6050
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6051
|
+
target: config.electron.nodeTarget
|
|
4973
6052
|
});
|
|
4974
6053
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
4975
6054
|
}
|
|
@@ -4980,10 +6059,14 @@ async function bundleNode(config, entry, opts) {
|
|
|
4980
6059
|
...restInputOptions,
|
|
4981
6060
|
input: entry,
|
|
4982
6061
|
platform: "node",
|
|
4983
|
-
transform: {
|
|
6062
|
+
transform: {
|
|
6063
|
+
...userTransform,
|
|
6064
|
+
target: config.electron.nodeTarget,
|
|
6065
|
+
define: mergedDefine
|
|
6066
|
+
},
|
|
4984
6067
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
4985
6068
|
});
|
|
4986
|
-
|
|
6069
|
+
fs8.mkdirSync(path11.dirname(opts.outFile), { recursive: true });
|
|
4987
6070
|
await bundle2.write({
|
|
4988
6071
|
sourcemap: !!config.build.sourcemap,
|
|
4989
6072
|
minify: !!config.build.minify,
|
|
@@ -4994,16 +6077,35 @@ async function bundleNode(config, entry, opts) {
|
|
|
4994
6077
|
codeSplitting: false
|
|
4995
6078
|
});
|
|
4996
6079
|
await bundle2.close();
|
|
4997
|
-
console.log(pc5.dim(` \u2713 ${opts.label} \u2192 ${
|
|
6080
|
+
console.log(pc5.dim(` \u2713 ${opts.label} \u2192 ${path11.relative(config.root, opts.outFile)}`));
|
|
4998
6081
|
return opts.outFile;
|
|
4999
6082
|
}
|
|
6083
|
+
function createElectronRendererConfig(config, inlineConfig = {}, overrides = {}) {
|
|
6084
|
+
const inlineClient = inlineConfig.environments?.client ?? {};
|
|
6085
|
+
return {
|
|
6086
|
+
...inlineConfig,
|
|
6087
|
+
...overrides,
|
|
6088
|
+
root: config.root,
|
|
6089
|
+
mode: config.mode,
|
|
6090
|
+
target: "web",
|
|
6091
|
+
framework: config.framework,
|
|
6092
|
+
base: config.base === "/" ? "./" : config.base,
|
|
6093
|
+
environments: {
|
|
6094
|
+
...inlineConfig.environments ?? {},
|
|
6095
|
+
client: {
|
|
6096
|
+
...inlineClient,
|
|
6097
|
+
html: config.electron.renderer
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
};
|
|
6101
|
+
}
|
|
5000
6102
|
function outFileName(outDir, base, format) {
|
|
5001
6103
|
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
5002
|
-
return
|
|
6104
|
+
return path11.join(outDir, base + ext);
|
|
5003
6105
|
}
|
|
5004
6106
|
function normalizePreload(preload, root) {
|
|
5005
6107
|
const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
|
|
5006
|
-
return list.map((p) =>
|
|
6108
|
+
return list.map((p) => path11.resolve(root, p));
|
|
5007
6109
|
}
|
|
5008
6110
|
function assertElectronVersion(config) {
|
|
5009
6111
|
const min = config.electron.minVersion;
|
|
@@ -5018,9 +6120,9 @@ function assertElectronVersion(config) {
|
|
|
5018
6120
|
}
|
|
5019
6121
|
function detectInstalledElectron(root) {
|
|
5020
6122
|
try {
|
|
5021
|
-
const pkgPath =
|
|
5022
|
-
if (!
|
|
5023
|
-
const pkg = JSON.parse(
|
|
6123
|
+
const pkgPath = path11.resolve(root, "node_modules/electron/package.json");
|
|
6124
|
+
if (!fs8.existsSync(pkgPath)) return null;
|
|
6125
|
+
const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
|
|
5024
6126
|
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
5025
6127
|
return Number.isFinite(major) ? major : null;
|
|
5026
6128
|
} catch {
|
|
@@ -5033,8 +6135,8 @@ init_server();
|
|
|
5033
6135
|
|
|
5034
6136
|
// src/server/electron-dev.ts
|
|
5035
6137
|
init_config();
|
|
5036
|
-
import
|
|
5037
|
-
import
|
|
6138
|
+
import path17 from "path";
|
|
6139
|
+
import fs12 from "fs";
|
|
5038
6140
|
import { createRequire as createRequire5 } from "module";
|
|
5039
6141
|
import { spawn } from "child_process";
|
|
5040
6142
|
import chokidar from "chokidar";
|
|
@@ -5047,17 +6149,21 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5047
6149
|
const { noSpawn, ...rest } = inlineConfig;
|
|
5048
6150
|
const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
|
|
5049
6151
|
warnElectronVersion(config);
|
|
5050
|
-
console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.
|
|
6152
|
+
console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.4.0"}`));
|
|
5051
6153
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5052
|
-
const server = await createServer2({
|
|
6154
|
+
const server = await createServer2({
|
|
6155
|
+
...rest,
|
|
6156
|
+
target: "electron",
|
|
6157
|
+
framework: config.framework
|
|
6158
|
+
});
|
|
5053
6159
|
await server.listen();
|
|
5054
|
-
const devUrl = `http://localhost:${server.config.server.port}
|
|
6160
|
+
const devUrl = `http://localhost:${server.config.server.port}` + electronRendererDevPath(config.electron.renderer);
|
|
5055
6161
|
console.log(pc10.dim(` renderer: ${devUrl}`));
|
|
5056
|
-
const stageDir =
|
|
5057
|
-
|
|
5058
|
-
const mainEntry =
|
|
6162
|
+
const stageDir = path17.resolve(config.root, ".nasti");
|
|
6163
|
+
fs12.mkdirSync(stageDir, { recursive: true });
|
|
6164
|
+
const mainEntry = path17.resolve(config.root, config.electron.main);
|
|
5059
6165
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
5060
|
-
const builtMainFile =
|
|
6166
|
+
const builtMainFile = path17.join(stageDir, "main" + extFor(config.electron.mainFormat));
|
|
5061
6167
|
const builtPreloadFiles = [];
|
|
5062
6168
|
const compileAll = async () => {
|
|
5063
6169
|
await compileNode(config, mainEntry, {
|
|
@@ -5067,9 +6173,9 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5067
6173
|
});
|
|
5068
6174
|
builtPreloadFiles.length = 0;
|
|
5069
6175
|
for (const entry of preloadEntries) {
|
|
5070
|
-
if (!
|
|
5071
|
-
const base =
|
|
5072
|
-
const out =
|
|
6176
|
+
if (!fs12.existsSync(entry)) continue;
|
|
6177
|
+
const base = path17.basename(entry).replace(/\.[^.]+$/, "");
|
|
6178
|
+
const out = path17.join(stageDir, base + extFor(config.electron.preloadFormat));
|
|
5073
6179
|
await compileNode(config, entry, {
|
|
5074
6180
|
outFile: out,
|
|
5075
6181
|
format: config.electron.preloadFormat,
|
|
@@ -5108,7 +6214,7 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5108
6214
|
};
|
|
5109
6215
|
spawnElectron();
|
|
5110
6216
|
if (config.electron.autoRestart) {
|
|
5111
|
-
const watchTargets = [mainEntry, ...preloadEntries].filter(
|
|
6217
|
+
const watchTargets = [mainEntry, ...preloadEntries].filter(fs12.existsSync);
|
|
5112
6218
|
const watcher = chokidar.watch(watchTargets, { ignoreInitial: true });
|
|
5113
6219
|
let restarting = null;
|
|
5114
6220
|
let pending = false;
|
|
@@ -5173,18 +6279,22 @@ async function compileNode(config, entry, opts) {
|
|
|
5173
6279
|
const result = transformCode(id, code, {
|
|
5174
6280
|
sourcemap: true,
|
|
5175
6281
|
jsxRuntime: "automatic",
|
|
5176
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6282
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6283
|
+
target: config.electron.nodeTarget
|
|
5177
6284
|
});
|
|
5178
6285
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
5179
6286
|
}
|
|
5180
6287
|
};
|
|
5181
6288
|
const bundle2 = await rolldown3({
|
|
5182
6289
|
input: entry,
|
|
5183
|
-
transform: {
|
|
6290
|
+
transform: {
|
|
6291
|
+
target: config.electron.nodeTarget,
|
|
6292
|
+
define: envDefine
|
|
6293
|
+
},
|
|
5184
6294
|
platform: "node",
|
|
5185
6295
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
5186
6296
|
});
|
|
5187
|
-
|
|
6297
|
+
fs12.mkdirSync(path17.dirname(opts.outFile), { recursive: true });
|
|
5188
6298
|
await bundle2.write({
|
|
5189
6299
|
file: opts.outFile,
|
|
5190
6300
|
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
@@ -5196,15 +6306,19 @@ async function compileNode(config, entry, opts) {
|
|
|
5196
6306
|
});
|
|
5197
6307
|
await bundle2.close();
|
|
5198
6308
|
}
|
|
6309
|
+
function electronRendererDevPath(renderer) {
|
|
6310
|
+
const normalized = renderer.split(path17.sep).join("/").replace(/^\.?\//, "");
|
|
6311
|
+
return normalized === "index.html" ? "/" : `/${normalized}`;
|
|
6312
|
+
}
|
|
5199
6313
|
function resolveElectronBinary(config) {
|
|
5200
|
-
if (config.electron.electronPath &&
|
|
6314
|
+
if (config.electron.electronPath && fs12.existsSync(config.electron.electronPath)) {
|
|
5201
6315
|
return config.electron.electronPath;
|
|
5202
6316
|
}
|
|
5203
6317
|
try {
|
|
5204
|
-
const require2 = createRequire5(
|
|
6318
|
+
const require2 = createRequire5(path17.resolve(config.root, "package.json"));
|
|
5205
6319
|
const pathFile = require2.resolve("electron");
|
|
5206
6320
|
const electronModule = require2(pathFile);
|
|
5207
|
-
if (typeof electronModule === "string" &&
|
|
6321
|
+
if (typeof electronModule === "string" && fs12.existsSync(electronModule)) {
|
|
5208
6322
|
return electronModule;
|
|
5209
6323
|
}
|
|
5210
6324
|
} catch {
|
|
@@ -5231,8 +6345,8 @@ function warnElectronVersion(config) {
|
|
|
5231
6345
|
}
|
|
5232
6346
|
|
|
5233
6347
|
// src/plugins/monaco-editor.ts
|
|
5234
|
-
import
|
|
5235
|
-
import
|
|
6348
|
+
import path18 from "path";
|
|
6349
|
+
import fs13 from "fs";
|
|
5236
6350
|
import crypto4 from "crypto";
|
|
5237
6351
|
import { createRequire as createRequire6 } from "module";
|
|
5238
6352
|
var DEFAULT_WORKERS = {
|
|
@@ -5253,9 +6367,9 @@ function normalizePublicPath(p) {
|
|
|
5253
6367
|
}
|
|
5254
6368
|
function readMonacoVersion(root) {
|
|
5255
6369
|
try {
|
|
5256
|
-
const require2 = createRequire6(
|
|
6370
|
+
const require2 = createRequire6(path18.resolve(root, "package.json"));
|
|
5257
6371
|
const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
|
|
5258
|
-
const pkg = JSON.parse(
|
|
6372
|
+
const pkg = JSON.parse(fs13.readFileSync(pkgJsonPath, "utf-8"));
|
|
5259
6373
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
5260
6374
|
} catch {
|
|
5261
6375
|
return "unknown";
|
|
@@ -5275,20 +6389,20 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5275
6389
|
let cacheDir = "";
|
|
5276
6390
|
const building = /* @__PURE__ */ new Map();
|
|
5277
6391
|
async function buildWorker(worker) {
|
|
5278
|
-
const cacheFile =
|
|
5279
|
-
if (
|
|
6392
|
+
const cacheFile = path18.join(cacheDir, `${worker.label}.worker.js`);
|
|
6393
|
+
if (fs13.existsSync(cacheFile)) return cacheFile;
|
|
5280
6394
|
const existing = building.get(worker.label);
|
|
5281
6395
|
if (existing) return existing;
|
|
5282
6396
|
const task = (async () => {
|
|
5283
6397
|
const { rolldown: rolldown4 } = await import("rolldown");
|
|
5284
|
-
const require2 = createRequire6(
|
|
6398
|
+
const require2 = createRequire6(path18.resolve(resolvedConfig.root, "package.json"));
|
|
5285
6399
|
let entry;
|
|
5286
6400
|
try {
|
|
5287
6401
|
entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
|
|
5288
6402
|
} catch {
|
|
5289
6403
|
entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
|
|
5290
6404
|
}
|
|
5291
|
-
|
|
6405
|
+
fs13.mkdirSync(cacheDir, { recursive: true });
|
|
5292
6406
|
const bundle2 = await rolldown4({
|
|
5293
6407
|
input: entry,
|
|
5294
6408
|
platform: "browser"
|
|
@@ -5348,12 +6462,12 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5348
6462
|
resolvedConfig = config;
|
|
5349
6463
|
const version = readMonacoVersion(config.root);
|
|
5350
6464
|
const key = crypto4.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
|
|
5351
|
-
cacheDir =
|
|
6465
|
+
cacheDir = path18.resolve(config.root, "node_modules/.nasti/monaco", key);
|
|
5352
6466
|
},
|
|
5353
6467
|
async configureServer(server) {
|
|
5354
6468
|
const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
|
|
5355
6469
|
const watcher = server.watcher;
|
|
5356
|
-
const monacoDir =
|
|
6470
|
+
const monacoDir = path18.resolve(resolvedConfig.root, "node_modules/monaco-editor");
|
|
5357
6471
|
try {
|
|
5358
6472
|
watcher?.unwatch?.(monacoDir);
|
|
5359
6473
|
} catch {
|
|
@@ -5383,7 +6497,7 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5383
6497
|
const file = await buildWorker(worker);
|
|
5384
6498
|
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
5385
6499
|
res.setHeader("Cache-Control", "public, max-age=604800, immutable");
|
|
5386
|
-
|
|
6500
|
+
fs13.createReadStream(file).pipe(res);
|
|
5387
6501
|
} catch (e) {
|
|
5388
6502
|
res.statusCode = 500;
|
|
5389
6503
|
res.end(`Monaco worker build failed: ${e.message}`);
|
|
@@ -5418,16 +6532,16 @@ self.monaco = monaco;`,
|
|
|
5418
6532
|
resolvedConfig.root,
|
|
5419
6533
|
resolvedConfig.build.outDir,
|
|
5420
6534
|
resolvedConfig.base
|
|
5421
|
-
) : isCDN(publicPath) ?
|
|
6535
|
+
) : isCDN(publicPath) ? path18.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path18.resolve(
|
|
5422
6536
|
resolvedConfig.root,
|
|
5423
6537
|
resolvedConfig.build.outDir,
|
|
5424
6538
|
publicPath.replace(/^\//, "")
|
|
5425
6539
|
);
|
|
5426
|
-
|
|
6540
|
+
fs13.mkdirSync(outDir, { recursive: true });
|
|
5427
6541
|
for (const worker of workers) {
|
|
5428
6542
|
try {
|
|
5429
6543
|
const cacheFile = await buildWorker(worker);
|
|
5430
|
-
|
|
6544
|
+
fs13.copyFileSync(cacheFile, path18.join(outDir, `${worker.label}.worker.js`));
|
|
5431
6545
|
} catch (e) {
|
|
5432
6546
|
throw new Error(
|
|
5433
6547
|
`[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
|
|
@@ -5452,12 +6566,15 @@ export {
|
|
|
5452
6566
|
buildElectron,
|
|
5453
6567
|
buildEnvDefine,
|
|
5454
6568
|
createDebugger,
|
|
6569
|
+
createElectronRendererConfig,
|
|
5455
6570
|
createLogger,
|
|
5456
6571
|
createNoopHotChannel,
|
|
5457
6572
|
createServer,
|
|
5458
6573
|
createWsHotChannel,
|
|
5459
6574
|
defineConfig,
|
|
6575
|
+
detectFramework,
|
|
5460
6576
|
electronPlugin,
|
|
6577
|
+
electronRendererDevPath,
|
|
5461
6578
|
loadEnv,
|
|
5462
6579
|
monacoEditorPlugin,
|
|
5463
6580
|
printServerUrls,
|