@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.cjs
CHANGED
|
@@ -5,10 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __glob = (map) => (
|
|
9
|
-
var fn = map[
|
|
8
|
+
var __glob = (map) => (path19) => {
|
|
9
|
+
var fn = map[path19];
|
|
10
10
|
if (fn) return fn();
|
|
11
|
-
throw new Error("Module not found in bundle: " +
|
|
11
|
+
throw new Error("Module not found in bundle: " + path19);
|
|
12
12
|
};
|
|
13
13
|
var __esm = (fn, res) => function __init() {
|
|
14
14
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -221,6 +221,92 @@ var init_logger = __esm({
|
|
|
221
221
|
}
|
|
222
222
|
});
|
|
223
223
|
|
|
224
|
+
// src/core/plugin-api.ts
|
|
225
|
+
function orderPlugins(plugins) {
|
|
226
|
+
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);
|
|
227
|
+
const indexesByName = /* @__PURE__ */ new Map();
|
|
228
|
+
baseline.forEach((plugin, index2) => {
|
|
229
|
+
const indexes = indexesByName.get(plugin.name) ?? [];
|
|
230
|
+
indexes.push(index2);
|
|
231
|
+
indexesByName.set(plugin.name, indexes);
|
|
232
|
+
});
|
|
233
|
+
const edges = baseline.map(() => /* @__PURE__ */ new Set());
|
|
234
|
+
const indegree = baseline.map(() => 0);
|
|
235
|
+
const addEdge = (from, to) => {
|
|
236
|
+
if (from === to || edges[from].has(to)) return;
|
|
237
|
+
edges[from].add(to);
|
|
238
|
+
indegree[to]++;
|
|
239
|
+
};
|
|
240
|
+
baseline.forEach((plugin, current) => {
|
|
241
|
+
for (const dependency of plugin.pre ?? []) {
|
|
242
|
+
for (const before of indexesByName.get(dependency) ?? []) addEdge(before, current);
|
|
243
|
+
}
|
|
244
|
+
for (const dependency of plugin.post ?? []) {
|
|
245
|
+
for (const after of indexesByName.get(dependency) ?? []) addEdge(current, after);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
const ready = indegree.map((degree, index2) => ({ degree, index: index2 })).filter(({ degree }) => degree === 0).map(({ index: index2 }) => index2);
|
|
249
|
+
const ordered = [];
|
|
250
|
+
while (ready.length > 0) {
|
|
251
|
+
ready.sort((a, b) => a - b);
|
|
252
|
+
const current = ready.shift();
|
|
253
|
+
ordered.push(baseline[current]);
|
|
254
|
+
for (const next of edges[current]) {
|
|
255
|
+
indegree[next]--;
|
|
256
|
+
if (indegree[next] === 0) ready.push(next);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (ordered.length !== baseline.length) {
|
|
260
|
+
const cyclic = baseline.filter((_, index2) => indegree[index2] > 0).map((plugin) => plugin.name);
|
|
261
|
+
throw new Error(
|
|
262
|
+
`[nasti] circular plugin setup dependency: ${[...new Set(cyclic)].join(", ")}`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
return ordered;
|
|
266
|
+
}
|
|
267
|
+
async function setupPluginApi(config, plugins) {
|
|
268
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
269
|
+
const api = {
|
|
270
|
+
config,
|
|
271
|
+
logger: config.logger,
|
|
272
|
+
expose(key, value) {
|
|
273
|
+
if (exposed.has(key) && exposed.get(key) !== value) {
|
|
274
|
+
throw new Error(`[nasti] plugin API key already exposed: ${String(key)}`);
|
|
275
|
+
}
|
|
276
|
+
exposed.set(key, value);
|
|
277
|
+
},
|
|
278
|
+
useExposed(key) {
|
|
279
|
+
return exposed.get(key);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
apiByConfig.set(config, api);
|
|
283
|
+
for (const plugin of plugins) {
|
|
284
|
+
await plugin.setup?.(api);
|
|
285
|
+
}
|
|
286
|
+
return api;
|
|
287
|
+
}
|
|
288
|
+
function getPluginApi(config) {
|
|
289
|
+
const api = apiByConfig.get(config);
|
|
290
|
+
if (!api) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
"[nasti] internal: plugin API requested before setup; getPluginApi requires the original ResolvedConfig reference registered by setupPluginApi, not a shallow copy"
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
return api;
|
|
296
|
+
}
|
|
297
|
+
function enforceRank(plugin) {
|
|
298
|
+
if (plugin.enforce === "pre") return 0;
|
|
299
|
+
if (plugin.enforce === "post") return 2;
|
|
300
|
+
return 1;
|
|
301
|
+
}
|
|
302
|
+
var apiByConfig;
|
|
303
|
+
var init_plugin_api = __esm({
|
|
304
|
+
"src/core/plugin-api.ts"() {
|
|
305
|
+
"use strict";
|
|
306
|
+
apiByConfig = /* @__PURE__ */ new WeakMap();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
224
310
|
// src/config/index.ts
|
|
225
311
|
function loadTsconfigPaths(root) {
|
|
226
312
|
const tsconfigPath = import_node_path.default.resolve(root, "tsconfig.json");
|
|
@@ -258,6 +344,43 @@ async function loadConfigFromFile(root) {
|
|
|
258
344
|
}
|
|
259
345
|
return {};
|
|
260
346
|
}
|
|
347
|
+
function detectFramework(root) {
|
|
348
|
+
const sourceRoot = import_node_path.default.resolve(root, "src");
|
|
349
|
+
if (containsVueFile(sourceRoot)) return "vue";
|
|
350
|
+
const packagePath = import_node_path.default.resolve(root, "package.json");
|
|
351
|
+
if (import_node_fs.default.existsSync(packagePath)) {
|
|
352
|
+
try {
|
|
353
|
+
const pkg = JSON.parse(import_node_fs.default.readFileSync(packagePath, "utf-8"));
|
|
354
|
+
const dependencies = {
|
|
355
|
+
...pkg.dependencies ?? {},
|
|
356
|
+
...pkg.devDependencies ?? {},
|
|
357
|
+
...pkg.peerDependencies ?? {},
|
|
358
|
+
...pkg.optionalDependencies ?? {}
|
|
359
|
+
};
|
|
360
|
+
const hasVue = "vue" in dependencies || "@vue/runtime-dom" in dependencies;
|
|
361
|
+
const hasReact = "react" in dependencies || "react-dom" in dependencies;
|
|
362
|
+
if (hasVue && !hasReact) return "vue";
|
|
363
|
+
if (hasReact) return "react";
|
|
364
|
+
if (hasVue) return "vue";
|
|
365
|
+
} catch {
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return "react";
|
|
369
|
+
}
|
|
370
|
+
function containsVueFile(dir, depth = 0) {
|
|
371
|
+
if (depth > 5 || !import_node_fs.default.existsSync(dir)) return false;
|
|
372
|
+
try {
|
|
373
|
+
for (const entry of import_node_fs.default.readdirSync(dir, { withFileTypes: true })) {
|
|
374
|
+
if (entry.isFile() && entry.name.endsWith(".vue")) return true;
|
|
375
|
+
if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== "dist" && containsVueFile(import_node_path.default.join(dir, entry.name), depth + 1)) {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} catch {
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
261
384
|
async function loadTsConfig(filePath) {
|
|
262
385
|
const { transformSync: transformSync2 } = await import("oxc-transform");
|
|
263
386
|
const code = import_node_fs.default.readFileSync(filePath, "utf-8");
|
|
@@ -304,7 +427,7 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
304
427
|
base: merged.base ?? defaults.base,
|
|
305
428
|
mode,
|
|
306
429
|
target: merged.target ?? defaults.target,
|
|
307
|
-
framework: merged.framework ?? defaults.framework,
|
|
430
|
+
framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
|
|
308
431
|
command,
|
|
309
432
|
resolve: {
|
|
310
433
|
// tsconfig paths 优先级最低:tsconfig < defaults < user config
|
|
@@ -351,7 +474,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
351
474
|
if (envOptions.build) Object.assign(resolved.build, envOptions.build);
|
|
352
475
|
resolved.environments.client = {
|
|
353
476
|
consumer,
|
|
354
|
-
|
|
477
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
478
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
479
|
+
html: import_node_path.default.resolve(
|
|
480
|
+
root,
|
|
481
|
+
envOptions.html ?? (resolved.target === "electron" ? resolved.electron.renderer : "index.html")
|
|
482
|
+
),
|
|
483
|
+
driver: envOptions.driver,
|
|
355
484
|
// 同引用 —— 精确镜像(assertClientEnvironmentMirror 校验)
|
|
356
485
|
resolve: resolved.resolve,
|
|
357
486
|
build: resolved.build
|
|
@@ -360,7 +489,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
360
489
|
}
|
|
361
490
|
resolved.environments[name] = {
|
|
362
491
|
consumer,
|
|
363
|
-
|
|
492
|
+
buildEnabled: envOptions.buildEnabled ?? true,
|
|
493
|
+
entry: normalizeEnvironmentEntries(envOptions.entry, root),
|
|
494
|
+
html: envOptions.consumer === "client" && envOptions.html ? import_node_path.default.resolve(root, envOptions.html) : void 0,
|
|
495
|
+
driver: envOptions.driver,
|
|
364
496
|
resolve: {
|
|
365
497
|
alias: { ...resolved.resolve.alias, ...envOptions.resolve?.alias },
|
|
366
498
|
extensions: envOptions.resolve?.extensions ?? [...resolved.resolve.extensions],
|
|
@@ -379,12 +511,13 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
379
511
|
};
|
|
380
512
|
}
|
|
381
513
|
assertClientEnvironmentMirror(resolved);
|
|
382
|
-
const filteredPlugins = rawPlugins.filter((p) => {
|
|
514
|
+
const filteredPlugins = orderPlugins(rawPlugins.filter((p) => {
|
|
383
515
|
if (!p.apply) return true;
|
|
384
516
|
if (typeof p.apply === "function") return p.apply(resolved, env);
|
|
385
517
|
return p.apply === command;
|
|
386
|
-
});
|
|
518
|
+
}));
|
|
387
519
|
resolved.plugins = filteredPlugins;
|
|
520
|
+
await setupPluginApi(resolved, filteredPlugins);
|
|
388
521
|
if (resolved.target === "electron") {
|
|
389
522
|
const autoExternal = detectNativeDeps(root);
|
|
390
523
|
if (autoExternal.length > 0) {
|
|
@@ -400,6 +533,10 @@ async function resolveConfig(inlineConfig = {}, command) {
|
|
|
400
533
|
}
|
|
401
534
|
return resolved;
|
|
402
535
|
}
|
|
536
|
+
function normalizeEnvironmentEntries(entry, root) {
|
|
537
|
+
const entries = Array.isArray(entry) ? entry : entry ? [entry] : [];
|
|
538
|
+
return entries.map((item) => import_node_path.default.resolve(root, item));
|
|
539
|
+
}
|
|
403
540
|
function detectNativeDeps(root) {
|
|
404
541
|
const result = /* @__PURE__ */ new Set();
|
|
405
542
|
const pkgJsonPath = import_node_path.default.resolve(root, "package.json");
|
|
@@ -520,6 +657,7 @@ var init_config = __esm({
|
|
|
520
657
|
import_node_fs = __toESM(require("fs"), 1);
|
|
521
658
|
init_defaults();
|
|
522
659
|
init_logger();
|
|
660
|
+
init_plugin_api();
|
|
523
661
|
CONFIG_FILES = [
|
|
524
662
|
"nasti.config.ts",
|
|
525
663
|
"nasti.config.js",
|
|
@@ -578,6 +716,7 @@ function resolvePlugin(config) {
|
|
|
578
716
|
}
|
|
579
717
|
if (!source.startsWith("/") && !source.startsWith(".")) {
|
|
580
718
|
if (vueRuntimeEntry && source === "vue") return vueRuntimeEntry;
|
|
719
|
+
if (config.command === "build") return null;
|
|
581
720
|
try {
|
|
582
721
|
const resolved = require2.resolve(source, {
|
|
583
722
|
paths: [importer ? import_node_path2.default.dirname(importer) : config.root]
|
|
@@ -713,27 +852,27 @@ var require_process = __commonJS({
|
|
|
713
852
|
var require_filesystem = __commonJS({
|
|
714
853
|
"node_modules/detect-libc/lib/filesystem.js"(exports2, module2) {
|
|
715
854
|
"use strict";
|
|
716
|
-
var
|
|
855
|
+
var fs14 = require("fs");
|
|
717
856
|
var LDD_PATH = "/usr/bin/ldd";
|
|
718
857
|
var SELF_PATH = "/proc/self/exe";
|
|
719
858
|
var MAX_LENGTH = 2048;
|
|
720
|
-
var readFileSync = (
|
|
721
|
-
const fd =
|
|
859
|
+
var readFileSync = (path19) => {
|
|
860
|
+
const fd = fs14.openSync(path19, "r");
|
|
722
861
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
723
|
-
const bytesRead =
|
|
724
|
-
|
|
862
|
+
const bytesRead = fs14.readSync(fd, buffer, 0, MAX_LENGTH, 0);
|
|
863
|
+
fs14.close(fd, () => {
|
|
725
864
|
});
|
|
726
865
|
return buffer.subarray(0, bytesRead);
|
|
727
866
|
};
|
|
728
|
-
var readFile = (
|
|
729
|
-
|
|
867
|
+
var readFile = (path19) => new Promise((resolve, reject) => {
|
|
868
|
+
fs14.open(path19, "r", (err, fd) => {
|
|
730
869
|
if (err) {
|
|
731
870
|
reject(err);
|
|
732
871
|
} else {
|
|
733
872
|
const buffer = Buffer.alloc(MAX_LENGTH);
|
|
734
|
-
|
|
873
|
+
fs14.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
|
|
735
874
|
resolve(buffer.subarray(0, bytesRead));
|
|
736
|
-
|
|
875
|
+
fs14.close(fd, () => {
|
|
737
876
|
});
|
|
738
877
|
});
|
|
739
878
|
}
|
|
@@ -845,11 +984,11 @@ var require_detect_libc = __commonJS({
|
|
|
845
984
|
}
|
|
846
985
|
return null;
|
|
847
986
|
};
|
|
848
|
-
var familyFromInterpreterPath = (
|
|
849
|
-
if (
|
|
850
|
-
if (
|
|
987
|
+
var familyFromInterpreterPath = (path19) => {
|
|
988
|
+
if (path19) {
|
|
989
|
+
if (path19.includes("/ld-musl-")) {
|
|
851
990
|
return MUSL;
|
|
852
|
-
} else if (
|
|
991
|
+
} else if (path19.includes("/ld-linux-")) {
|
|
853
992
|
return GLIBC;
|
|
854
993
|
}
|
|
855
994
|
}
|
|
@@ -896,8 +1035,8 @@ var require_detect_libc = __commonJS({
|
|
|
896
1035
|
cachedFamilyInterpreter = null;
|
|
897
1036
|
try {
|
|
898
1037
|
const selfContent = await readFile(SELF_PATH);
|
|
899
|
-
const
|
|
900
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
1038
|
+
const path19 = interpreterPath(selfContent);
|
|
1039
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path19);
|
|
901
1040
|
} catch (e) {
|
|
902
1041
|
}
|
|
903
1042
|
return cachedFamilyInterpreter;
|
|
@@ -909,8 +1048,8 @@ var require_detect_libc = __commonJS({
|
|
|
909
1048
|
cachedFamilyInterpreter = null;
|
|
910
1049
|
try {
|
|
911
1050
|
const selfContent = readFileSync(SELF_PATH);
|
|
912
|
-
const
|
|
913
|
-
cachedFamilyInterpreter = familyFromInterpreterPath(
|
|
1051
|
+
const path19 = interpreterPath(selfContent);
|
|
1052
|
+
cachedFamilyInterpreter = familyFromInterpreterPath(path19);
|
|
914
1053
|
} catch (e) {
|
|
915
1054
|
}
|
|
916
1055
|
return cachedFamilyInterpreter;
|
|
@@ -1915,7 +2054,8 @@ function transformCode(filename, code, options = {}) {
|
|
|
1915
2054
|
importSource: options.jsxImportSource ?? "react",
|
|
1916
2055
|
refresh: options.reactRefresh ?? false
|
|
1917
2056
|
} : void 0,
|
|
1918
|
-
sourcemap: options.sourcemap ?? true
|
|
2057
|
+
sourcemap: options.sourcemap ?? true,
|
|
2058
|
+
target: options.target
|
|
1919
2059
|
});
|
|
1920
2060
|
if (result.errors && result.errors.length > 0) {
|
|
1921
2061
|
const msg = result.errors.map((e) => e.message ?? String(e)).join("\n");
|
|
@@ -1973,8 +2113,8 @@ function vuePlugin(config) {
|
|
|
1973
2113
|
let descriptor = descriptorCache.get(filePath);
|
|
1974
2114
|
if (!descriptor) {
|
|
1975
2115
|
try {
|
|
1976
|
-
const
|
|
1977
|
-
const source =
|
|
2116
|
+
const fs14 = await import("fs");
|
|
2117
|
+
const source = fs14.readFileSync(filePath, "utf-8");
|
|
1978
2118
|
const parsed = sfc.parse(source, { filename: filePath });
|
|
1979
2119
|
if (parsed.errors.length) return null;
|
|
1980
2120
|
descriptor = parsed.descriptor;
|
|
@@ -2118,7 +2258,7 @@ function htmlPlugin(config) {
|
|
|
2118
2258
|
transformIndexHtml(html) {
|
|
2119
2259
|
const tags = [];
|
|
2120
2260
|
if (config.command === "serve") {
|
|
2121
|
-
const isReactLike = config.framework === "react"
|
|
2261
|
+
const isReactLike = config.framework === "react";
|
|
2122
2262
|
if (isReactLike) {
|
|
2123
2263
|
tags.push({
|
|
2124
2264
|
tag: "script",
|
|
@@ -2172,8 +2312,8 @@ function serializeTag(tag) {
|
|
|
2172
2312
|
}
|
|
2173
2313
|
return ` <${tag.tag}${attrs}>${children}</${tag.tag}>`;
|
|
2174
2314
|
}
|
|
2175
|
-
async function readHtmlFile(root) {
|
|
2176
|
-
const htmlPath = import_node_path6.default.resolve(root,
|
|
2315
|
+
async function readHtmlFile(root, htmlFile = "index.html") {
|
|
2316
|
+
const htmlPath = import_node_path6.default.isAbsolute(htmlFile) ? htmlFile : import_node_path6.default.resolve(root, htmlFile);
|
|
2177
2317
|
if (!import_node_fs4.default.existsSync(htmlPath)) return null;
|
|
2178
2318
|
return import_node_fs4.default.readFileSync(htmlPath, "utf-8");
|
|
2179
2319
|
}
|
|
@@ -2196,16 +2336,27 @@ window.__vite_plugin_react_preamble_installed__ = true;
|
|
|
2196
2336
|
// src/plugins/builtins.ts
|
|
2197
2337
|
function resolvePluginList(config, userPlugins, opts = {}) {
|
|
2198
2338
|
const isServe = config.command === "serve";
|
|
2339
|
+
let environmentOptions;
|
|
2340
|
+
if (opts.environmentName) {
|
|
2341
|
+
environmentOptions = config.environments[opts.environmentName];
|
|
2342
|
+
if (!environmentOptions) {
|
|
2343
|
+
throw new Error(
|
|
2344
|
+
`[nasti] unknown environment "${opts.environmentName}" \u2014 declare it in config.environments`
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
const pluginConfig = environmentOptions ? { ...config, resolve: environmentOptions.resolve, build: environmentOptions.build } : config;
|
|
2349
|
+
const consumer = opts.consumer ?? environmentOptions?.consumer;
|
|
2199
2350
|
return [
|
|
2200
2351
|
// vuePlugin 排最前(enforce: 'pre' 语义):.vue 先编译成 JS 再走后续管道
|
|
2201
|
-
...config.framework === "vue" ? [vuePlugin(
|
|
2202
|
-
resolvePlugin(
|
|
2203
|
-
cssPlugin(
|
|
2204
|
-
assetsPlugin(
|
|
2205
|
-
...isServe ? [htmlPlugin(
|
|
2352
|
+
...config.framework === "vue" ? [vuePlugin(pluginConfig)] : [],
|
|
2353
|
+
resolvePlugin(pluginConfig),
|
|
2354
|
+
cssPlugin(pluginConfig, opts.cssEngine, consumer),
|
|
2355
|
+
assetsPlugin(pluginConfig),
|
|
2356
|
+
...isServe ? [htmlPlugin(pluginConfig)] : [],
|
|
2206
2357
|
...userPlugins,
|
|
2207
2358
|
// cssPostPlugin 最后(enforce: 'post' 语义):renderChunk 聚合抽取
|
|
2208
|
-
...!isServe && opts.cssEngine ? [cssPostPlugin(
|
|
2359
|
+
...!isServe && opts.cssEngine ? [cssPostPlugin(pluginConfig, opts.cssEngine)] : []
|
|
2209
2360
|
];
|
|
2210
2361
|
}
|
|
2211
2362
|
var init_builtins = __esm({
|
|
@@ -2221,21 +2372,11 @@ var init_builtins = __esm({
|
|
|
2221
2372
|
});
|
|
2222
2373
|
|
|
2223
2374
|
// src/core/plugin-container.ts
|
|
2224
|
-
function sortPlugins(plugins) {
|
|
2225
|
-
const pre = [];
|
|
2226
|
-
const normal = [];
|
|
2227
|
-
const post = [];
|
|
2228
|
-
for (const plugin of plugins) {
|
|
2229
|
-
if (plugin.enforce === "pre") pre.push(plugin);
|
|
2230
|
-
else if (plugin.enforce === "post") post.push(plugin);
|
|
2231
|
-
else normal.push(plugin);
|
|
2232
|
-
}
|
|
2233
|
-
return [...pre, ...normal, ...post];
|
|
2234
|
-
}
|
|
2235
2375
|
var PluginContainer;
|
|
2236
2376
|
var init_plugin_container = __esm({
|
|
2237
2377
|
"src/core/plugin-container.ts"() {
|
|
2238
2378
|
"use strict";
|
|
2379
|
+
init_plugin_api();
|
|
2239
2380
|
PluginContainer = class {
|
|
2240
2381
|
plugins;
|
|
2241
2382
|
config;
|
|
@@ -2246,7 +2387,7 @@ var init_plugin_container = __esm({
|
|
|
2246
2387
|
constructor(config, environment) {
|
|
2247
2388
|
this.config = config;
|
|
2248
2389
|
this.environment = environment;
|
|
2249
|
-
this.plugins =
|
|
2390
|
+
this.plugins = orderPlugins(config.plugins);
|
|
2250
2391
|
this.ctx = this.createContext();
|
|
2251
2392
|
}
|
|
2252
2393
|
createContext() {
|
|
@@ -2345,17 +2486,35 @@ var init_plugin_container = __esm({
|
|
|
2345
2486
|
}
|
|
2346
2487
|
});
|
|
2347
2488
|
|
|
2489
|
+
// src/core/url.ts
|
|
2490
|
+
function removeTimestampQuery(url) {
|
|
2491
|
+
const hashIndex = url.indexOf("#");
|
|
2492
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
2493
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
2494
|
+
const queryIndex = withoutHash.indexOf("?");
|
|
2495
|
+
if (queryIndex < 0) return url;
|
|
2496
|
+
const pathname = withoutHash.slice(0, queryIndex);
|
|
2497
|
+
const query = withoutHash.slice(queryIndex + 1).split("&").filter((part) => !/^t=\d+$/.test(part)).join("&");
|
|
2498
|
+
return pathname + (query ? `?${query}` : "") + hash;
|
|
2499
|
+
}
|
|
2500
|
+
var init_url = __esm({
|
|
2501
|
+
"src/core/url.ts"() {
|
|
2502
|
+
"use strict";
|
|
2503
|
+
}
|
|
2504
|
+
});
|
|
2505
|
+
|
|
2348
2506
|
// src/core/module-graph.ts
|
|
2349
2507
|
var ModuleGraph;
|
|
2350
2508
|
var init_module_graph = __esm({
|
|
2351
2509
|
"src/core/module-graph.ts"() {
|
|
2352
2510
|
"use strict";
|
|
2511
|
+
init_url();
|
|
2353
2512
|
ModuleGraph = class {
|
|
2354
2513
|
urlToModuleMap = /* @__PURE__ */ new Map();
|
|
2355
2514
|
idToModuleMap = /* @__PURE__ */ new Map();
|
|
2356
2515
|
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
2357
2516
|
getModuleByUrl(url) {
|
|
2358
|
-
return this.urlToModuleMap.get(url);
|
|
2517
|
+
return this.urlToModuleMap.get(removeTimestampQuery(url));
|
|
2359
2518
|
}
|
|
2360
2519
|
getModuleById(id) {
|
|
2361
2520
|
return this.idToModuleMap.get(id);
|
|
@@ -2364,10 +2523,11 @@ var init_module_graph = __esm({
|
|
|
2364
2523
|
return this.fileToModulesMap.get(file);
|
|
2365
2524
|
}
|
|
2366
2525
|
async ensureEntryFromUrl(url) {
|
|
2367
|
-
|
|
2526
|
+
const normalizedUrl = removeTimestampQuery(url);
|
|
2527
|
+
let mod = this.urlToModuleMap.get(normalizedUrl);
|
|
2368
2528
|
if (mod) return mod;
|
|
2369
|
-
mod = this.createModule(
|
|
2370
|
-
this.urlToModuleMap.set(
|
|
2529
|
+
mod = this.createModule(normalizedUrl);
|
|
2530
|
+
this.urlToModuleMap.set(normalizedUrl, mod);
|
|
2371
2531
|
return mod;
|
|
2372
2532
|
}
|
|
2373
2533
|
createModule(url, id) {
|
|
@@ -2381,6 +2541,7 @@ var init_module_graph = __esm({
|
|
|
2381
2541
|
acceptedHmrDeps: /* @__PURE__ */ new Set(),
|
|
2382
2542
|
transformResult: null,
|
|
2383
2543
|
lastHMRTimestamp: 0,
|
|
2544
|
+
invalidationVersion: 0,
|
|
2384
2545
|
isSelfAccepting: false
|
|
2385
2546
|
};
|
|
2386
2547
|
this.idToModuleMap.set(mod.id, mod);
|
|
@@ -2423,10 +2584,64 @@ var init_module_graph = __esm({
|
|
|
2423
2584
|
}
|
|
2424
2585
|
}
|
|
2425
2586
|
}
|
|
2587
|
+
/**
|
|
2588
|
+
* 用一次转换得到的信息原子更新 import 与 HMR accept 关系。
|
|
2589
|
+
* 依赖节点会在真正被浏览器请求前预先创建,这样入口模块先转换时也能建立完整图。
|
|
2590
|
+
*/
|
|
2591
|
+
async updateModuleInfo(mod, importedUrls, acceptedUrls, isSelfAccepting, expectedInvalidationVersion) {
|
|
2592
|
+
const importedModules = await Promise.all(
|
|
2593
|
+
[...importedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
2594
|
+
);
|
|
2595
|
+
const acceptedModules = await Promise.all(
|
|
2596
|
+
[...acceptedUrls].map((url) => this.ensureEntryFromUrl(url))
|
|
2597
|
+
);
|
|
2598
|
+
if (expectedInvalidationVersion !== void 0 && mod.invalidationVersion !== expectedInvalidationVersion) {
|
|
2599
|
+
return null;
|
|
2600
|
+
}
|
|
2601
|
+
const previousImports = new Set(mod.importedModules);
|
|
2602
|
+
for (const imported of previousImports) {
|
|
2603
|
+
imported.importers.delete(mod);
|
|
2604
|
+
}
|
|
2605
|
+
mod.importedModules.clear();
|
|
2606
|
+
mod.acceptedHmrDeps.clear();
|
|
2607
|
+
for (const imported of importedModules) {
|
|
2608
|
+
mod.importedModules.add(imported);
|
|
2609
|
+
imported.importers.add(mod);
|
|
2610
|
+
}
|
|
2611
|
+
for (const accepted of acceptedModules) {
|
|
2612
|
+
mod.acceptedHmrDeps.add(accepted);
|
|
2613
|
+
}
|
|
2614
|
+
mod.isSelfAccepting = isSelfAccepting;
|
|
2615
|
+
const pruned = /* @__PURE__ */ new Set();
|
|
2616
|
+
for (const imported of previousImports) {
|
|
2617
|
+
if (!mod.importedModules.has(imported) && imported.importers.size === 0) {
|
|
2618
|
+
pruned.add(imported);
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
return pruned;
|
|
2622
|
+
}
|
|
2426
2623
|
/** 使模块的转换缓存失效 */
|
|
2427
|
-
invalidateModule(mod) {
|
|
2624
|
+
invalidateModule(mod, timestamp = Date.now()) {
|
|
2428
2625
|
mod.transformResult = null;
|
|
2429
|
-
mod.lastHMRTimestamp =
|
|
2626
|
+
mod.lastHMRTimestamp = timestamp;
|
|
2627
|
+
mod.invalidationVersion++;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* 仅失效到 HMR 边界:显式接受依赖的模块本身不会重执行;自接受模块需要失效,
|
|
2631
|
+
* 但不再继续影响其 importer。这样既能传播依赖时间戳,也不会隐式重复副作用。
|
|
2632
|
+
*/
|
|
2633
|
+
invalidateModuleAndImporters(mod, timestamp = Date.now(), seen = /* @__PURE__ */ new Set()) {
|
|
2634
|
+
if (seen.has(mod)) return;
|
|
2635
|
+
seen.add(mod);
|
|
2636
|
+
this.invalidateModule(mod, timestamp);
|
|
2637
|
+
for (const importer of mod.importers) {
|
|
2638
|
+
if (importer.acceptedHmrDeps.has(mod)) continue;
|
|
2639
|
+
if (importer.isSelfAccepting) {
|
|
2640
|
+
this.invalidateModule(importer, timestamp);
|
|
2641
|
+
continue;
|
|
2642
|
+
}
|
|
2643
|
+
this.invalidateModuleAndImporters(importer, timestamp, seen);
|
|
2644
|
+
}
|
|
2430
2645
|
}
|
|
2431
2646
|
/** 使所有模块缓存失效 */
|
|
2432
2647
|
invalidateAll() {
|
|
@@ -2437,34 +2652,32 @@ var init_module_graph = __esm({
|
|
|
2437
2652
|
/** 获取 HMR 传播边界 - 从变更模块向上遍历找到接受更新的边界 */
|
|
2438
2653
|
getHmrBoundaries(mod) {
|
|
2439
2654
|
const boundaries = [];
|
|
2440
|
-
const
|
|
2441
|
-
const
|
|
2442
|
-
if (
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
boundaries.push({ boundary
|
|
2446
|
-
return true;
|
|
2655
|
+
const traversed = /* @__PURE__ */ new Set();
|
|
2656
|
+
const addBoundary = (boundary, acceptedVia) => {
|
|
2657
|
+
if (!boundaries.some(
|
|
2658
|
+
(item) => item.boundary === boundary && item.acceptedVia === acceptedVia
|
|
2659
|
+
)) {
|
|
2660
|
+
boundaries.push({ boundary, acceptedVia });
|
|
2447
2661
|
}
|
|
2448
|
-
|
|
2449
|
-
|
|
2662
|
+
};
|
|
2663
|
+
const propagate = (node) => {
|
|
2664
|
+
if (traversed.has(node)) return true;
|
|
2665
|
+
traversed.add(node);
|
|
2666
|
+
if (node.isSelfAccepting) {
|
|
2667
|
+
addBoundary(node, node);
|
|
2450
2668
|
return true;
|
|
2451
2669
|
}
|
|
2452
2670
|
if (node.importers.size === 0) return false;
|
|
2453
2671
|
for (const importer of node.importers) {
|
|
2454
|
-
if (
|
|
2672
|
+
if (importer.acceptedHmrDeps.has(node)) {
|
|
2673
|
+
addBoundary(importer, node);
|
|
2674
|
+
continue;
|
|
2675
|
+
}
|
|
2676
|
+
if (!propagate(importer)) return false;
|
|
2455
2677
|
}
|
|
2456
2678
|
return true;
|
|
2457
2679
|
};
|
|
2458
|
-
|
|
2459
|
-
boundaries.push({ boundary: mod, acceptedVia: mod });
|
|
2460
|
-
return boundaries;
|
|
2461
|
-
}
|
|
2462
|
-
for (const importer of mod.importers) {
|
|
2463
|
-
if (!propagate(importer, mod)) {
|
|
2464
|
-
return [];
|
|
2465
|
-
}
|
|
2466
|
-
}
|
|
2467
|
-
return boundaries;
|
|
2680
|
+
return propagate(mod) ? boundaries : [];
|
|
2468
2681
|
}
|
|
2469
2682
|
};
|
|
2470
2683
|
}
|
|
@@ -2542,6 +2755,7 @@ var init_environment = __esm({
|
|
|
2542
2755
|
init_module_graph();
|
|
2543
2756
|
init_hot_channel();
|
|
2544
2757
|
init_debug();
|
|
2758
|
+
init_plugin_api();
|
|
2545
2759
|
debug2 = createDebugger("nasti:environment");
|
|
2546
2760
|
NastiEnvironment = class {
|
|
2547
2761
|
name;
|
|
@@ -2550,6 +2764,7 @@ var init_environment = __esm({
|
|
|
2550
2764
|
config;
|
|
2551
2765
|
options;
|
|
2552
2766
|
hot;
|
|
2767
|
+
driver;
|
|
2553
2768
|
/** applyToEnvironment 过滤后的插件(init() 后可用) */
|
|
2554
2769
|
plugins = [];
|
|
2555
2770
|
/** per-env 插件容器(init() 后可用;dev 管线使用) */
|
|
@@ -2557,6 +2772,8 @@ var init_environment = __esm({
|
|
|
2557
2772
|
/** per-env 模块图(dev 管线使用) */
|
|
2558
2773
|
moduleGraph;
|
|
2559
2774
|
candidatePlugins;
|
|
2775
|
+
pluginApi;
|
|
2776
|
+
buildMetadata = {};
|
|
2560
2777
|
initialized = false;
|
|
2561
2778
|
constructor(name, config, init = {}) {
|
|
2562
2779
|
const options = config.environments[name];
|
|
@@ -2573,6 +2790,7 @@ var init_environment = __esm({
|
|
|
2573
2790
|
this.hot = init.hot ?? createNoopHotChannel();
|
|
2574
2791
|
this.moduleGraph = new ModuleGraph();
|
|
2575
2792
|
this.candidatePlugins = init.plugins ?? config.plugins;
|
|
2793
|
+
this.pluginApi = init.pluginApi ?? getPluginApi(config);
|
|
2576
2794
|
}
|
|
2577
2795
|
/** 过滤插件并建 per-env PluginContainer */
|
|
2578
2796
|
async init() {
|
|
@@ -2583,10 +2801,57 @@ var init_environment = __esm({
|
|
|
2583
2801
|
{ ...this.config, plugins: this.plugins },
|
|
2584
2802
|
this
|
|
2585
2803
|
);
|
|
2804
|
+
if (this.options.driver) {
|
|
2805
|
+
const claimed = [];
|
|
2806
|
+
for (const plugin of this.plugins) {
|
|
2807
|
+
const driver = await plugin.createEnvironmentDriver?.(this, this.pluginApi);
|
|
2808
|
+
if (driver) claimed.push({ plugin, driver });
|
|
2809
|
+
}
|
|
2810
|
+
if (claimed.length === 0) {
|
|
2811
|
+
throw new Error(
|
|
2812
|
+
`[nasti] environment "${this.name}" requested driver "${this.options.driver}", but no plugin provided it`
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
if (claimed.length > 1) {
|
|
2816
|
+
throw new Error(
|
|
2817
|
+
`[nasti] environment "${this.name}" was claimed by multiple drivers: ` + claimed.map(({ plugin, driver }) => `${plugin.name} (${driver.name})`).join(", ")
|
|
2818
|
+
);
|
|
2819
|
+
}
|
|
2820
|
+
this.driver = claimed[0].driver;
|
|
2821
|
+
debug2?.(`env "${this.name}" uses driver "${this.driver.name}"`);
|
|
2822
|
+
}
|
|
2586
2823
|
debug2?.(`env "${this.name}" initialized (${this.plugins.length} plugins)`);
|
|
2587
2824
|
}
|
|
2825
|
+
getDriverContext() {
|
|
2826
|
+
return {
|
|
2827
|
+
environment: this,
|
|
2828
|
+
config: this.config,
|
|
2829
|
+
api: this.pluginApi,
|
|
2830
|
+
logger: this.config.logger
|
|
2831
|
+
};
|
|
2832
|
+
}
|
|
2833
|
+
setBuildMetadata(metadata) {
|
|
2834
|
+
const { entries: currentEntries, ...currentMetadata } = this.buildMetadata;
|
|
2835
|
+
const { entries, ...nextMetadata } = metadata;
|
|
2836
|
+
this.buildMetadata = {
|
|
2837
|
+
...currentMetadata,
|
|
2838
|
+
...nextMetadata,
|
|
2839
|
+
...currentEntries || entries ? { entries: { ...currentEntries, ...entries } } : {}
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
getBuildMetadata() {
|
|
2843
|
+
const { entries, ...metadata } = this.buildMetadata;
|
|
2844
|
+
return {
|
|
2845
|
+
...metadata,
|
|
2846
|
+
...entries ? { entries: { ...entries } } : {}
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2588
2849
|
async close() {
|
|
2589
|
-
|
|
2850
|
+
try {
|
|
2851
|
+
await this.driver?.close?.(this.getDriverContext());
|
|
2852
|
+
} finally {
|
|
2853
|
+
await this.hot.close?.();
|
|
2854
|
+
}
|
|
2590
2855
|
}
|
|
2591
2856
|
};
|
|
2592
2857
|
}
|
|
@@ -2746,11 +3011,141 @@ var init_reporter = __esm({
|
|
|
2746
3011
|
}
|
|
2747
3012
|
});
|
|
2748
3013
|
|
|
3014
|
+
// src/core/build-app-context.ts
|
|
3015
|
+
function createBuildAppContext(config, results) {
|
|
3016
|
+
const output = [];
|
|
3017
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
3018
|
+
const outDir = import_node_path9.default.resolve(config.root, config.build.outDir);
|
|
3019
|
+
let environmentArtifacts;
|
|
3020
|
+
return {
|
|
3021
|
+
config,
|
|
3022
|
+
results,
|
|
3023
|
+
get output() {
|
|
3024
|
+
return Object.freeze([...output]);
|
|
3025
|
+
},
|
|
3026
|
+
getResult(environmentName) {
|
|
3027
|
+
return results[environmentName];
|
|
3028
|
+
},
|
|
3029
|
+
getArtifact(environmentName, fileName) {
|
|
3030
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3031
|
+
return results[environmentName]?.output.find(
|
|
3032
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalized
|
|
3033
|
+
);
|
|
3034
|
+
},
|
|
3035
|
+
getEntry(environmentName, entryName) {
|
|
3036
|
+
const result = results[environmentName];
|
|
3037
|
+
const fileName = result?.entries?.[entryName];
|
|
3038
|
+
if (!fileName) return void 0;
|
|
3039
|
+
return result.output.find(
|
|
3040
|
+
(artifact) => normalizeEnvironmentFileName(artifact.fileName) === normalizeEnvironmentFileName(fileName)
|
|
3041
|
+
);
|
|
3042
|
+
},
|
|
3043
|
+
getManifest(environmentName) {
|
|
3044
|
+
return results[environmentName]?.manifest;
|
|
3045
|
+
},
|
|
3046
|
+
emitFile(file) {
|
|
3047
|
+
const fileName = normalizeAppFileName(file.fileName);
|
|
3048
|
+
const collisionKey = artifactCollisionKey(fileName);
|
|
3049
|
+
if (emitted.has(collisionKey)) {
|
|
3050
|
+
throw new Error(`[nasti] app artifact already emitted: ${fileName}`);
|
|
3051
|
+
}
|
|
3052
|
+
environmentArtifacts ??= collectEnvironmentArtifacts(config, results, outDir);
|
|
3053
|
+
if (environmentArtifacts.has(collisionKey)) {
|
|
3054
|
+
throw new Error(`[nasti] app artifact conflicts with environment output: ${fileName}`);
|
|
3055
|
+
}
|
|
3056
|
+
const target = import_node_path9.default.resolve(outDir, ...fileName.split("/"));
|
|
3057
|
+
const relative = import_node_path9.default.relative(outDir, target);
|
|
3058
|
+
if (relative.startsWith("..") || import_node_path9.default.isAbsolute(relative)) {
|
|
3059
|
+
throw new Error(`[nasti] app artifact must stay inside build.outDir: ${file.fileName}`);
|
|
3060
|
+
}
|
|
3061
|
+
assertNoSymlinkComponents(outDir, fileName);
|
|
3062
|
+
import_node_fs6.default.mkdirSync(import_node_path9.default.dirname(target), { recursive: true });
|
|
3063
|
+
import_node_fs6.default.writeFileSync(target, file.source);
|
|
3064
|
+
const artifact = {
|
|
3065
|
+
...file,
|
|
3066
|
+
fileName,
|
|
3067
|
+
type: "asset"
|
|
3068
|
+
};
|
|
3069
|
+
emitted.add(collisionKey);
|
|
3070
|
+
output.push(artifact);
|
|
3071
|
+
return fileName;
|
|
3072
|
+
}
|
|
3073
|
+
};
|
|
3074
|
+
}
|
|
3075
|
+
function normalizeEnvironmentFileName(fileName) {
|
|
3076
|
+
return import_node_path9.default.posix.normalize(fileName.replace(/\\/g, "/").replace(/^\.\//, ""));
|
|
3077
|
+
}
|
|
3078
|
+
function isInvalidEnvironmentFileName(fileName) {
|
|
3079
|
+
return !fileName || fileName === "." || fileName === ".." || fileName.startsWith("../") || import_node_path9.default.posix.isAbsolute(fileName) || /^[A-Za-z]:\//.test(fileName);
|
|
3080
|
+
}
|
|
3081
|
+
function normalizeAppFileName(fileName) {
|
|
3082
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3083
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
3084
|
+
throw new Error(`[nasti] invalid app artifact fileName: ${fileName}`);
|
|
3085
|
+
}
|
|
3086
|
+
return normalized;
|
|
3087
|
+
}
|
|
3088
|
+
function artifactCollisionKey(fileName) {
|
|
3089
|
+
return normalizeEnvironmentFileName(fileName).toLowerCase();
|
|
3090
|
+
}
|
|
3091
|
+
function collectEnvironmentArtifacts(config, results, appOutDir) {
|
|
3092
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
3093
|
+
for (const [environmentName, result] of Object.entries(results)) {
|
|
3094
|
+
const environment = config.environments[environmentName];
|
|
3095
|
+
if (!environment) continue;
|
|
3096
|
+
const environmentOutDir = import_node_path9.default.resolve(config.root, environment.build.outDir);
|
|
3097
|
+
for (const artifact of result.output) {
|
|
3098
|
+
const artifactPath = import_node_path9.default.resolve(
|
|
3099
|
+
environmentOutDir,
|
|
3100
|
+
...normalizeEnvironmentFileName(artifact.fileName).split("/")
|
|
3101
|
+
);
|
|
3102
|
+
const relative = import_node_path9.default.relative(appOutDir, artifactPath);
|
|
3103
|
+
if (!relative.startsWith("..") && !import_node_path9.default.isAbsolute(relative)) {
|
|
3104
|
+
occupied.add(artifactCollisionKey(relative));
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
return occupied;
|
|
3109
|
+
}
|
|
3110
|
+
function assertNoSymlinkComponents(outDir, fileName) {
|
|
3111
|
+
let current = outDir;
|
|
3112
|
+
for (const segment of fileName.split("/")) {
|
|
3113
|
+
current = import_node_path9.default.join(current, segment);
|
|
3114
|
+
let stats;
|
|
3115
|
+
try {
|
|
3116
|
+
stats = import_node_fs6.default.lstatSync(current);
|
|
3117
|
+
} catch (error) {
|
|
3118
|
+
if (error.code === "ENOENT") continue;
|
|
3119
|
+
throw error;
|
|
3120
|
+
}
|
|
3121
|
+
if (stats.isSymbolicLink()) {
|
|
3122
|
+
throw new Error(`[nasti] app artifact path cannot traverse a symlink: ${fileName}`);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
function inferEnvironmentEntries(output) {
|
|
3127
|
+
const entries = {};
|
|
3128
|
+
for (const artifact of output) {
|
|
3129
|
+
if (artifact.type !== "chunk" || !artifact.isEntry || !artifact.name) continue;
|
|
3130
|
+
entries[artifact.name] = normalizeEnvironmentFileName(artifact.fileName);
|
|
3131
|
+
}
|
|
3132
|
+
return Object.keys(entries).length > 0 ? entries : void 0;
|
|
3133
|
+
}
|
|
3134
|
+
var import_node_fs6, import_node_path9;
|
|
3135
|
+
var init_build_app_context = __esm({
|
|
3136
|
+
"src/core/build-app-context.ts"() {
|
|
3137
|
+
"use strict";
|
|
3138
|
+
import_node_fs6 = __toESM(require("fs"), 1);
|
|
3139
|
+
import_node_path9 = __toESM(require("path"), 1);
|
|
3140
|
+
}
|
|
3141
|
+
});
|
|
3142
|
+
|
|
2749
3143
|
// src/build/index.ts
|
|
2750
3144
|
var build_exports = {};
|
|
2751
3145
|
__export(build_exports, {
|
|
2752
3146
|
build: () => build,
|
|
2753
3147
|
getRolldownOptions: () => getRolldownOptions,
|
|
3148
|
+
replaceEntryScript: () => replaceEntryScript,
|
|
2754
3149
|
resolveClientEntries: () => resolveClientEntries,
|
|
2755
3150
|
toRolldownPlugins: () => toRolldownPlugins
|
|
2756
3151
|
});
|
|
@@ -2758,9 +3153,14 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2758
3153
|
const config = environment.config;
|
|
2759
3154
|
const envOptions = environment.options;
|
|
2760
3155
|
const isServer = environment.consumer === "server";
|
|
2761
|
-
const outDir =
|
|
3156
|
+
const outDir = import_node_path10.default.resolve(config.root, envOptions.build.outDir);
|
|
2762
3157
|
const assetsDir = envOptions.build.assetsDir;
|
|
2763
|
-
const {
|
|
3158
|
+
const {
|
|
3159
|
+
output: userOutput,
|
|
3160
|
+
transform: userTransform,
|
|
3161
|
+
resolve: userResolve,
|
|
3162
|
+
...restInputOptions
|
|
3163
|
+
} = envOptions.build.rolldownOptions;
|
|
2764
3164
|
const vueDefine = config.framework === "vue" ? {
|
|
2765
3165
|
__VUE_OPTIONS_API__: "true",
|
|
2766
3166
|
__VUE_PROD_DEVTOOLS__: "false",
|
|
@@ -2774,19 +3174,22 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2774
3174
|
input: entryPoints,
|
|
2775
3175
|
transform: { ...userTransform, define: mergedDefine },
|
|
2776
3176
|
plugins: rolldownPlugins,
|
|
3177
|
+
// client/server consumer 都必须使用当前环境的 conditions/mainFields;Lynx
|
|
3178
|
+
// BG/MT 通常同为 client consumer,但仍可能声明不同的运行时条件。
|
|
3179
|
+
resolve: {
|
|
3180
|
+
...userResolve ?? {},
|
|
3181
|
+
// Environment API 是条件解析的唯一高层入口,优先于继承来的底层选项。
|
|
3182
|
+
conditionNames: envOptions.resolve.conditions,
|
|
3183
|
+
mainFields: envOptions.resolve.mainFields
|
|
3184
|
+
},
|
|
2777
3185
|
...isServer ? {
|
|
2778
3186
|
platform: restInputOptions.platform ?? "node",
|
|
2779
|
-
resolve: {
|
|
2780
|
-
conditionNames: envOptions.resolve.conditions,
|
|
2781
|
-
mainFields: envOptions.resolve.mainFields,
|
|
2782
|
-
...restInputOptions.resolve
|
|
2783
|
-
},
|
|
2784
3187
|
// server 产物:node 内建恒外部化;bare specifier 默认外部化
|
|
2785
3188
|
//(同 Vite ssr.external 默认 —— 依赖由 node_modules 运行时解析),
|
|
2786
3189
|
// 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
|
|
2787
3190
|
external: restInputOptions.external ?? ((id) => {
|
|
2788
3191
|
if (NODE_BUILTINS.has(id)) return true;
|
|
2789
|
-
return !id.startsWith(".") && !
|
|
3192
|
+
return !id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0");
|
|
2790
3193
|
})
|
|
2791
3194
|
} : {}
|
|
2792
3195
|
};
|
|
@@ -2813,37 +3216,139 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
|
|
|
2813
3216
|
};
|
|
2814
3217
|
return { inputOptions, outputOptions, outDir };
|
|
2815
3218
|
}
|
|
2816
|
-
function toRolldownPlugins(plugins) {
|
|
3219
|
+
function toRolldownPlugins(plugins, environment) {
|
|
3220
|
+
const wrap = (hook) => {
|
|
3221
|
+
if (!hook) return hook;
|
|
3222
|
+
return function(...args) {
|
|
3223
|
+
return hook.apply(attachEnvironment(this, environment), args);
|
|
3224
|
+
};
|
|
3225
|
+
};
|
|
2817
3226
|
return plugins.map((p) => ({
|
|
2818
3227
|
name: p.name,
|
|
2819
|
-
resolveId: p.resolveId,
|
|
2820
|
-
load: p.load,
|
|
2821
|
-
transform: p.transform,
|
|
2822
|
-
buildStart: p.buildStart,
|
|
2823
|
-
buildEnd: p.buildEnd,
|
|
3228
|
+
resolveId: wrap(p.resolveId),
|
|
3229
|
+
load: wrap(p.load),
|
|
3230
|
+
transform: wrap(p.transform),
|
|
3231
|
+
buildStart: wrap(p.buildStart),
|
|
3232
|
+
buildEnd: wrap(p.buildEnd),
|
|
2824
3233
|
// closeBundle 在 bundle.close() 时触发 —— PWA manifest/SW 等终态产物依赖
|
|
2825
|
-
closeBundle: p.closeBundle,
|
|
2826
|
-
renderChunk: p.renderChunk,
|
|
2827
|
-
augmentChunkHash: p.augmentChunkHash,
|
|
2828
|
-
generateBundle: p.generateBundle
|
|
3234
|
+
closeBundle: wrap(p.closeBundle),
|
|
3235
|
+
renderChunk: wrap(p.renderChunk),
|
|
3236
|
+
augmentChunkHash: wrap(p.augmentChunkHash),
|
|
3237
|
+
generateBundle: wrap(p.generateBundle)
|
|
2829
3238
|
}));
|
|
2830
3239
|
}
|
|
3240
|
+
function attachEnvironment(context, environment) {
|
|
3241
|
+
if (context?.environment === environment) return context;
|
|
3242
|
+
try {
|
|
3243
|
+
Object.defineProperty(context, "environment", {
|
|
3244
|
+
configurable: true,
|
|
3245
|
+
enumerable: false,
|
|
3246
|
+
writable: false,
|
|
3247
|
+
value: environment
|
|
3248
|
+
});
|
|
3249
|
+
return context;
|
|
3250
|
+
} catch {
|
|
3251
|
+
return new Proxy(context, {
|
|
3252
|
+
get(target, property) {
|
|
3253
|
+
if (property === "environment") return environment;
|
|
3254
|
+
const value = Reflect.get(target, property, target);
|
|
3255
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
3256
|
+
},
|
|
3257
|
+
set(target, property, value) {
|
|
3258
|
+
return Reflect.set(target, property, value, target);
|
|
3259
|
+
}
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
function finalizeEnvironmentResult(environment, result) {
|
|
3264
|
+
const metadata = environment.getBuildMetadata();
|
|
3265
|
+
const inferredEntries = inferEnvironmentEntries(result.output);
|
|
3266
|
+
const entries = {
|
|
3267
|
+
...inferredEntries,
|
|
3268
|
+
...metadata.entries,
|
|
3269
|
+
...result.entries
|
|
3270
|
+
};
|
|
3271
|
+
const normalizedEntries = Object.fromEntries(
|
|
3272
|
+
Object.entries(entries).map(([name, fileName]) => {
|
|
3273
|
+
const normalized = normalizeEnvironmentFileName(fileName);
|
|
3274
|
+
if (isInvalidEnvironmentFileName(normalized)) {
|
|
3275
|
+
throw new Error(
|
|
3276
|
+
`[nasti] environment "${environment.name}" returned invalid entry "${name}": ${fileName}`
|
|
3277
|
+
);
|
|
3278
|
+
}
|
|
3279
|
+
return [name, normalized];
|
|
3280
|
+
})
|
|
3281
|
+
);
|
|
3282
|
+
return {
|
|
3283
|
+
...metadata,
|
|
3284
|
+
...result,
|
|
3285
|
+
output: result.output,
|
|
3286
|
+
...Object.keys(normalizedEntries).length > 0 ? { entries: normalizedEntries } : {}
|
|
3287
|
+
};
|
|
3288
|
+
}
|
|
3289
|
+
function prepareBuildOutputDirectories(config, buildableNames) {
|
|
3290
|
+
const directories = /* @__PURE__ */ new Set();
|
|
3291
|
+
const protectedPaths = /* @__PURE__ */ new Set();
|
|
3292
|
+
const clientIsBuilt = buildableNames.includes("client");
|
|
3293
|
+
if (!clientIsBuilt && config.build.emptyOutDir) {
|
|
3294
|
+
directories.add(import_node_path10.default.resolve(config.root, config.build.outDir));
|
|
3295
|
+
}
|
|
3296
|
+
for (const name of buildableNames) {
|
|
3297
|
+
const environment = config.environments[name];
|
|
3298
|
+
const outDir = import_node_path10.default.resolve(config.root, environment.build.outDir);
|
|
3299
|
+
if (!environment.build.emptyOutDir) {
|
|
3300
|
+
protectedPaths.add(outDir);
|
|
3301
|
+
continue;
|
|
3302
|
+
}
|
|
3303
|
+
if (!environment.driver) directories.add(outDir);
|
|
3304
|
+
}
|
|
3305
|
+
const containsPath = (parent, child) => {
|
|
3306
|
+
const relative = import_node_path10.default.relative(parent, child);
|
|
3307
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path10.default.isAbsolute(relative);
|
|
3308
|
+
};
|
|
3309
|
+
const roots = [...directories].filter(
|
|
3310
|
+
(directory) => ![...protectedPaths].some((protectedPath) => containsPath(directory, protectedPath))
|
|
3311
|
+
).sort((a, b) => a.length - b.length).filter(
|
|
3312
|
+
(directory, index2, all) => !all.slice(0, index2).some((parent) => containsPath(parent, directory))
|
|
3313
|
+
);
|
|
3314
|
+
for (const directory of roots) {
|
|
3315
|
+
if (import_node_fs7.default.existsSync(directory)) import_node_fs7.default.rmSync(directory, { recursive: true, force: true });
|
|
3316
|
+
}
|
|
3317
|
+
}
|
|
3318
|
+
function assertDriverBuildResult(environment, result) {
|
|
3319
|
+
const output = result != null && typeof result === "object" ? result.output : void 0;
|
|
3320
|
+
const hasValidOutput = Array.isArray(output) && output.every(
|
|
3321
|
+
(artifact) => artifact != null && typeof artifact === "object" && typeof artifact.fileName === "string" && typeof artifact.type === "string"
|
|
3322
|
+
);
|
|
3323
|
+
if (!hasValidOutput) {
|
|
3324
|
+
throw new Error(
|
|
3325
|
+
`[nasti] environment "${environment.name}" driver "${environment.driver?.name}" returned an invalid build result; expected { output: EnvironmentBuildOutput[] }`
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
2831
3329
|
function resolveClientEntries(config, html) {
|
|
3330
|
+
const configuredEntries = config.environments.client?.entry ?? [];
|
|
3331
|
+
if (configuredEntries.length > 0) return configuredEntries;
|
|
2832
3332
|
const entryPoints = [];
|
|
3333
|
+
const htmlFile = config.environments.client?.html;
|
|
3334
|
+
const htmlDir = htmlFile ? import_node_path10.default.dirname(htmlFile) : config.root;
|
|
2833
3335
|
if (html) {
|
|
2834
3336
|
const scriptMatches = html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi);
|
|
2835
3337
|
for (const match of scriptMatches) {
|
|
2836
3338
|
const src = match[1];
|
|
2837
3339
|
if (src && !src.startsWith("http")) {
|
|
2838
|
-
|
|
3340
|
+
const cleanSrc = src.split(/[?#]/, 1)[0];
|
|
3341
|
+
entryPoints.push(
|
|
3342
|
+
cleanSrc.startsWith("/") ? import_node_path10.default.resolve(config.root, cleanSrc.replace(/^\//, "")) : import_node_path10.default.resolve(htmlDir, cleanSrc)
|
|
3343
|
+
);
|
|
2839
3344
|
}
|
|
2840
3345
|
}
|
|
2841
3346
|
}
|
|
2842
3347
|
if (entryPoints.length === 0) {
|
|
2843
3348
|
const fallbackEntries = ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"];
|
|
2844
3349
|
for (const entry of fallbackEntries) {
|
|
2845
|
-
const fullPath =
|
|
2846
|
-
if (
|
|
3350
|
+
const fullPath = import_node_path10.default.resolve(config.root, entry);
|
|
3351
|
+
if (import_node_fs7.default.existsSync(fullPath)) {
|
|
2847
3352
|
entryPoints.push(fullPath);
|
|
2848
3353
|
break;
|
|
2849
3354
|
}
|
|
@@ -2871,130 +3376,229 @@ async function build(inlineConfig = {}) {
|
|
|
2871
3376
|
const startTime = performance.now();
|
|
2872
3377
|
logger.info(
|
|
2873
3378
|
import_picocolors4.default.cyan(`
|
|
2874
|
-
nasti v${"2.
|
|
3379
|
+
nasti v${"2.4.0"} `) + import_picocolors4.default.green(`building for ${config.mode}...`)
|
|
2875
3380
|
);
|
|
2876
3381
|
debug4?.(`root: ${config.root}`);
|
|
2877
|
-
const buildableNames = Object.keys(config.environments).filter(
|
|
2878
|
-
|
|
2879
|
-
|
|
3382
|
+
const buildableNames = Object.keys(config.environments).filter((name) => {
|
|
3383
|
+
const environment = config.environments[name];
|
|
3384
|
+
if (!environment.buildEnabled) return false;
|
|
3385
|
+
return name === "client" || environment.entry.length > 0 || !!environment.driver;
|
|
3386
|
+
});
|
|
2880
3387
|
buildableNames.sort((a, b) => a === "client" ? -1 : b === "client" ? 1 : 0);
|
|
3388
|
+
prepareBuildOutputDirectories(config, buildableNames);
|
|
2881
3389
|
const environments = {};
|
|
3390
|
+
const environmentResults = {};
|
|
3391
|
+
const initializedEnvironments = [];
|
|
3392
|
+
const buildAppContext = createBuildAppContext(config, environmentResults);
|
|
2882
3393
|
let clientOutput = [];
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
3394
|
+
let buildFailed = false;
|
|
3395
|
+
try {
|
|
3396
|
+
for (const name of buildableNames) {
|
|
3397
|
+
const built = name === "client" ? await buildClientEnvironment(config) : await buildServerEnvironment(config, name);
|
|
3398
|
+
initializedEnvironments.push(built.environment);
|
|
3399
|
+
environments[name] = built.result.output;
|
|
3400
|
+
environmentResults[name] = built.result;
|
|
3401
|
+
if (name === "client") clientOutput = built.result.output;
|
|
3402
|
+
if (buildableNames.length > 1) {
|
|
3403
|
+
debug4?.(`environment "${name}" built (${built.result.output.length} files)`);
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
const pluginApi = getPluginApi(config);
|
|
3407
|
+
for (const plugin of config.plugins) {
|
|
3408
|
+
await plugin.afterBuildApp?.(environmentResults, pluginApi, buildAppContext);
|
|
3409
|
+
}
|
|
3410
|
+
} catch (error) {
|
|
3411
|
+
buildFailed = true;
|
|
3412
|
+
throw error;
|
|
3413
|
+
} finally {
|
|
3414
|
+
let closeFailed = false;
|
|
3415
|
+
let firstCloseError;
|
|
3416
|
+
for (const environment of [...initializedEnvironments].reverse()) {
|
|
3417
|
+
try {
|
|
3418
|
+
await environment.close();
|
|
3419
|
+
} catch (error) {
|
|
3420
|
+
if (!closeFailed) {
|
|
3421
|
+
closeFailed = true;
|
|
3422
|
+
firstCloseError = error;
|
|
3423
|
+
}
|
|
3424
|
+
const closeError = error instanceof Error ? error : new Error(String(error));
|
|
3425
|
+
logger.error(`[nasti] failed to close environment "${environment.name}"`, {
|
|
3426
|
+
error: closeError
|
|
3427
|
+
});
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
if (closeFailed && !buildFailed) {
|
|
3431
|
+
throw firstCloseError;
|
|
2889
3432
|
}
|
|
2890
3433
|
}
|
|
2891
3434
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
2892
|
-
const
|
|
3435
|
+
const allOutput = [...Object.values(environments).flat(), ...buildAppContext.output];
|
|
3436
|
+
const totalSize = allOutput.reduce((sum, chunk) => {
|
|
2893
3437
|
const content = chunk.type === "chunk" ? chunk.code : chunk.source;
|
|
2894
3438
|
if (content == null) return sum;
|
|
2895
3439
|
return sum + (typeof content === "string" ? Buffer.byteLength(content) : content.byteLength);
|
|
2896
3440
|
}, 0);
|
|
2897
|
-
const fileCount =
|
|
3441
|
+
const fileCount = allOutput.length;
|
|
2898
3442
|
const envSuffix = buildableNames.length > 1 ? ` (${buildableNames.join(" + ")})` : "";
|
|
2899
3443
|
logger.info(import_picocolors4.default.green(`\u2713 built in ${elapsed}s`) + import_picocolors4.default.dim(envSuffix));
|
|
2900
3444
|
logger.info(import_picocolors4.default.dim(` ${fileCount} files, ${displaySize(totalSize)} total \u2192 ${config.build.outDir}/`));
|
|
2901
|
-
return {
|
|
3445
|
+
return {
|
|
3446
|
+
output: clientOutput,
|
|
3447
|
+
environments,
|
|
3448
|
+
environmentResults,
|
|
3449
|
+
appOutput: [...buildAppContext.output]
|
|
3450
|
+
};
|
|
2902
3451
|
}
|
|
2903
3452
|
async function buildClientEnvironment(config) {
|
|
2904
3453
|
const logger = config.logger;
|
|
2905
|
-
const outDir =
|
|
2906
|
-
if (config.build.emptyOutDir && import_node_fs6.default.existsSync(outDir)) {
|
|
2907
|
-
import_node_fs6.default.rmSync(outDir, { recursive: true, force: true });
|
|
2908
|
-
}
|
|
2909
|
-
import_node_fs6.default.mkdirSync(outDir, { recursive: true });
|
|
2910
|
-
const html = await readHtmlFile(config.root);
|
|
2911
|
-
const entryPoints = resolveClientEntries(config, html);
|
|
2912
|
-
if (entryPoints.length === 0) {
|
|
2913
|
-
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
2914
|
-
}
|
|
3454
|
+
const outDir = import_node_path10.default.resolve(config.root, config.build.outDir);
|
|
2915
3455
|
const cssEngine = createCssEngine();
|
|
2916
|
-
const pluginList = resolvePluginList(config, config.plugins, {
|
|
2917
|
-
|
|
3456
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
3457
|
+
cssEngine,
|
|
3458
|
+
environmentName: "client"
|
|
3459
|
+
});
|
|
3460
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
2918
3461
|
mode: "build",
|
|
2919
|
-
plugins: pluginList
|
|
3462
|
+
plugins: pluginList,
|
|
3463
|
+
pluginApi: getPluginApi(config)
|
|
2920
3464
|
});
|
|
2921
3465
|
await clientEnv.init();
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
...nativeReporter ? [nativeReporter] : []
|
|
2928
|
-
];
|
|
2929
|
-
const { inputOptions, outputOptions } = getRolldownOptions(clientEnv, entryPoints, rolldownPlugins);
|
|
2930
|
-
const bundle2 = await (0, import_rolldown.rolldown)(inputOptions);
|
|
2931
|
-
const { output } = await bundle2.write(outputOptions);
|
|
2932
|
-
await bundle2.close();
|
|
2933
|
-
if (html) {
|
|
2934
|
-
let processedHtml = html;
|
|
2935
|
-
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
2936
|
-
for (const p of htmlPlugins) {
|
|
2937
|
-
const result = await p.transformIndexHtml(processedHtml);
|
|
2938
|
-
if (typeof result === "string") {
|
|
2939
|
-
processedHtml = result;
|
|
2940
|
-
} else if (result && "html" in result) {
|
|
2941
|
-
processedHtml = processHtml(result.html, result.tags);
|
|
2942
|
-
} else if (Array.isArray(result)) {
|
|
2943
|
-
processedHtml = processHtml(processedHtml, result);
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
|
-
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
2947
|
-
for (const chunk of output) {
|
|
2948
|
-
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
2949
|
-
const originalEntry = import_node_path9.default.relative(config.root, chunk.facadeModuleId);
|
|
2950
|
-
processedHtml = processedHtml.replace(
|
|
2951
|
-
new RegExp(`(src=["'])/?(${escapeRegExp(originalEntry)})(["'])`, "g"),
|
|
2952
|
-
`$1${config.base}${chunk.fileName}$3`
|
|
3466
|
+
try {
|
|
3467
|
+
if (clientEnv.driver) {
|
|
3468
|
+
if (!clientEnv.driver.build) {
|
|
3469
|
+
throw new Error(
|
|
3470
|
+
`[nasti] environment "client" driver "${clientEnv.driver.name}" does not implement build()`
|
|
2953
3471
|
);
|
|
2954
3472
|
}
|
|
3473
|
+
const result = await clientEnv.driver.build(clientEnv.getDriverContext());
|
|
3474
|
+
assertDriverBuildResult(clientEnv, result);
|
|
3475
|
+
return { environment: clientEnv, result: finalizeEnvironmentResult(clientEnv, result) };
|
|
2955
3476
|
}
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
3477
|
+
import_node_fs7.default.mkdirSync(outDir, { recursive: true });
|
|
3478
|
+
const htmlFile = config.environments.client.html ?? import_node_path10.default.resolve(config.root, "index.html");
|
|
3479
|
+
const html = await readHtmlFile(config.root, htmlFile);
|
|
3480
|
+
const entryPoints = resolveClientEntries(config, html);
|
|
3481
|
+
if (entryPoints.length === 0) {
|
|
3482
|
+
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
3483
|
+
}
|
|
3484
|
+
const allPlugins = clientEnv.plugins;
|
|
3485
|
+
const nativeReporter = config.logLevel === "silent" ? null : await tryNativeReporterPlugin(config, logger);
|
|
3486
|
+
const rolldownPlugins = [
|
|
3487
|
+
createOxcTransformPlugin(config, clientEnv),
|
|
3488
|
+
...toRolldownPlugins(allPlugins, clientEnv),
|
|
3489
|
+
...nativeReporter ? [nativeReporter] : []
|
|
3490
|
+
];
|
|
3491
|
+
const { inputOptions, outputOptions } = getRolldownOptions(
|
|
3492
|
+
clientEnv,
|
|
3493
|
+
entryPoints,
|
|
3494
|
+
rolldownPlugins
|
|
3495
|
+
);
|
|
3496
|
+
const bundle2 = await (0, import_rolldown.rolldown)(inputOptions);
|
|
3497
|
+
const { output } = await bundle2.write(outputOptions);
|
|
3498
|
+
await bundle2.close();
|
|
3499
|
+
if (html) {
|
|
3500
|
+
let processedHtml = html;
|
|
3501
|
+
const htmlPlugins = [...allPlugins.filter((p) => p.transformIndexHtml), htmlPlugin(config)];
|
|
3502
|
+
for (const p of htmlPlugins) {
|
|
3503
|
+
const result = await p.transformIndexHtml(processedHtml);
|
|
3504
|
+
if (typeof result === "string") {
|
|
3505
|
+
processedHtml = result;
|
|
3506
|
+
} else if (result && "html" in result) {
|
|
3507
|
+
processedHtml = processHtml(result.html, result.tags);
|
|
3508
|
+
} else if (Array.isArray(result)) {
|
|
3509
|
+
processedHtml = processHtml(processedHtml, result);
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
processedHtml = injectCssLinks(processedHtml, cssEngine, config);
|
|
3513
|
+
for (const chunk of output) {
|
|
3514
|
+
if (chunk.type === "chunk" && chunk.isEntry && chunk.facadeModuleId) {
|
|
3515
|
+
processedHtml = replaceEntryScript(
|
|
3516
|
+
processedHtml,
|
|
3517
|
+
chunk.facadeModuleId,
|
|
3518
|
+
chunk.fileName,
|
|
3519
|
+
config,
|
|
3520
|
+
htmlFile,
|
|
3521
|
+
config.base
|
|
3522
|
+
);
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
import_node_fs7.default.writeFileSync(import_node_path10.default.resolve(outDir, "index.html"), processedHtml);
|
|
3526
|
+
}
|
|
3527
|
+
if (!nativeReporter && config.logLevel !== "silent") {
|
|
3528
|
+
reportBuildOutput(output, config, logger);
|
|
3529
|
+
}
|
|
3530
|
+
warnLargeChunks(output, config, logger);
|
|
3531
|
+
return {
|
|
3532
|
+
environment: clientEnv,
|
|
3533
|
+
result: finalizeEnvironmentResult(clientEnv, { output })
|
|
3534
|
+
};
|
|
3535
|
+
} catch (error) {
|
|
3536
|
+
try {
|
|
3537
|
+
await clientEnv.close();
|
|
3538
|
+
} catch (closeError) {
|
|
3539
|
+
const normalized = closeError instanceof Error ? closeError : new Error(String(closeError));
|
|
3540
|
+
logger.error("[nasti] failed to close client environment after build failure", {
|
|
3541
|
+
error: normalized
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3544
|
+
throw error;
|
|
2960
3545
|
}
|
|
2961
|
-
warnLargeChunks(output, config, logger);
|
|
2962
|
-
return output;
|
|
2963
3546
|
}
|
|
2964
3547
|
async function buildServerEnvironment(config, name) {
|
|
2965
3548
|
const envOptions = config.environments[name];
|
|
2966
3549
|
const logger = config.logger;
|
|
3550
|
+
const pluginList = resolvePluginList(config, config.plugins, {
|
|
3551
|
+
consumer: envOptions.consumer,
|
|
3552
|
+
environmentName: name
|
|
3553
|
+
});
|
|
3554
|
+
const environment = new NastiEnvironment(name, config, {
|
|
3555
|
+
mode: "build",
|
|
3556
|
+
plugins: pluginList,
|
|
3557
|
+
pluginApi: getPluginApi(config)
|
|
3558
|
+
});
|
|
3559
|
+
await environment.init();
|
|
3560
|
+
if (environment.driver) {
|
|
3561
|
+
if (!environment.driver.build) {
|
|
3562
|
+
await environment.close();
|
|
3563
|
+
throw new Error(
|
|
3564
|
+
`[nasti] environment "${name}" driver "${environment.driver.name}" does not implement build()`
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
try {
|
|
3568
|
+
const result = await environment.driver.build(environment.getDriverContext());
|
|
3569
|
+
assertDriverBuildResult(environment, result);
|
|
3570
|
+
return { environment, result: finalizeEnvironmentResult(environment, result) };
|
|
3571
|
+
} catch (error) {
|
|
3572
|
+
await environment.close();
|
|
3573
|
+
throw error;
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
2967
3576
|
for (const entry of envOptions.entry) {
|
|
2968
|
-
if (!
|
|
3577
|
+
if (!import_node_fs7.default.existsSync(entry)) {
|
|
3578
|
+
await environment.close();
|
|
2969
3579
|
throw new Error(`[nasti] environment "${name}" entry not found: ${entry}`);
|
|
2970
3580
|
}
|
|
2971
3581
|
}
|
|
2972
|
-
const pluginList = resolvePluginList(config, config.plugins, { consumer: envOptions.consumer });
|
|
2973
|
-
const environment = new NastiEnvironment(name, { ...config, plugins: pluginList }, {
|
|
2974
|
-
mode: "build",
|
|
2975
|
-
plugins: pluginList
|
|
2976
|
-
});
|
|
2977
|
-
await environment.init();
|
|
2978
3582
|
const rolldownPlugins = [
|
|
2979
3583
|
createOxcTransformPlugin(config, environment),
|
|
2980
|
-
...toRolldownPlugins(environment.plugins)
|
|
3584
|
+
...toRolldownPlugins(environment.plugins, environment)
|
|
2981
3585
|
];
|
|
2982
3586
|
const { inputOptions, outputOptions, outDir } = getRolldownOptions(
|
|
2983
3587
|
environment,
|
|
2984
3588
|
envOptions.entry,
|
|
2985
3589
|
rolldownPlugins
|
|
2986
3590
|
);
|
|
2987
|
-
|
|
2988
|
-
import_node_fs6.default.rmSync(outDir, { recursive: true, force: true });
|
|
2989
|
-
}
|
|
2990
|
-
import_node_fs6.default.mkdirSync(outDir, { recursive: true });
|
|
3591
|
+
import_node_fs7.default.mkdirSync(outDir, { recursive: true });
|
|
2991
3592
|
const bundle2 = await (0, import_rolldown.rolldown)(inputOptions);
|
|
2992
3593
|
const { output } = await bundle2.write(outputOptions);
|
|
2993
3594
|
await bundle2.close();
|
|
2994
3595
|
logger.info(
|
|
2995
|
-
import_picocolors4.default.dim(` [${name}] `) + output.map((o) =>
|
|
3596
|
+
import_picocolors4.default.dim(` [${name}] `) + output.map((o) => import_node_path10.default.join(envOptions.build.outDir, o.fileName)).join(import_picocolors4.default.dim(", "))
|
|
2996
3597
|
);
|
|
2997
|
-
return
|
|
3598
|
+
return {
|
|
3599
|
+
environment,
|
|
3600
|
+
result: finalizeEnvironmentResult(environment, { output })
|
|
3601
|
+
};
|
|
2998
3602
|
}
|
|
2999
3603
|
function injectCssLinks(html, cssEngine, config) {
|
|
3000
3604
|
const cssLinkTags = [];
|
|
@@ -3020,12 +3624,31 @@ function injectCssLinks(html, cssEngine, config) {
|
|
|
3020
3624
|
function escapeRegExp(string) {
|
|
3021
3625
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3022
3626
|
}
|
|
3023
|
-
|
|
3627
|
+
function replaceEntryScript(html, facadeModuleId, fileName, config, htmlFile, urlPrefix) {
|
|
3628
|
+
const rootRelative = import_node_path10.default.relative(config.root, facadeModuleId).split(import_node_path10.default.sep).join("/");
|
|
3629
|
+
const resolvedHtmlFile = import_node_path10.default.resolve(config.root, htmlFile);
|
|
3630
|
+
const htmlRelative = import_node_path10.default.relative(import_node_path10.default.dirname(resolvedHtmlFile), facadeModuleId).split(import_node_path10.default.sep).join("/");
|
|
3631
|
+
const candidates = /* @__PURE__ */ new Set([
|
|
3632
|
+
rootRelative,
|
|
3633
|
+
`/${rootRelative}`,
|
|
3634
|
+
htmlRelative,
|
|
3635
|
+
`./${htmlRelative}`
|
|
3636
|
+
]);
|
|
3637
|
+
let processed = html;
|
|
3638
|
+
for (const candidate of candidates) {
|
|
3639
|
+
processed = processed.replace(
|
|
3640
|
+
new RegExp(`(src=["'])${escapeRegExp(candidate)}([?#][^"']*)?(["'])`, "g"),
|
|
3641
|
+
`$1${urlPrefix}${fileName}$3`
|
|
3642
|
+
);
|
|
3643
|
+
}
|
|
3644
|
+
return processed;
|
|
3645
|
+
}
|
|
3646
|
+
var import_node_path10, import_node_fs7, import_node_module3, import_rolldown, import_picocolors4, debug4, NODE_BUILTINS;
|
|
3024
3647
|
var init_build = __esm({
|
|
3025
3648
|
"src/build/index.ts"() {
|
|
3026
3649
|
"use strict";
|
|
3027
|
-
|
|
3028
|
-
|
|
3650
|
+
import_node_path10 = __toESM(require("path"), 1);
|
|
3651
|
+
import_node_fs7 = __toESM(require("fs"), 1);
|
|
3029
3652
|
import_node_module3 = require("module");
|
|
3030
3653
|
import_rolldown = require("rolldown");
|
|
3031
3654
|
init_config();
|
|
@@ -3037,6 +3660,8 @@ var init_build = __esm({
|
|
|
3037
3660
|
init_env();
|
|
3038
3661
|
init_reporter();
|
|
3039
3662
|
init_debug();
|
|
3663
|
+
init_plugin_api();
|
|
3664
|
+
init_build_app_context();
|
|
3040
3665
|
import_picocolors4 = __toESM(require("picocolors"), 1);
|
|
3041
3666
|
debug4 = createDebugger("nasti:build");
|
|
3042
3667
|
NODE_BUILTINS = /* @__PURE__ */ new Set([...import_node_module3.builtinModules, ...import_node_module3.builtinModules.map((m) => `node:${m}`)]);
|
|
@@ -3096,15 +3721,17 @@ __export(middleware_exports, {
|
|
|
3096
3721
|
transformMiddleware: () => transformMiddleware,
|
|
3097
3722
|
transformRequest: () => transformRequest
|
|
3098
3723
|
});
|
|
3099
|
-
function getReactRefreshRuntimeEsm() {
|
|
3100
|
-
if (__refreshRuntimeCache)
|
|
3724
|
+
function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
|
|
3725
|
+
if (__refreshRuntimeCache) {
|
|
3726
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
3727
|
+
}
|
|
3101
3728
|
let cjsPath;
|
|
3102
3729
|
try {
|
|
3103
3730
|
const pkgPath = __require.resolve("react-refresh/package.json");
|
|
3104
|
-
cjsPath =
|
|
3731
|
+
cjsPath = import_node_path12.default.join(import_node_path12.default.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
|
|
3105
3732
|
} catch (err) {
|
|
3106
|
-
cjsPath =
|
|
3107
|
-
if (!
|
|
3733
|
+
cjsPath = import_node_path12.default.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
|
|
3734
|
+
if (!import_node_fs9.default.existsSync(cjsPath)) {
|
|
3108
3735
|
const origMsg = err instanceof Error ? err.message : String(err);
|
|
3109
3736
|
throw new Error(
|
|
3110
3737
|
`[nasti] Missing dependency "react-refresh". Install it with: npm install react-refresh
|
|
@@ -3112,7 +3739,7 @@ Original resolve error: ${origMsg}`
|
|
|
3112
3739
|
);
|
|
3113
3740
|
}
|
|
3114
3741
|
}
|
|
3115
|
-
const cjsSource =
|
|
3742
|
+
const cjsSource = import_node_fs9.default.readFileSync(cjsPath, "utf-8");
|
|
3116
3743
|
__refreshRuntimeCache = `// Wrapped react-refresh runtime -> ESM
|
|
3117
3744
|
const exports = {};
|
|
3118
3745
|
const module = { exports };
|
|
@@ -3132,7 +3759,7 @@ export const findAffectedHostInstances = __rt.findAffectedHostInstances;
|
|
|
3132
3759
|
export const collectCustomHooksForSignature = __rt.collectCustomHooksForSignature;
|
|
3133
3760
|
export default __rt;
|
|
3134
3761
|
`;
|
|
3135
|
-
return __refreshRuntimeCache;
|
|
3762
|
+
return includeBoundaryHelpers ? __refreshRuntimeCache + REACT_REFRESH_BOUNDARY_HELPERS : __refreshRuntimeCache;
|
|
3136
3763
|
}
|
|
3137
3764
|
function buildReactRefreshWrapper(moduleUrl, transformedCode) {
|
|
3138
3765
|
const urlLit = JSON.stringify(moduleUrl);
|
|
@@ -3158,22 +3785,40 @@ window.$RefreshReg$ = prevRefreshReg;
|
|
|
3158
3785
|
window.$RefreshSig$ = prevRefreshSig;
|
|
3159
3786
|
|
|
3160
3787
|
if (__nasti_hot__) {
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3788
|
+
let __nasti_current_exports__;
|
|
3789
|
+
__nasti_hot__.accept((nextExports) => {
|
|
3790
|
+
if (!nextExports) return;
|
|
3791
|
+
if (!__nasti_current_exports__) {
|
|
3792
|
+
__nasti_hot__.invalidate('Could not Fast Refresh (previous exports unavailable)');
|
|
3793
|
+
return;
|
|
3794
|
+
}
|
|
3795
|
+
const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(
|
|
3796
|
+
${urlLit},
|
|
3797
|
+
__nasti_current_exports__,
|
|
3798
|
+
nextExports,
|
|
3799
|
+
);
|
|
3800
|
+
if (invalidateMessage) __nasti_hot__.invalidate(invalidateMessage);
|
|
3801
|
+
});
|
|
3802
|
+
RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
|
|
3803
|
+
__nasti_current_exports__ = currentExports;
|
|
3804
|
+
RefreshRuntime.registerExportsForReactRefresh(${urlLit}, currentExports);
|
|
3166
3805
|
});
|
|
3167
3806
|
}
|
|
3168
3807
|
`;
|
|
3169
3808
|
}
|
|
3170
3809
|
function injectImportMetaHot(code, moduleUrl) {
|
|
3171
|
-
|
|
3810
|
+
const hotRE = /\bimport\.meta\.hot\b/g;
|
|
3811
|
+
const matches = [...maskStringsAndComments(code).matchAll(hotRE)];
|
|
3812
|
+
if (matches.length === 0) return code;
|
|
3813
|
+
for (const match of matches.reverse()) {
|
|
3814
|
+
const start = match.index;
|
|
3815
|
+
code = code.slice(0, start) + "__nasti_hot__" + code.slice(start + match[0].length);
|
|
3816
|
+
}
|
|
3172
3817
|
const urlLit = JSON.stringify(moduleUrl);
|
|
3173
3818
|
const header = `import { createHotContext as __nasti_createHotContext__ } from "/@nasti/client";
|
|
3174
3819
|
const __nasti_hot__ = __nasti_createHotContext__(${urlLit});
|
|
3175
3820
|
`;
|
|
3176
|
-
return header + code
|
|
3821
|
+
return header + code;
|
|
3177
3822
|
}
|
|
3178
3823
|
function transformMiddleware(ctx) {
|
|
3179
3824
|
ctx.envDefine = buildEnvDefine(
|
|
@@ -3200,7 +3845,10 @@ function transformMiddleware(ctx) {
|
|
|
3200
3845
|
return;
|
|
3201
3846
|
}
|
|
3202
3847
|
if (url === "/" || url.endsWith(".html")) {
|
|
3203
|
-
const html = await readHtmlFile(
|
|
3848
|
+
const html = await readHtmlFile(
|
|
3849
|
+
ctx.config.root,
|
|
3850
|
+
ctx.config.environments.client?.html
|
|
3851
|
+
);
|
|
3204
3852
|
if (html) {
|
|
3205
3853
|
let processedHtml = html;
|
|
3206
3854
|
for (const plugin of ctx.config.plugins) {
|
|
@@ -3246,13 +3894,14 @@ function transformMiddleware(ctx) {
|
|
|
3246
3894
|
}
|
|
3247
3895
|
async function transformRequest(url, ctx) {
|
|
3248
3896
|
const { config, pluginContainer, moduleGraph } = ctx;
|
|
3897
|
+
url = removeTimestampQuery(url);
|
|
3249
3898
|
const cleanReqUrl = url.split("?")[0];
|
|
3250
3899
|
const cached2 = moduleGraph.getModuleByUrl(url);
|
|
3251
3900
|
if (cached2?.transformResult) {
|
|
3252
3901
|
return cached2.transformResult;
|
|
3253
3902
|
}
|
|
3254
3903
|
if (cleanReqUrl === "/@react-refresh") {
|
|
3255
|
-
return { code: getReactRefreshRuntimeEsm() };
|
|
3904
|
+
return { code: getReactRefreshRuntimeEsm(true) };
|
|
3256
3905
|
}
|
|
3257
3906
|
if (cleanReqUrl.startsWith("/@modules/") && url.includes("?")) {
|
|
3258
3907
|
const idParam = new URLSearchParams(url.slice(url.indexOf("?") + 1)).get("id");
|
|
@@ -3260,8 +3909,8 @@ async function transformRequest(url, ctx) {
|
|
|
3260
3909
|
let realIdValid = false;
|
|
3261
3910
|
try {
|
|
3262
3911
|
if (idParam) {
|
|
3263
|
-
realId =
|
|
3264
|
-
realIdValid =
|
|
3912
|
+
realId = import_node_fs9.default.realpathSync(idParam);
|
|
3913
|
+
realIdValid = import_node_fs9.default.statSync(realId).isFile() && (realId.includes(`${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}`) || isUnderRoot(realId, config.root));
|
|
3265
3914
|
}
|
|
3266
3915
|
} catch {
|
|
3267
3916
|
realId = null;
|
|
@@ -3288,6 +3937,8 @@ async function transformRequest(url, ctx) {
|
|
|
3288
3937
|
}
|
|
3289
3938
|
const rawQuery = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
|
|
3290
3939
|
if (rawQuery && !/^t=\d+$/.test(rawQuery)) {
|
|
3940
|
+
const mod2 = await moduleGraph.ensureEntryFromUrl(url);
|
|
3941
|
+
const transformVersion2 = mod2.invalidationVersion;
|
|
3291
3942
|
const loaded = await pluginContainer.load(url);
|
|
3292
3943
|
if (loaded != null) {
|
|
3293
3944
|
let code2 = typeof loaded === "string" ? loaded : loaded.code;
|
|
@@ -3295,30 +3946,43 @@ async function transformRequest(url, ctx) {
|
|
|
3295
3946
|
if (transformed != null) {
|
|
3296
3947
|
code2 = typeof transformed === "string" ? transformed : transformed.code;
|
|
3297
3948
|
}
|
|
3298
|
-
const
|
|
3299
|
-
moduleGraph.registerModule(mod2,
|
|
3300
|
-
|
|
3949
|
+
const parentFile = resolveUrlToFile(cleanReqUrl, config.root) ?? cleanReqUrl;
|
|
3950
|
+
moduleGraph.registerModule(mod2, parentFile);
|
|
3951
|
+
const hotInfo2 = rewriteHotAcceptDeps(code2, config, parentFile);
|
|
3952
|
+
code2 = injectImportMetaHot(hotInfo2.code, url);
|
|
3301
3953
|
code2 = replaceEnvInCode(code2, ctx.envDefine ?? buildEnvDefine(
|
|
3302
3954
|
loadEnv(config.mode, config.root, config.envPrefix),
|
|
3303
3955
|
config.mode
|
|
3304
3956
|
));
|
|
3305
|
-
|
|
3957
|
+
const importedUrls2 = /* @__PURE__ */ new Set();
|
|
3958
|
+
code2 = rewriteImports(code2, config, parentFile, importedUrls2, moduleGraph);
|
|
3959
|
+
const pruned2 = await moduleGraph.updateModuleInfo(
|
|
3960
|
+
mod2,
|
|
3961
|
+
importedUrls2,
|
|
3962
|
+
hotInfo2.acceptedUrls,
|
|
3963
|
+
hotInfo2.isSelfAccepting,
|
|
3964
|
+
transformVersion2
|
|
3965
|
+
);
|
|
3306
3966
|
const transformResult2 = { code: code2 };
|
|
3307
|
-
|
|
3967
|
+
if (pruned2) {
|
|
3968
|
+
if (pruned2.size > 0) ctx.onPrune?.([...pruned2].map((item) => item.url));
|
|
3969
|
+
mod2.transformResult = transformResult2;
|
|
3970
|
+
}
|
|
3308
3971
|
return transformResult2;
|
|
3309
3972
|
}
|
|
3310
3973
|
}
|
|
3311
3974
|
const filePath = resolveUrlToFile(url, config.root);
|
|
3312
|
-
if (!filePath || !
|
|
3975
|
+
if (!filePath || !import_node_fs9.default.existsSync(filePath)) return null;
|
|
3313
3976
|
const mod = await moduleGraph.ensureEntryFromUrl(url);
|
|
3314
3977
|
moduleGraph.registerModule(mod, filePath);
|
|
3978
|
+
const transformVersion = mod.invalidationVersion;
|
|
3315
3979
|
if (cleanReqUrl.startsWith("/@modules/")) {
|
|
3316
3980
|
const code2 = await bundlePackageAsEsm(filePath, config.root);
|
|
3317
3981
|
const transformResult2 = { code: code2 };
|
|
3318
3982
|
mod.transformResult = transformResult2;
|
|
3319
3983
|
return transformResult2;
|
|
3320
3984
|
}
|
|
3321
|
-
let code =
|
|
3985
|
+
let code = import_node_fs9.default.readFileSync(filePath, "utf-8");
|
|
3322
3986
|
const pluginResult = await pluginContainer.transform(code, filePath);
|
|
3323
3987
|
if (pluginResult) {
|
|
3324
3988
|
code = typeof pluginResult === "string" ? pluginResult : pluginResult.code;
|
|
@@ -3338,9 +4002,10 @@ async function transformRequest(url, ctx) {
|
|
|
3338
4002
|
if (useRefresh) {
|
|
3339
4003
|
code = buildReactRefreshWrapper(stableUrl, code);
|
|
3340
4004
|
wrappedWithRefresh = true;
|
|
3341
|
-
mod.isSelfAccepting = true;
|
|
3342
4005
|
}
|
|
3343
4006
|
}
|
|
4007
|
+
const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
|
|
4008
|
+
code = hotInfo.code;
|
|
3344
4009
|
if (!wrappedWithRefresh) {
|
|
3345
4010
|
code = injectImportMetaHot(code, stableUrl);
|
|
3346
4011
|
}
|
|
@@ -3349,9 +4014,20 @@ async function transformRequest(url, ctx) {
|
|
|
3349
4014
|
config.mode
|
|
3350
4015
|
);
|
|
3351
4016
|
code = replaceEnvInCode(code, envDefine);
|
|
3352
|
-
|
|
4017
|
+
const importedUrls = /* @__PURE__ */ new Set();
|
|
4018
|
+
code = rewriteImports(code, config, filePath, importedUrls, moduleGraph);
|
|
4019
|
+
const pruned = await moduleGraph.updateModuleInfo(
|
|
4020
|
+
mod,
|
|
4021
|
+
importedUrls,
|
|
4022
|
+
hotInfo.acceptedUrls,
|
|
4023
|
+
wrappedWithRefresh || hotInfo.isSelfAccepting,
|
|
4024
|
+
transformVersion
|
|
4025
|
+
);
|
|
3353
4026
|
const transformResult = { code };
|
|
3354
|
-
|
|
4027
|
+
if (pruned) {
|
|
4028
|
+
if (pruned.size > 0) ctx.onPrune?.([...pruned].map((item) => item.url));
|
|
4029
|
+
mod.transformResult = transformResult;
|
|
4030
|
+
}
|
|
3355
4031
|
return transformResult;
|
|
3356
4032
|
}
|
|
3357
4033
|
async function loadVirtualModule(spec, ctx) {
|
|
@@ -3359,7 +4035,7 @@ async function loadVirtualModule(spec, ctx) {
|
|
|
3359
4035
|
const resolved = await pluginContainer.resolveId(spec);
|
|
3360
4036
|
if (resolved == null) return null;
|
|
3361
4037
|
const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
|
|
3362
|
-
const looksVirtual = resolvedId.startsWith("\0") || !
|
|
4038
|
+
const looksVirtual = resolvedId.startsWith("\0") || !import_node_fs9.default.existsSync(resolvedId);
|
|
3363
4039
|
if (!looksVirtual) return null;
|
|
3364
4040
|
const loadResult = await pluginContainer.load(resolvedId);
|
|
3365
4041
|
if (loadResult == null) return null;
|
|
@@ -3372,7 +4048,7 @@ async function loadVirtualModule(spec, ctx) {
|
|
|
3372
4048
|
loadEnv(config.mode, config.root, config.envPrefix),
|
|
3373
4049
|
config.mode
|
|
3374
4050
|
));
|
|
3375
|
-
const anchor =
|
|
4051
|
+
const anchor = import_node_path12.default.join(config.root, "__nasti_virtual__.ts");
|
|
3376
4052
|
code = rewriteImports(code, config, anchor);
|
|
3377
4053
|
return { id: resolvedId, result: { code } };
|
|
3378
4054
|
}
|
|
@@ -3398,7 +4074,7 @@ async function doBundlePackage(entryFile, root) {
|
|
|
3398
4074
|
await bundle2.close();
|
|
3399
4075
|
let code = result.output[0].code;
|
|
3400
4076
|
code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
|
|
3401
|
-
const externalBaseDir =
|
|
4077
|
+
const externalBaseDir = import_node_path12.default.dirname(entryFile);
|
|
3402
4078
|
code = code.replace(
|
|
3403
4079
|
/^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
|
|
3404
4080
|
(_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir, root)}${q}`
|
|
@@ -3416,16 +4092,16 @@ async function doBundlePackage(entryFile, root) {
|
|
|
3416
4092
|
return code;
|
|
3417
4093
|
}
|
|
3418
4094
|
async function tryGenerateSubpathShim(entryFile, root) {
|
|
3419
|
-
const NM = `${
|
|
4095
|
+
const NM = `${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}`;
|
|
3420
4096
|
if (!entryFile.includes(NM)) return null;
|
|
3421
4097
|
let pkgDir = null;
|
|
3422
4098
|
let pkgName = null;
|
|
3423
|
-
let dir =
|
|
4099
|
+
let dir = import_node_path12.default.dirname(entryFile);
|
|
3424
4100
|
while (true) {
|
|
3425
|
-
const pkgJsonPath =
|
|
3426
|
-
if (
|
|
4101
|
+
const pkgJsonPath = import_node_path12.default.join(dir, "package.json");
|
|
4102
|
+
if (import_node_fs9.default.existsSync(pkgJsonPath)) {
|
|
3427
4103
|
try {
|
|
3428
|
-
const pkg = JSON.parse(
|
|
4104
|
+
const pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
3429
4105
|
if (typeof pkg?.name === "string" && pkg.name) {
|
|
3430
4106
|
pkgDir = dir;
|
|
3431
4107
|
pkgName = pkg.name;
|
|
@@ -3434,16 +4110,16 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3434
4110
|
} catch {
|
|
3435
4111
|
}
|
|
3436
4112
|
}
|
|
3437
|
-
const parent =
|
|
4113
|
+
const parent = import_node_path12.default.dirname(dir);
|
|
3438
4114
|
if (parent === dir) return null;
|
|
3439
4115
|
dir = parent;
|
|
3440
4116
|
if (!dir.includes(NM)) return null;
|
|
3441
4117
|
}
|
|
3442
4118
|
if (!pkgDir || !pkgName) return null;
|
|
3443
|
-
const entryExt =
|
|
4119
|
+
const entryExt = import_node_path12.default.extname(entryFile);
|
|
3444
4120
|
const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
|
|
3445
4121
|
if (!mainEntry) return null;
|
|
3446
|
-
if (
|
|
4122
|
+
if (import_node_path12.default.resolve(mainEntry) === import_node_path12.default.resolve(entryFile)) return null;
|
|
3447
4123
|
let mainNs;
|
|
3448
4124
|
let subNs;
|
|
3449
4125
|
try {
|
|
@@ -3467,7 +4143,7 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3467
4143
|
if (mainNs["default"] !== subNs["default"]) return null;
|
|
3468
4144
|
}
|
|
3469
4145
|
const rootMain = resolveNodeModule(root, pkgName);
|
|
3470
|
-
const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir +
|
|
4146
|
+
const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + import_node_path12.default.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
|
|
3471
4147
|
const lines = [
|
|
3472
4148
|
`// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
|
|
3473
4149
|
`import * as __pkg from "${mainEntryUrl}";`
|
|
@@ -3481,10 +4157,10 @@ async function tryGenerateSubpathShim(entryFile, root) {
|
|
|
3481
4157
|
return lines.join("\n") + "\n";
|
|
3482
4158
|
}
|
|
3483
4159
|
function pickMainEntryByExtension(pkgDir, preferredExt) {
|
|
3484
|
-
const pkgJsonPath =
|
|
4160
|
+
const pkgJsonPath = import_node_path12.default.join(pkgDir, "package.json");
|
|
3485
4161
|
let pkg;
|
|
3486
4162
|
try {
|
|
3487
|
-
pkg = JSON.parse(
|
|
4163
|
+
pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
3488
4164
|
} catch {
|
|
3489
4165
|
return null;
|
|
3490
4166
|
}
|
|
@@ -3503,14 +4179,14 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
|
|
|
3503
4179
|
if (typeof pkg.module === "string") candidates.push(pkg.module);
|
|
3504
4180
|
if (typeof pkg.main === "string") candidates.push(pkg.main);
|
|
3505
4181
|
for (const cand of candidates) {
|
|
3506
|
-
if (
|
|
3507
|
-
const full =
|
|
3508
|
-
if (
|
|
4182
|
+
if (import_node_path12.default.extname(cand) === preferredExt) {
|
|
4183
|
+
const full = import_node_path12.default.resolve(pkgDir, cand);
|
|
4184
|
+
if (import_node_fs9.default.existsSync(full)) return full;
|
|
3509
4185
|
}
|
|
3510
4186
|
}
|
|
3511
4187
|
for (const cand of candidates) {
|
|
3512
|
-
const full =
|
|
3513
|
-
if (
|
|
4188
|
+
const full = import_node_path12.default.resolve(pkgDir, cand);
|
|
4189
|
+
if (import_node_fs9.default.existsSync(full)) return full;
|
|
3514
4190
|
}
|
|
3515
4191
|
return null;
|
|
3516
4192
|
}
|
|
@@ -3556,72 +4232,231 @@ async function injectCjsNamedExports(code, entryFile) {
|
|
|
3556
4232
|
return code;
|
|
3557
4233
|
}
|
|
3558
4234
|
}
|
|
3559
|
-
function rewriteImports(code, config, filePath) {
|
|
4235
|
+
function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
|
|
4236
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
4237
|
+
const transformSpec = (spec) => {
|
|
4238
|
+
const resolved = removeTimestampQuery(resolveSpec(spec));
|
|
4239
|
+
importedUrls?.add(resolved);
|
|
4240
|
+
const timestamp = moduleGraph?.getModuleByUrl(resolved)?.lastHMRTimestamp ?? 0;
|
|
4241
|
+
return timestamp > 0 ? appendTimestampQuery(resolved, timestamp) : resolved;
|
|
4242
|
+
};
|
|
4243
|
+
return code.replace(
|
|
4244
|
+
/\bfrom\s+(['"])([^'"]+)\1/g,
|
|
4245
|
+
(_m, q, s) => `from ${q}${transformSpec(s)}${q}`
|
|
4246
|
+
).replace(
|
|
4247
|
+
/\bimport\s+(['"])([^'"]+)\1/g,
|
|
4248
|
+
(_m, q, s) => `import ${q}${transformSpec(s)}${q}`
|
|
4249
|
+
).replace(
|
|
4250
|
+
/\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g,
|
|
4251
|
+
(_m, q, s) => `import(${q}${transformSpec(s)}${q})`
|
|
4252
|
+
);
|
|
4253
|
+
}
|
|
4254
|
+
function createModuleSpecifierResolver(config, filePath) {
|
|
3560
4255
|
const root = config.root;
|
|
3561
|
-
const fileDir =
|
|
4256
|
+
const fileDir = import_node_path12.default.dirname(filePath);
|
|
3562
4257
|
const aliasEntries = Object.entries(config.resolve.alias).sort(
|
|
3563
4258
|
([a], [b]) => b.length - a.length
|
|
3564
4259
|
);
|
|
3565
|
-
const toRootUrl = (abs) => "/" +
|
|
3566
|
-
|
|
3567
|
-
const suffixMatch =
|
|
4260
|
+
const toRootUrl = (abs) => "/" + import_node_path12.default.relative(root, abs).replace(/\\/g, "/");
|
|
4261
|
+
return (specifier) => {
|
|
4262
|
+
const suffixMatch = specifier.match(/[?#].*$/);
|
|
3568
4263
|
const suffix = suffixMatch ? suffixMatch[0] : "";
|
|
3569
|
-
const baseSpec = suffix ?
|
|
4264
|
+
const baseSpec = suffix ? specifier.slice(0, -suffix.length) : specifier;
|
|
3570
4265
|
for (const [key, value] of aliasEntries) {
|
|
3571
4266
|
if (baseSpec === key || baseSpec.startsWith(key + "/")) {
|
|
3572
4267
|
const aliasBase = resolveAliasTarget2(value, root);
|
|
3573
4268
|
const sub = baseSpec.slice(key.length).replace(/^\//, "");
|
|
3574
|
-
const target = sub ?
|
|
4269
|
+
const target = sub ? import_node_path12.default.join(aliasBase, sub) : aliasBase;
|
|
3575
4270
|
const resolved = tryResolveDiskPath(target);
|
|
3576
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix :
|
|
4271
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
3577
4272
|
}
|
|
3578
4273
|
}
|
|
3579
4274
|
if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : spec;
|
|
4275
|
+
const resolved = tryResolveDiskPath(import_node_path12.default.resolve(fileDir, baseSpec));
|
|
4276
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
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(import_node_path12.default.join(root, baseSpec.replace(/^\//, "")));
|
|
4280
|
+
return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
|
|
3588
4281
|
}
|
|
3589
|
-
if (baseSpec.startsWith("/")) return
|
|
3590
|
-
return `/@modules/${
|
|
4282
|
+
if (baseSpec.startsWith("/")) return specifier;
|
|
4283
|
+
return `/@modules/${specifier}`;
|
|
3591
4284
|
};
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
)
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
)
|
|
4285
|
+
}
|
|
4286
|
+
function rewriteHotAcceptDeps(code, config, filePath) {
|
|
4287
|
+
const acceptedUrls = /* @__PURE__ */ new Set();
|
|
4288
|
+
const edits = [];
|
|
4289
|
+
const resolveSpec = createModuleSpecifierResolver(config, filePath);
|
|
4290
|
+
const acceptRE = /(?:\bimport\.meta\.hot|\b__nasti_hot__)(?:(?:\?\.)|\.)accept\s*\(/g;
|
|
4291
|
+
const searchableCode = maskStringsAndComments(code);
|
|
4292
|
+
let isSelfAccepting = false;
|
|
4293
|
+
let match;
|
|
4294
|
+
while (match = acceptRE.exec(searchableCode)) {
|
|
4295
|
+
let cursor = match.index + match[0].length;
|
|
4296
|
+
const skipTrivia = () => {
|
|
4297
|
+
while (cursor < code.length) {
|
|
4298
|
+
if (/\s/.test(code[cursor])) {
|
|
4299
|
+
cursor++;
|
|
4300
|
+
continue;
|
|
4301
|
+
}
|
|
4302
|
+
if (code[cursor] === "/" && code[cursor + 1] === "/") {
|
|
4303
|
+
cursor += 2;
|
|
4304
|
+
while (cursor < code.length && code[cursor] !== "\n") cursor++;
|
|
4305
|
+
continue;
|
|
4306
|
+
}
|
|
4307
|
+
if (code[cursor] === "/" && code[cursor + 1] === "*") {
|
|
4308
|
+
cursor += 2;
|
|
4309
|
+
while (cursor < code.length && !(code[cursor] === "*" && code[cursor + 1] === "/")) cursor++;
|
|
4310
|
+
cursor += 2;
|
|
4311
|
+
continue;
|
|
4312
|
+
}
|
|
4313
|
+
break;
|
|
4314
|
+
}
|
|
4315
|
+
};
|
|
4316
|
+
skipTrivia();
|
|
4317
|
+
const first = code[cursor];
|
|
4318
|
+
if (!first || first === ")" || first !== "[" && first !== "'" && first !== '"' && first !== "`") {
|
|
4319
|
+
isSelfAccepting = true;
|
|
4320
|
+
continue;
|
|
4321
|
+
}
|
|
4322
|
+
const readLiteral = () => {
|
|
4323
|
+
const quote = code[cursor];
|
|
4324
|
+
if (quote !== "'" && quote !== '"' && quote !== "`") return;
|
|
4325
|
+
const start = cursor;
|
|
4326
|
+
cursor++;
|
|
4327
|
+
let raw = "";
|
|
4328
|
+
while (cursor < code.length) {
|
|
4329
|
+
const char = code[cursor];
|
|
4330
|
+
if (char === "\\") {
|
|
4331
|
+
raw += code[cursor + 1] ?? "";
|
|
4332
|
+
cursor += 2;
|
|
4333
|
+
continue;
|
|
4334
|
+
}
|
|
4335
|
+
if (char === quote) {
|
|
4336
|
+
cursor++;
|
|
4337
|
+
const resolved = removeTimestampQuery(resolveSpec(raw));
|
|
4338
|
+
acceptedUrls.add(resolved);
|
|
4339
|
+
edits.push({ start, end: cursor, value: JSON.stringify(resolved) });
|
|
4340
|
+
return;
|
|
4341
|
+
}
|
|
4342
|
+
if (quote === "`" && char === "$" && code[cursor + 1] === "{") return;
|
|
4343
|
+
raw += char;
|
|
4344
|
+
cursor++;
|
|
4345
|
+
}
|
|
4346
|
+
};
|
|
4347
|
+
if (first === "[") {
|
|
4348
|
+
cursor++;
|
|
4349
|
+
while (cursor < code.length) {
|
|
4350
|
+
skipTrivia();
|
|
4351
|
+
if (code[cursor] === ",") {
|
|
4352
|
+
cursor++;
|
|
4353
|
+
skipTrivia();
|
|
4354
|
+
}
|
|
4355
|
+
if (code[cursor] === "]") break;
|
|
4356
|
+
const before = cursor;
|
|
4357
|
+
readLiteral();
|
|
4358
|
+
if (cursor === before) break;
|
|
4359
|
+
}
|
|
4360
|
+
} else {
|
|
4361
|
+
readLiteral();
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
4365
|
+
code = code.slice(0, edit.start) + edit.value + code.slice(edit.end);
|
|
4366
|
+
}
|
|
4367
|
+
return { code, acceptedUrls, isSelfAccepting };
|
|
4368
|
+
}
|
|
4369
|
+
function maskStringsAndComments(code) {
|
|
4370
|
+
const masked = code.split("");
|
|
4371
|
+
let state = "code";
|
|
4372
|
+
const isRegexStart = (index2) => {
|
|
4373
|
+
let previous = index2 - 1;
|
|
4374
|
+
while (previous >= 0 && /\s/.test(code[previous])) previous--;
|
|
4375
|
+
return previous < 0 || "=(:,!&|?{};[]+-*%^~<>".includes(code[previous]);
|
|
4376
|
+
};
|
|
4377
|
+
for (let i = 0; i < code.length; i++) {
|
|
4378
|
+
const char = code[i];
|
|
4379
|
+
const next = code[i + 1];
|
|
4380
|
+
if (state === "code") {
|
|
4381
|
+
if (char === "'") state = "single";
|
|
4382
|
+
else if (char === '"') state = "double";
|
|
4383
|
+
else if (char === "`") state = "template";
|
|
4384
|
+
else if (char === "/" && next === "/") state = "line-comment";
|
|
4385
|
+
else if (char === "/" && next === "*") state = "block-comment";
|
|
4386
|
+
else if (char === "/" && isRegexStart(i)) state = "regex";
|
|
4387
|
+
else continue;
|
|
4388
|
+
masked[i] = " ";
|
|
4389
|
+
continue;
|
|
4390
|
+
}
|
|
4391
|
+
if (state === "line-comment") {
|
|
4392
|
+
if (char === "\n") {
|
|
4393
|
+
state = "code";
|
|
4394
|
+
} else {
|
|
4395
|
+
masked[i] = " ";
|
|
4396
|
+
}
|
|
4397
|
+
continue;
|
|
4398
|
+
}
|
|
4399
|
+
if (state === "block-comment") {
|
|
4400
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4401
|
+
if (char === "*" && next === "/") {
|
|
4402
|
+
masked[i + 1] = " ";
|
|
4403
|
+
i++;
|
|
4404
|
+
state = "code";
|
|
4405
|
+
}
|
|
4406
|
+
continue;
|
|
4407
|
+
}
|
|
4408
|
+
if (state === "regex" || state === "regex-class") {
|
|
4409
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4410
|
+
if (char === "\\") {
|
|
4411
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
4412
|
+
} else if (state === "regex" && char === "[") {
|
|
4413
|
+
state = "regex-class";
|
|
4414
|
+
} else if (state === "regex-class" && char === "]") {
|
|
4415
|
+
state = "regex";
|
|
4416
|
+
} else if (state === "regex" && char === "/") {
|
|
4417
|
+
state = "code";
|
|
4418
|
+
}
|
|
4419
|
+
continue;
|
|
4420
|
+
}
|
|
4421
|
+
masked[i] = char === "\n" ? "\n" : " ";
|
|
4422
|
+
if (char === "\\") {
|
|
4423
|
+
if (i + 1 < code.length) masked[++i] = " ";
|
|
4424
|
+
continue;
|
|
4425
|
+
}
|
|
4426
|
+
if (state === "single" && char === "'" || state === "double" && char === '"' || state === "template" && char === "`") {
|
|
4427
|
+
state = "code";
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
return masked.join("");
|
|
3602
4431
|
}
|
|
3603
4432
|
function resolveAliasTarget2(value, root) {
|
|
3604
|
-
if (
|
|
3605
|
-
if (value.startsWith("/")) return
|
|
3606
|
-
return
|
|
4433
|
+
if (import_node_path12.default.isAbsolute(value) && import_node_fs9.default.existsSync(value)) return value;
|
|
4434
|
+
if (value.startsWith("/")) return import_node_path12.default.join(root, value.slice(1));
|
|
4435
|
+
return import_node_path12.default.resolve(root, value);
|
|
3607
4436
|
}
|
|
3608
4437
|
function tryResolveDiskPath(target) {
|
|
3609
|
-
if (
|
|
4438
|
+
if (import_node_fs9.default.existsSync(target) && import_node_fs9.default.statSync(target).isFile()) return target;
|
|
3610
4439
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3611
4440
|
const withExt = target + ext;
|
|
3612
|
-
if (
|
|
4441
|
+
if (import_node_fs9.default.existsSync(withExt) && import_node_fs9.default.statSync(withExt).isFile()) return withExt;
|
|
3613
4442
|
}
|
|
3614
|
-
if (
|
|
4443
|
+
if (import_node_fs9.default.existsSync(target) && import_node_fs9.default.statSync(target).isDirectory()) {
|
|
3615
4444
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3616
|
-
const idx =
|
|
3617
|
-
if (
|
|
4445
|
+
const idx = import_node_path12.default.join(target, "index" + ext);
|
|
4446
|
+
if (import_node_fs9.default.existsSync(idx) && import_node_fs9.default.statSync(idx).isFile()) return idx;
|
|
3618
4447
|
}
|
|
3619
4448
|
}
|
|
3620
4449
|
return null;
|
|
3621
4450
|
}
|
|
3622
4451
|
function isUnderRoot(abs, root) {
|
|
3623
|
-
const rel =
|
|
3624
|
-
return !!rel && !rel.startsWith("..") && !
|
|
4452
|
+
const rel = import_node_path12.default.relative(root, abs);
|
|
4453
|
+
return !!rel && !rel.startsWith("..") && !import_node_path12.default.isAbsolute(rel);
|
|
4454
|
+
}
|
|
4455
|
+
function appendTimestampQuery(url, timestamp) {
|
|
4456
|
+
const hashIndex = url.indexOf("#");
|
|
4457
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
|
|
4458
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
4459
|
+
return `${withoutHash}${withoutHash.includes("?") ? "&" : "?"}t=${timestamp}${hash}`;
|
|
3625
4460
|
}
|
|
3626
4461
|
function externalSpecToModuleUrl(spec, baseDir, root) {
|
|
3627
4462
|
const resolved = resolveNodeModule(baseDir, spec);
|
|
@@ -3634,7 +4469,7 @@ function resolveNodeModule(baseDir, moduleName) {
|
|
|
3634
4469
|
const resolved = resolveNodeModuleEntry(baseDir, moduleName);
|
|
3635
4470
|
if (!resolved) return null;
|
|
3636
4471
|
try {
|
|
3637
|
-
return
|
|
4472
|
+
return import_node_fs9.default.realpathSync(resolved);
|
|
3638
4473
|
} catch {
|
|
3639
4474
|
return resolved;
|
|
3640
4475
|
}
|
|
@@ -3654,21 +4489,21 @@ function resolveNodeModuleEntry(root, moduleName) {
|
|
|
3654
4489
|
let pkgDir = null;
|
|
3655
4490
|
let dir = root;
|
|
3656
4491
|
for (; ; ) {
|
|
3657
|
-
const candidate =
|
|
3658
|
-
if (
|
|
4492
|
+
const candidate = import_node_path12.default.join(dir, "node_modules", pkgName);
|
|
4493
|
+
if (import_node_fs9.default.existsSync(candidate)) {
|
|
3659
4494
|
pkgDir = candidate;
|
|
3660
4495
|
break;
|
|
3661
4496
|
}
|
|
3662
|
-
const parent =
|
|
4497
|
+
const parent = import_node_path12.default.dirname(dir);
|
|
3663
4498
|
if (parent === dir) break;
|
|
3664
4499
|
dir = parent;
|
|
3665
4500
|
}
|
|
3666
4501
|
if (!pkgDir) return null;
|
|
3667
|
-
const pkgJsonPath =
|
|
3668
|
-
if (!
|
|
4502
|
+
const pkgJsonPath = import_node_path12.default.join(pkgDir, "package.json");
|
|
4503
|
+
if (!import_node_fs9.default.existsSync(pkgJsonPath)) return null;
|
|
3669
4504
|
let pkg;
|
|
3670
4505
|
try {
|
|
3671
|
-
pkg = JSON.parse(
|
|
4506
|
+
pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
3672
4507
|
} catch {
|
|
3673
4508
|
return null;
|
|
3674
4509
|
}
|
|
@@ -3681,32 +4516,32 @@ function resolveNodeModuleEntry(root, moduleName) {
|
|
|
3681
4516
|
const subDirs = [""];
|
|
3682
4517
|
for (const field of ["module", "main"]) {
|
|
3683
4518
|
if (typeof pkg[field] === "string") {
|
|
3684
|
-
const dir2 =
|
|
4519
|
+
const dir2 = import_node_path12.default.dirname(pkg[field]);
|
|
3685
4520
|
if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
|
|
3686
4521
|
}
|
|
3687
4522
|
}
|
|
3688
4523
|
for (const dir2 of subDirs) {
|
|
3689
|
-
const direct =
|
|
3690
|
-
if (
|
|
4524
|
+
const direct = import_node_path12.default.join(pkgDir, dir2, subpath);
|
|
4525
|
+
if (import_node_fs9.default.existsSync(direct) && import_node_fs9.default.statSync(direct).isFile()) return direct;
|
|
3691
4526
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3692
|
-
if (
|
|
4527
|
+
if (import_node_fs9.default.existsSync(direct + ext)) return direct + ext;
|
|
3693
4528
|
}
|
|
3694
4529
|
}
|
|
3695
4530
|
return null;
|
|
3696
4531
|
}
|
|
3697
4532
|
for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
|
|
3698
4533
|
if (typeof pkg[field] === "string") {
|
|
3699
|
-
const entry =
|
|
3700
|
-
if (
|
|
4534
|
+
const entry = import_node_path12.default.join(pkgDir, pkg[field]);
|
|
4535
|
+
if (import_node_fs9.default.existsSync(entry)) return entry;
|
|
3701
4536
|
}
|
|
3702
4537
|
}
|
|
3703
|
-
const indexFallback =
|
|
3704
|
-
if (
|
|
4538
|
+
const indexFallback = import_node_path12.default.join(pkgDir, "index.js");
|
|
4539
|
+
if (import_node_fs9.default.existsSync(indexFallback)) return indexFallback;
|
|
3705
4540
|
return null;
|
|
3706
4541
|
}
|
|
3707
4542
|
function resolvePackageExports(exports2, key, pkgDir) {
|
|
3708
4543
|
if (typeof exports2 === "string") {
|
|
3709
|
-
return key === "." ?
|
|
4544
|
+
return key === "." ? import_node_path12.default.join(pkgDir, exports2) : null;
|
|
3710
4545
|
}
|
|
3711
4546
|
const entry = exports2[key];
|
|
3712
4547
|
if (entry === void 0) {
|
|
@@ -3718,7 +4553,7 @@ function resolvePackageExports(exports2, key, pkgDir) {
|
|
|
3718
4553
|
return resolveExportValue(entry, pkgDir);
|
|
3719
4554
|
}
|
|
3720
4555
|
function resolveExportValue(value, pkgDir) {
|
|
3721
|
-
if (typeof value === "string") return
|
|
4556
|
+
if (typeof value === "string") return import_node_path12.default.join(pkgDir, value);
|
|
3722
4557
|
if (Array.isArray(value)) {
|
|
3723
4558
|
for (const item of value) {
|
|
3724
4559
|
const r = resolveExportValue(item, pkgDir);
|
|
@@ -3742,17 +4577,17 @@ function resolveUrlToFile(url, root) {
|
|
|
3742
4577
|
const moduleName = cleanUrl.slice("/@modules/".length);
|
|
3743
4578
|
return resolveNodeModule(root, moduleName);
|
|
3744
4579
|
}
|
|
3745
|
-
const filePath =
|
|
3746
|
-
if (
|
|
4580
|
+
const filePath = import_node_path12.default.resolve(root, cleanUrl.replace(/^\//, ""));
|
|
4581
|
+
if (import_node_fs9.default.existsSync(filePath) && import_node_fs9.default.statSync(filePath).isFile()) {
|
|
3747
4582
|
return filePath;
|
|
3748
4583
|
}
|
|
3749
4584
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3750
4585
|
const withExt = filePath + ext;
|
|
3751
|
-
if (
|
|
4586
|
+
if (import_node_fs9.default.existsSync(withExt)) return withExt;
|
|
3752
4587
|
}
|
|
3753
4588
|
for (const ext of RESOLVE_EXTENSIONS) {
|
|
3754
|
-
const indexFile =
|
|
3755
|
-
if (
|
|
4589
|
+
const indexFile = import_node_path12.default.join(filePath, "index" + ext);
|
|
4590
|
+
if (import_node_fs9.default.existsSync(indexFile)) return indexFile;
|
|
3756
4591
|
}
|
|
3757
4592
|
return null;
|
|
3758
4593
|
}
|
|
@@ -3760,36 +4595,35 @@ function isModuleRequest(url) {
|
|
|
3760
4595
|
const cleanUrl = url.split("?")[0];
|
|
3761
4596
|
if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
|
|
3762
4597
|
if (cleanUrl.startsWith("/@modules/")) return true;
|
|
3763
|
-
if (!
|
|
4598
|
+
if (!import_node_path12.default.extname(cleanUrl)) return true;
|
|
3764
4599
|
return false;
|
|
3765
4600
|
}
|
|
3766
4601
|
function getHmrClientCode() {
|
|
3767
4602
|
return `
|
|
3768
4603
|
// Nasti HMR Client
|
|
3769
|
-
const
|
|
4604
|
+
const socketProtocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
|
4605
|
+
const socket = new WebSocket(socketProtocol + '://' + location.host, 'nasti-hmr');
|
|
3770
4606
|
const hotModulesMap = new Map();
|
|
3771
4607
|
const disposeMap = new Map();
|
|
3772
4608
|
const pruneMap = new Map();
|
|
4609
|
+
const dataMap = new Map();
|
|
4610
|
+
let updateQueue = [];
|
|
4611
|
+
let pendingUpdateQueue = false;
|
|
3773
4612
|
|
|
3774
4613
|
socket.addEventListener('message', async ({ data }) => {
|
|
3775
4614
|
const payload = JSON.parse(data);
|
|
3776
4615
|
switch (payload.type) {
|
|
3777
4616
|
case 'connected':
|
|
3778
|
-
console.
|
|
4617
|
+
console.debug('[nasti] connected.');
|
|
3779
4618
|
clearErrorOverlay();
|
|
3780
4619
|
break;
|
|
3781
4620
|
case 'update':
|
|
3782
4621
|
try {
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
} else if (update.type === 'css-update') {
|
|
3787
|
-
return updateCss(update.path);
|
|
3788
|
-
}
|
|
3789
|
-
}));
|
|
4622
|
+
// CSS \u5728 unbundled \u6A21\u5F0F\u4E0B\u4E5F\u662F\u4F1A\u6CE8\u5165 <style> \u7684 JS \u6A21\u5757\uFF0C\u548C\u666E\u901A JS
|
|
4623
|
+
// \u4E00\u6837\u91CD\u65B0 import \u624D\u80FD\u6267\u884C dispose/accept \u5E76\u4FDD\u6301\u9875\u9762\u72B6\u6001\u3002
|
|
4624
|
+
await Promise.all(payload.updates.map(queueUpdate));
|
|
3790
4625
|
clearErrorOverlay();
|
|
3791
|
-
console.
|
|
3792
|
-
location.reload();
|
|
4626
|
+
console.debug('[nasti] HMR update complete.');
|
|
3793
4627
|
} catch (err) {
|
|
3794
4628
|
console.error('[nasti] HMR update failed:', err);
|
|
3795
4629
|
showErrorOverlay(err);
|
|
@@ -3800,10 +4634,17 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
3800
4634
|
location.reload();
|
|
3801
4635
|
break;
|
|
3802
4636
|
case 'prune':
|
|
3803
|
-
payload.paths.
|
|
3804
|
-
const
|
|
3805
|
-
|
|
3806
|
-
|
|
4637
|
+
await Promise.all(payload.paths.map(async (path) => {
|
|
4638
|
+
const data = dataMap.get(path);
|
|
4639
|
+
const dispose = disposeMap.get(path);
|
|
4640
|
+
const prune = pruneMap.get(path);
|
|
4641
|
+
if (dispose) await dispose(data);
|
|
4642
|
+
if (prune) await prune(data);
|
|
4643
|
+
hotModulesMap.delete(path);
|
|
4644
|
+
disposeMap.delete(path);
|
|
4645
|
+
pruneMap.delete(path);
|
|
4646
|
+
dataMap.delete(path);
|
|
4647
|
+
}));
|
|
3807
4648
|
break;
|
|
3808
4649
|
case 'error':
|
|
3809
4650
|
console.error('[nasti] error:', payload.err.message);
|
|
@@ -3812,33 +4653,64 @@ socket.addEventListener('message', async ({ data }) => {
|
|
|
3812
4653
|
}
|
|
3813
4654
|
});
|
|
3814
4655
|
|
|
3815
|
-
// \
|
|
4656
|
+
// \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
|
|
3816
4657
|
let reconnectTimer = 0;
|
|
3817
4658
|
socket.addEventListener('close', () => {
|
|
3818
4659
|
clearTimeout(reconnectTimer);
|
|
3819
4660
|
reconnectTimer = setTimeout(() => location.reload(), 1000);
|
|
3820
4661
|
});
|
|
3821
4662
|
|
|
4663
|
+
/**
|
|
4664
|
+
* \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
|
|
4665
|
+
* \u6539\u53D8\u6A21\u5757\u5E94\u7528\u987A\u5E8F\u3002\u8FD9\u4E0E Vite HMRClient \u7684 fetch/apply \u4E24\u9636\u6BB5\u4E00\u81F4\u3002
|
|
4666
|
+
*/
|
|
4667
|
+
async function queueUpdate(update) {
|
|
4668
|
+
updateQueue.push(fetchUpdate(update));
|
|
4669
|
+
if (pendingUpdateQueue) return;
|
|
4670
|
+
|
|
4671
|
+
pendingUpdateQueue = true;
|
|
4672
|
+
await Promise.resolve();
|
|
4673
|
+
pendingUpdateQueue = false;
|
|
4674
|
+
const loading = updateQueue;
|
|
4675
|
+
updateQueue = [];
|
|
4676
|
+
const applyUpdates = await Promise.all(loading);
|
|
4677
|
+
for (const apply of applyUpdates) {
|
|
4678
|
+
if (apply) apply();
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
|
|
3822
4682
|
async function fetchUpdate(update) {
|
|
3823
4683
|
const mod = hotModulesMap.get(update.path);
|
|
3824
|
-
// \
|
|
3825
|
-
|
|
3826
|
-
if (dispose) dispose();
|
|
4684
|
+
// \u5C1A\u672A\u5728\u5F53\u524D\u9875\u9762\u52A0\u8F7D\u7684\u52A8\u6001\u6A21\u5757\u4E0D\u9700\u8981\u66F4\u65B0\u3002
|
|
4685
|
+
if (!mod) return;
|
|
3827
4686
|
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
4687
|
+
// \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
|
|
4688
|
+
const qualifiedCallbacks = mod.callbacks.filter(({ deps }) =>
|
|
4689
|
+
deps.includes(update.acceptedPath)
|
|
4690
|
+
);
|
|
4691
|
+
const isSelfUpdate = update.path === update.acceptedPath;
|
|
4692
|
+
if (!isSelfUpdate && qualifiedCallbacks.length === 0) return;
|
|
4693
|
+
|
|
4694
|
+
const dispose = disposeMap.get(update.acceptedPath);
|
|
4695
|
+
if (dispose) await dispose(dataMap.get(update.acceptedPath));
|
|
4696
|
+
const newMod = await import(appendTimestampQuery(update.acceptedPath, update.timestamp));
|
|
4697
|
+
|
|
4698
|
+
return () => {
|
|
4699
|
+
for (const { deps, fn } of qualifiedCallbacks) {
|
|
4700
|
+
fn(deps.map((dep) => dep === update.acceptedPath ? newMod : undefined));
|
|
4701
|
+
}
|
|
4702
|
+
const detail = isSelfUpdate
|
|
4703
|
+
? update.path
|
|
4704
|
+
: update.acceptedPath + ' via ' + update.path;
|
|
4705
|
+
console.debug('[nasti] hot updated:', detail);
|
|
4706
|
+
};
|
|
3833
4707
|
}
|
|
3834
4708
|
|
|
3835
|
-
function
|
|
3836
|
-
const
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
.then(css => { el.textContent = css; });
|
|
3841
|
-
}
|
|
4709
|
+
function appendTimestampQuery(url, timestamp) {
|
|
4710
|
+
const hashIndex = url.indexOf('#');
|
|
4711
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : '';
|
|
4712
|
+
const withoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
4713
|
+
return withoutHash + (withoutHash.includes('?') ? '&' : '?') + 't=' + timestamp + hash;
|
|
3842
4714
|
}
|
|
3843
4715
|
|
|
3844
4716
|
function clearErrorOverlay() {
|
|
@@ -3866,23 +4738,30 @@ function showErrorOverlay(err) {
|
|
|
3866
4738
|
document.body.appendChild(overlay);
|
|
3867
4739
|
}
|
|
3868
4740
|
|
|
3869
|
-
/**
|
|
3870
|
-
* \u751F\u6210 import.meta.hot \u7684 hot context\u3002
|
|
3871
|
-
* \u5173\u952E\u7EA6\u675F\uFF1A\u540C\u4E00 ownerPath \u7684 accept \u56DE\u8C03\u5FC5\u987B\u66FF\u6362\uFF08\u4E0D\u662F append\uFF09\u3002
|
|
3872
|
-
* \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
|
|
3873
|
-
* \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
|
|
3874
|
-
*/
|
|
3875
4741
|
export function createHotContext(ownerPath) {
|
|
4742
|
+
if (!dataMap.has(ownerPath)) dataMap.set(ownerPath, {});
|
|
4743
|
+
|
|
4744
|
+
// \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
|
|
4745
|
+
const existing = hotModulesMap.get(ownerPath);
|
|
4746
|
+
if (existing) existing.callbacks = [];
|
|
4747
|
+
|
|
4748
|
+
const acceptDeps = (deps, callback = () => {}) => {
|
|
4749
|
+
const mod = hotModulesMap.get(ownerPath) || { id: ownerPath, callbacks: [] };
|
|
4750
|
+
mod.callbacks.push({ deps, fn: callback });
|
|
4751
|
+
hotModulesMap.set(ownerPath, mod);
|
|
4752
|
+
};
|
|
4753
|
+
|
|
3876
4754
|
return {
|
|
3877
4755
|
accept(deps, callback) {
|
|
3878
|
-
// \u81EA\u63A5\u53D7: hot.accept() \u6216 hot.accept(callback)
|
|
3879
4756
|
if (typeof deps === 'function' || deps === undefined) {
|
|
3880
|
-
|
|
3881
|
-
|
|
4757
|
+
acceptDeps([ownerPath], ([mod]) => deps?.(mod));
|
|
4758
|
+
} else if (typeof deps === 'string') {
|
|
4759
|
+
acceptDeps([deps], ([mod]) => callback?.(mod));
|
|
4760
|
+
} else if (Array.isArray(deps)) {
|
|
4761
|
+
acceptDeps(deps, callback);
|
|
4762
|
+
} else {
|
|
4763
|
+
throw new Error('invalid hot.accept() usage');
|
|
3882
4764
|
}
|
|
3883
|
-
// \u4F9D\u8D56\u63A5\u53D7: hot.accept(deps, callback)\uFF0C\u591A\u6B21\u8C03\u7528\u8FFD\u52A0
|
|
3884
|
-
const existing = hotModulesMap.get(ownerPath)?.callbacks ?? [];
|
|
3885
|
-
hotModulesMap.set(ownerPath, { callbacks: [...existing, callback] });
|
|
3886
4765
|
},
|
|
3887
4766
|
prune(callback) {
|
|
3888
4767
|
pruneMap.set(ownerPath, callback);
|
|
@@ -3893,27 +4772,91 @@ export function createHotContext(ownerPath) {
|
|
|
3893
4772
|
invalidate() {
|
|
3894
4773
|
location.reload();
|
|
3895
4774
|
},
|
|
3896
|
-
data:
|
|
4775
|
+
data: dataMap.get(ownerPath),
|
|
3897
4776
|
};
|
|
3898
4777
|
}
|
|
3899
4778
|
`;
|
|
3900
4779
|
}
|
|
3901
|
-
var
|
|
4780
|
+
var import_node_path12, import_node_fs9, import_node_module5, import_node_url3, import_picocolors6, import_meta, __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
|
|
3902
4781
|
var init_middleware = __esm({
|
|
3903
4782
|
"src/server/middleware.ts"() {
|
|
3904
4783
|
"use strict";
|
|
3905
|
-
|
|
3906
|
-
|
|
4784
|
+
import_node_path12 = __toESM(require("path"), 1);
|
|
4785
|
+
import_node_fs9 = __toESM(require("fs"), 1);
|
|
3907
4786
|
import_node_module5 = require("module");
|
|
3908
4787
|
import_node_url3 = require("url");
|
|
3909
4788
|
import_picocolors6 = __toESM(require("picocolors"), 1);
|
|
3910
4789
|
init_transformer();
|
|
3911
4790
|
init_html();
|
|
3912
4791
|
init_env();
|
|
4792
|
+
init_url();
|
|
3913
4793
|
import_meta = {};
|
|
3914
|
-
__dirname_esm =
|
|
4794
|
+
__dirname_esm = import_node_path12.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
|
|
3915
4795
|
__require = (0, import_node_module5.createRequire)(import_meta.url);
|
|
3916
4796
|
__refreshRuntimeCache = null;
|
|
4797
|
+
REACT_REFRESH_BOUNDARY_HELPERS = `
|
|
4798
|
+
function __nastiIsPlainObject(obj) {
|
|
4799
|
+
return Object.prototype.toString.call(obj) === '[object Object]' &&
|
|
4800
|
+
(obj.constructor === Object || obj.constructor === undefined);
|
|
4801
|
+
}
|
|
4802
|
+
function __nastiIsCompoundComponent(type) {
|
|
4803
|
+
if (!__nastiIsPlainObject(type)) return false;
|
|
4804
|
+
for (const key in type) {
|
|
4805
|
+
if (!isLikelyComponentType(type[key])) return false;
|
|
4806
|
+
}
|
|
4807
|
+
return true;
|
|
4808
|
+
}
|
|
4809
|
+
export function registerExportsForReactRefresh(filename, moduleExports) {
|
|
4810
|
+
for (const key in moduleExports) {
|
|
4811
|
+
if (key === '__esModule') continue;
|
|
4812
|
+
const value = moduleExports[key];
|
|
4813
|
+
if (isLikelyComponentType(value)) {
|
|
4814
|
+
register(value, filename + ' export ' + key);
|
|
4815
|
+
} else if (__nastiIsCompoundComponent(value)) {
|
|
4816
|
+
for (const subKey in value) {
|
|
4817
|
+
register(value[subKey], filename + ' export ' + key + '-' + subKey);
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
let __nastiRefreshTimer;
|
|
4823
|
+
function __nastiEnqueueRefresh() {
|
|
4824
|
+
clearTimeout(__nastiRefreshTimer);
|
|
4825
|
+
__nastiRefreshTimer = setTimeout(() => performReactRefresh(), 16);
|
|
4826
|
+
}
|
|
4827
|
+
function __nastiCheckExports(ignored, exports, predicate) {
|
|
4828
|
+
for (const key in exports) {
|
|
4829
|
+
if (ignored.includes(key)) continue;
|
|
4830
|
+
if (!predicate(key, exports[key])) return key;
|
|
4831
|
+
}
|
|
4832
|
+
return true;
|
|
4833
|
+
}
|
|
4834
|
+
export function validateRefreshBoundaryAndEnqueueUpdate(id, prevExports, nextExports) {
|
|
4835
|
+
const ignored = window.__getReactRefreshIgnoredExports?.({ id }) ?? [];
|
|
4836
|
+
if (__nastiCheckExports(ignored, prevExports, (key) => key in nextExports) !== true) {
|
|
4837
|
+
return 'Could not Fast Refresh (export removed)';
|
|
4838
|
+
}
|
|
4839
|
+
if (__nastiCheckExports(ignored, nextExports, (key) => key in prevExports) !== true) {
|
|
4840
|
+
return 'Could not Fast Refresh (new export)';
|
|
4841
|
+
}
|
|
4842
|
+
let hasExports = false;
|
|
4843
|
+
const compatible = __nastiCheckExports(ignored, nextExports, (key, value) => {
|
|
4844
|
+
hasExports = true;
|
|
4845
|
+
return isLikelyComponentType(value) ||
|
|
4846
|
+
__nastiIsCompoundComponent(value) ||
|
|
4847
|
+
prevExports[key] === value;
|
|
4848
|
+
});
|
|
4849
|
+
if (!hasExports) {
|
|
4850
|
+
return 'Could not Fast Refresh (no exports)';
|
|
4851
|
+
}
|
|
4852
|
+
if (compatible === true) {
|
|
4853
|
+
__nastiEnqueueRefresh();
|
|
4854
|
+
return;
|
|
4855
|
+
}
|
|
4856
|
+
return 'Could not Fast Refresh ("' + compatible + '" export is incompatible)';
|
|
4857
|
+
}
|
|
4858
|
+
export const __hmr_import = (module) => import(module);
|
|
4859
|
+
`;
|
|
3917
4860
|
REACT_REFRESH_GLOBAL_PREAMBLE = `
|
|
3918
4861
|
import RefreshRuntime from "/@react-refresh";
|
|
3919
4862
|
RefreshRuntime.injectIntoGlobalHook(window);
|
|
@@ -3932,21 +4875,23 @@ window.__vite_plugin_react_preamble_installed__ = true;
|
|
|
3932
4875
|
async function handleFileChange(file, server) {
|
|
3933
4876
|
const { moduleGraph, ws, config } = server;
|
|
3934
4877
|
const logger = config.logger;
|
|
3935
|
-
const relativePath = "/" +
|
|
3936
|
-
const shortFile =
|
|
4878
|
+
const relativePath = "/" + import_node_path13.default.relative(config.root, file);
|
|
4879
|
+
const shortFile = import_node_path13.default.relative(config.root, file);
|
|
3937
4880
|
const mods = moduleGraph.getModulesByFile(file);
|
|
3938
4881
|
if (!mods || mods.size === 0) {
|
|
3939
4882
|
return;
|
|
3940
4883
|
}
|
|
3941
4884
|
const updates = [];
|
|
3942
4885
|
const timestamp = Date.now();
|
|
4886
|
+
const graph = moduleGraph;
|
|
4887
|
+
const invalidatedModules = /* @__PURE__ */ new Set();
|
|
3943
4888
|
for (const mod of mods) {
|
|
3944
|
-
|
|
4889
|
+
graph.invalidateModuleAndImporters(mod, timestamp, invalidatedModules);
|
|
3945
4890
|
const ctx = {
|
|
3946
4891
|
file,
|
|
3947
4892
|
timestamp,
|
|
3948
4893
|
modules: [mod],
|
|
3949
|
-
read: () =>
|
|
4894
|
+
read: () => import_node_fs10.default.readFileSync(file, "utf-8"),
|
|
3950
4895
|
server
|
|
3951
4896
|
};
|
|
3952
4897
|
let affectedModules = [mod];
|
|
@@ -3959,19 +4904,25 @@ async function handleFileChange(file, server) {
|
|
|
3959
4904
|
}
|
|
3960
4905
|
}
|
|
3961
4906
|
for (const affected of affectedModules) {
|
|
3962
|
-
|
|
4907
|
+
graph.invalidateModuleAndImporters(affected, timestamp, invalidatedModules);
|
|
4908
|
+
const boundaries = graph.getHmrBoundaries(affected);
|
|
3963
4909
|
if (boundaries.length === 0) {
|
|
3964
4910
|
logger.info(import_picocolors7.default.green("page reload ") + import_picocolors7.default.dim(shortFile), { timestamp: true });
|
|
3965
4911
|
ws.send({ type: "full-reload", path: relativePath });
|
|
3966
4912
|
return;
|
|
3967
4913
|
}
|
|
3968
|
-
for (const { boundary } of boundaries) {
|
|
3969
|
-
|
|
4914
|
+
for (const { boundary, acceptedVia } of boundaries) {
|
|
4915
|
+
const update = {
|
|
3970
4916
|
type: boundary.type === "css" ? "css-update" : "js-update",
|
|
3971
4917
|
path: boundary.url,
|
|
3972
|
-
acceptedPath:
|
|
4918
|
+
acceptedPath: acceptedVia.url,
|
|
3973
4919
|
timestamp
|
|
3974
|
-
}
|
|
4920
|
+
};
|
|
4921
|
+
if (!updates.some(
|
|
4922
|
+
(existing) => existing.type === update.type && existing.path === update.path && existing.acceptedPath === update.acceptedPath
|
|
4923
|
+
)) {
|
|
4924
|
+
updates.push(update);
|
|
4925
|
+
}
|
|
3975
4926
|
}
|
|
3976
4927
|
}
|
|
3977
4928
|
}
|
|
@@ -3983,12 +4934,12 @@ async function handleFileChange(file, server) {
|
|
|
3983
4934
|
ws.send({ type: "update", updates });
|
|
3984
4935
|
}
|
|
3985
4936
|
}
|
|
3986
|
-
var
|
|
4937
|
+
var import_node_path13, import_node_fs10, import_picocolors7;
|
|
3987
4938
|
var init_hmr = __esm({
|
|
3988
4939
|
"src/server/hmr.ts"() {
|
|
3989
4940
|
"use strict";
|
|
3990
|
-
|
|
3991
|
-
|
|
4941
|
+
import_node_path13 = __toESM(require("path"), 1);
|
|
4942
|
+
import_node_fs10 = __toESM(require("fs"), 1);
|
|
3992
4943
|
import_picocolors7 = __toESM(require("picocolors"), 1);
|
|
3993
4944
|
}
|
|
3994
4945
|
});
|
|
@@ -4007,12 +4958,12 @@ function createModuleRunner(environment) {
|
|
|
4007
4958
|
}
|
|
4008
4959
|
return new NastiModuleRunner(environment);
|
|
4009
4960
|
}
|
|
4010
|
-
var
|
|
4961
|
+
var import_node_path14, import_node_fs11, import_node_module6, import_node_url4, debug5, NODE_BUILTINS3, NastiModuleRunner, AsyncFunction;
|
|
4011
4962
|
var init_runnable_environment = __esm({
|
|
4012
4963
|
"src/server/runnable-environment.ts"() {
|
|
4013
4964
|
"use strict";
|
|
4014
|
-
|
|
4015
|
-
|
|
4965
|
+
import_node_path14 = __toESM(require("path"), 1);
|
|
4966
|
+
import_node_fs11 = __toESM(require("fs"), 1);
|
|
4016
4967
|
import_node_module6 = require("module");
|
|
4017
4968
|
import_node_url4 = require("url");
|
|
4018
4969
|
init_transformer();
|
|
@@ -4034,7 +4985,7 @@ var init_runnable_environment = __esm({
|
|
|
4034
4985
|
this.config.mode,
|
|
4035
4986
|
ssrDefineOverrides(environment.consumer)
|
|
4036
4987
|
);
|
|
4037
|
-
this.require = (0, import_node_module6.createRequire)(
|
|
4988
|
+
this.require = (0, import_node_module6.createRequire)(import_node_path14.default.join(this.config.root, "package.json"));
|
|
4038
4989
|
const handlers = {
|
|
4039
4990
|
fetchModule: async (id, importer) => this.fetchModule(id, importer),
|
|
4040
4991
|
getBuiltins: () => [/^node:/, ...import_node_module6.builtinModules]
|
|
@@ -4058,9 +5009,9 @@ var init_runnable_environment = __esm({
|
|
|
4058
5009
|
this.cache.clear();
|
|
4059
5010
|
}
|
|
4060
5011
|
resolveToId(rawUrl) {
|
|
4061
|
-
if (
|
|
5012
|
+
if (import_node_path14.default.isAbsolute(rawUrl) && import_node_fs11.default.existsSync(rawUrl.split("?")[0])) return rawUrl;
|
|
4062
5013
|
const clean = rawUrl.replace(/^\//, "");
|
|
4063
|
-
return
|
|
5014
|
+
return import_node_path14.default.resolve(this.config.root, clean);
|
|
4064
5015
|
}
|
|
4065
5016
|
/**
|
|
4066
5017
|
* fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
|
|
@@ -4069,14 +5020,14 @@ var init_runnable_environment = __esm({
|
|
|
4069
5020
|
*/
|
|
4070
5021
|
async fetchModule(id, importer) {
|
|
4071
5022
|
if (NODE_BUILTINS3.has(id)) return { externalize: id };
|
|
4072
|
-
if (!id.startsWith(".") && !
|
|
5023
|
+
if (!id.startsWith(".") && !import_node_path14.default.isAbsolute(id) && !id.startsWith("\0")) {
|
|
4073
5024
|
return { externalize: id };
|
|
4074
5025
|
}
|
|
4075
5026
|
const container = this.environment.pluginContainer;
|
|
4076
5027
|
let resolvedId = id;
|
|
4077
5028
|
if (id.startsWith(".") && importer) {
|
|
4078
5029
|
const resolved = await container.resolveId(id, importer);
|
|
4079
|
-
resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id :
|
|
5030
|
+
resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : import_node_path14.default.resolve(import_node_path14.default.dirname(importer.split("?")[0]), id);
|
|
4080
5031
|
}
|
|
4081
5032
|
resolvedId = this.completeExtension(resolvedId);
|
|
4082
5033
|
const cleanId = resolvedId.split("?")[0];
|
|
@@ -4084,8 +5035,8 @@ var init_runnable_environment = __esm({
|
|
|
4084
5035
|
const loaded = await container.load(resolvedId);
|
|
4085
5036
|
if (loaded != null) {
|
|
4086
5037
|
code = typeof loaded === "string" ? loaded : loaded.code;
|
|
4087
|
-
} else if (
|
|
4088
|
-
code =
|
|
5038
|
+
} else if (import_node_fs11.default.existsSync(cleanId)) {
|
|
5039
|
+
code = import_node_fs11.default.readFileSync(cleanId, "utf-8");
|
|
4089
5040
|
} else {
|
|
4090
5041
|
throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
|
|
4091
5042
|
}
|
|
@@ -4118,19 +5069,19 @@ var init_runnable_environment = __esm({
|
|
|
4118
5069
|
completeExtension(id) {
|
|
4119
5070
|
const clean = id.split("?")[0];
|
|
4120
5071
|
const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
|
|
4121
|
-
if (
|
|
5072
|
+
if (import_node_fs11.default.existsSync(clean) && import_node_fs11.default.statSync(clean).isFile()) return id;
|
|
4122
5073
|
const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
|
|
4123
5074
|
if (jsMatch) {
|
|
4124
5075
|
for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
|
|
4125
|
-
if (
|
|
5076
|
+
if (import_node_fs11.default.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
|
|
4126
5077
|
}
|
|
4127
5078
|
}
|
|
4128
5079
|
for (const ext of this.config.resolve.extensions) {
|
|
4129
|
-
if (
|
|
5080
|
+
if (import_node_fs11.default.existsSync(clean + ext)) return clean + ext + query;
|
|
4130
5081
|
}
|
|
4131
5082
|
for (const ext of this.config.resolve.extensions) {
|
|
4132
|
-
const indexPath =
|
|
4133
|
-
if (
|
|
5083
|
+
const indexPath = import_node_path14.default.join(clean, `index${ext}`);
|
|
5084
|
+
if (import_node_fs11.default.existsSync(indexPath)) return indexPath;
|
|
4134
5085
|
}
|
|
4135
5086
|
return id;
|
|
4136
5087
|
}
|
|
@@ -4157,10 +5108,10 @@ var init_runnable_environment = __esm({
|
|
|
4157
5108
|
return;
|
|
4158
5109
|
}
|
|
4159
5110
|
const ssrImport = async (dep) => {
|
|
4160
|
-
if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !
|
|
5111
|
+
if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !import_node_path14.default.isAbsolute(dep) && !dep.startsWith("\0")) {
|
|
4161
5112
|
return this.importExternal(dep);
|
|
4162
5113
|
}
|
|
4163
|
-
const depId = dep.startsWith(".") ? this.completeExtension(
|
|
5114
|
+
const depId = dep.startsWith(".") ? this.completeExtension(import_node_path14.default.resolve(import_node_path14.default.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
|
|
4164
5115
|
return this.instantiate(depId);
|
|
4165
5116
|
};
|
|
4166
5117
|
const ssrExportAll = (sourceModule) => {
|
|
@@ -4192,7 +5143,7 @@ var init_runnable_environment = __esm({
|
|
|
4192
5143
|
}
|
|
4193
5144
|
async importExternal(spec) {
|
|
4194
5145
|
try {
|
|
4195
|
-
return await (spec.startsWith("node:") || !
|
|
5146
|
+
return await (spec.startsWith("node:") || !import_node_path14.default.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import((0, import_node_url4.pathToFileURL)(spec).href));
|
|
4196
5147
|
} catch (err) {
|
|
4197
5148
|
throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
|
|
4198
5149
|
}
|
|
@@ -4235,7 +5186,7 @@ async function createBundledDevServer(opts) {
|
|
|
4235
5186
|
`[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.`
|
|
4236
5187
|
);
|
|
4237
5188
|
}
|
|
4238
|
-
const html = await readHtmlFile(config.root);
|
|
5189
|
+
const html = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4239
5190
|
const entryPoints = resolveClientEntries(config, html);
|
|
4240
5191
|
if (entryPoints.length === 0) {
|
|
4241
5192
|
throw new Error("No entry point found. Add a <script> tag to index.html or create src/main.ts");
|
|
@@ -4250,7 +5201,7 @@ async function createBundledDevServer(opts) {
|
|
|
4250
5201
|
createReactRefreshRuntimePlugin(entryPoints),
|
|
4251
5202
|
createBundledOxcRefreshPlugin()
|
|
4252
5203
|
] : [],
|
|
4253
|
-
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins)),
|
|
5204
|
+
...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
|
|
4254
5205
|
...useReactRefresh ? [
|
|
4255
5206
|
refreshWrapperFn({
|
|
4256
5207
|
cwd: config.root,
|
|
@@ -4299,7 +5250,7 @@ async function createBundledDevServer(opts) {
|
|
|
4299
5250
|
}
|
|
4300
5251
|
const url = `/${patchPath}`;
|
|
4301
5252
|
logger.info(
|
|
4302
|
-
import_picocolors8.default.green("hmr update ") + import_picocolors8.default.dim(changedFiles.map((f) =>
|
|
5253
|
+
import_picocolors8.default.green("hmr update ") + import_picocolors8.default.dim(changedFiles.map((f) => import_node_path15.default.relative(config.root, f)).join(", ")),
|
|
4303
5254
|
{ timestamp: true }
|
|
4304
5255
|
);
|
|
4305
5256
|
sendTo(clientId, { type: "hmr:update", path: url, url });
|
|
@@ -4435,13 +5386,13 @@ async function createBundledDevServer(opts) {
|
|
|
4435
5386
|
return;
|
|
4436
5387
|
}
|
|
4437
5388
|
res.setHeader("ETag", hit.etag);
|
|
4438
|
-
res.setHeader("Content-Type", MIME_TYPES[
|
|
5389
|
+
res.setHeader("Content-Type", MIME_TYPES[import_node_path15.default.extname(fileName)] ?? "application/octet-stream");
|
|
4439
5390
|
res.setHeader("Cache-Control", "no-cache");
|
|
4440
5391
|
res.end(hit.content);
|
|
4441
5392
|
return;
|
|
4442
5393
|
}
|
|
4443
5394
|
if (pathname === "/" || pathname.endsWith(".html")) {
|
|
4444
|
-
const rawHtml = await readHtmlFile(config.root);
|
|
5395
|
+
const rawHtml = await readHtmlFile(config.root, config.environments.client?.html);
|
|
4445
5396
|
if (rawHtml) {
|
|
4446
5397
|
res.setHeader("Content-Type", "text/html");
|
|
4447
5398
|
res.setHeader("Cache-Control", "no-store");
|
|
@@ -4471,7 +5422,7 @@ function stripCatchAllLoad(plugins) {
|
|
|
4471
5422
|
);
|
|
4472
5423
|
}
|
|
4473
5424
|
function createReactRefreshRuntimePlugin(entryPoints) {
|
|
4474
|
-
const entryIds = new Set(entryPoints.map((p) =>
|
|
5425
|
+
const entryIds = new Set(entryPoints.map((p) => import_node_path15.default.resolve(p)));
|
|
4475
5426
|
return {
|
|
4476
5427
|
name: "nasti:bundled-react-refresh",
|
|
4477
5428
|
resolveId(source) {
|
|
@@ -4489,7 +5440,7 @@ function createReactRefreshRuntimePlugin(entryPoints) {
|
|
|
4489
5440
|
return null;
|
|
4490
5441
|
},
|
|
4491
5442
|
transform(code, id) {
|
|
4492
|
-
if (!entryIds.has(
|
|
5443
|
+
if (!entryIds.has(import_node_path15.default.resolve(id.split("?")[0]))) return null;
|
|
4493
5444
|
return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
|
|
4494
5445
|
${code}`, map: null };
|
|
4495
5446
|
}
|
|
@@ -4525,19 +5476,22 @@ async function renderBundledIndexHtml(html, config, entryFileNames) {
|
|
|
4525
5476
|
}
|
|
4526
5477
|
}
|
|
4527
5478
|
for (const [facadeModuleId, fileName] of entryFileNames) {
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
5479
|
+
processed = replaceEntryScript(
|
|
5480
|
+
processed,
|
|
5481
|
+
facadeModuleId,
|
|
5482
|
+
fileName,
|
|
5483
|
+
config,
|
|
5484
|
+
config.environments.client?.html ?? "index.html",
|
|
5485
|
+
"/"
|
|
4532
5486
|
);
|
|
4533
5487
|
}
|
|
4534
5488
|
return processed;
|
|
4535
5489
|
}
|
|
4536
|
-
var
|
|
5490
|
+
var import_node_path15, import_node_crypto3, import_ws2, import_picocolors8, debug6, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
|
|
4537
5491
|
var init_dev_engine = __esm({
|
|
4538
5492
|
"src/server/bundled/dev-engine.ts"() {
|
|
4539
5493
|
"use strict";
|
|
4540
|
-
|
|
5494
|
+
import_node_path15 = __toESM(require("path"), 1);
|
|
4541
5495
|
import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
4542
5496
|
import_ws2 = require("ws");
|
|
4543
5497
|
import_picocolors8 = __toESM(require("picocolors"), 1);
|
|
@@ -4664,27 +5618,38 @@ async function createServer(inlineConfig = {}) {
|
|
|
4664
5618
|
const startTime = performance.now();
|
|
4665
5619
|
const config = await resolveConfig(inlineConfig, "serve");
|
|
4666
5620
|
const logger = config.logger;
|
|
4667
|
-
const allPlugins = resolvePluginList(config, config.plugins
|
|
5621
|
+
const allPlugins = resolvePluginList(config, config.plugins, {
|
|
5622
|
+
environmentName: "client"
|
|
5623
|
+
});
|
|
4668
5624
|
const configWithPlugins = { ...config, plugins: allPlugins };
|
|
4669
5625
|
const app = (0, import_connect.default)();
|
|
4670
5626
|
const httpServer = import_node_http.default.createServer(app);
|
|
4671
5627
|
const ws = createWebSocketServer(httpServer);
|
|
4672
|
-
const
|
|
5628
|
+
const pluginApi = getPluginApi(config);
|
|
5629
|
+
const clientEnv = new NastiEnvironment("client", config, {
|
|
4673
5630
|
hot: createWsHotChannel(ws),
|
|
4674
5631
|
mode: "dev",
|
|
4675
|
-
plugins: allPlugins
|
|
5632
|
+
plugins: allPlugins,
|
|
5633
|
+
pluginApi
|
|
4676
5634
|
});
|
|
4677
5635
|
await clientEnv.init();
|
|
4678
5636
|
const environments = { client: clientEnv };
|
|
4679
5637
|
for (const name of Object.keys(config.environments)) {
|
|
4680
5638
|
if (name === "client") continue;
|
|
4681
5639
|
const consumer = config.environments[name].consumer;
|
|
4682
|
-
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
4683
|
-
|
|
5640
|
+
const envPlugins = resolvePluginList(config, config.plugins, {
|
|
5641
|
+
consumer,
|
|
5642
|
+
environmentName: name
|
|
5643
|
+
});
|
|
5644
|
+
environments[name] = new NastiEnvironment(name, config, {
|
|
4684
5645
|
mode: "dev",
|
|
4685
|
-
plugins: envPlugins
|
|
5646
|
+
plugins: envPlugins,
|
|
5647
|
+
pluginApi
|
|
4686
5648
|
});
|
|
4687
5649
|
}
|
|
5650
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5651
|
+
if (name !== "client" && environment.options.driver) await environment.init();
|
|
5652
|
+
}
|
|
4688
5653
|
let ssrRunner = null;
|
|
4689
5654
|
async function getSsrRunner() {
|
|
4690
5655
|
if (ssrRunner) return ssrRunner;
|
|
@@ -4709,23 +5674,15 @@ async function createServer(inlineConfig = {}) {
|
|
|
4709
5674
|
});
|
|
4710
5675
|
app.use(bundledServer.middleware);
|
|
4711
5676
|
}
|
|
4712
|
-
app.use(transformMiddleware({
|
|
4713
|
-
config: configWithPlugins,
|
|
4714
|
-
pluginContainer,
|
|
4715
|
-
moduleGraph
|
|
4716
|
-
}));
|
|
4717
|
-
const publicDir = import_node_path15.default.resolve(config.root, "public");
|
|
4718
|
-
app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
|
|
4719
|
-
app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
|
|
4720
5677
|
const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
|
|
4721
|
-
const outDirAbs =
|
|
5678
|
+
const outDirAbs = import_node_path16.default.resolve(config.root, config.build.outDir);
|
|
4722
5679
|
const watcher = (0, import_chokidar.watch)(config.root, {
|
|
4723
5680
|
ignored: (filePath) => {
|
|
4724
5681
|
if (filePath === config.root) return false;
|
|
4725
|
-
if (filePath === outDirAbs || filePath.startsWith(outDirAbs +
|
|
4726
|
-
const rel =
|
|
4727
|
-
if (!rel || rel.startsWith("..") ||
|
|
4728
|
-
for (const seg of rel.split(
|
|
5682
|
+
if (filePath === outDirAbs || filePath.startsWith(outDirAbs + import_node_path16.default.sep)) return true;
|
|
5683
|
+
const rel = import_node_path16.default.relative(config.root, filePath);
|
|
5684
|
+
if (!rel || rel.startsWith("..") || import_node_path16.default.isAbsolute(rel)) return false;
|
|
5685
|
+
for (const seg of rel.split(import_node_path16.default.sep)) {
|
|
4729
5686
|
if (ignoredSegments.has(seg)) return true;
|
|
4730
5687
|
}
|
|
4731
5688
|
return false;
|
|
@@ -4733,13 +5690,72 @@ async function createServer(inlineConfig = {}) {
|
|
|
4733
5690
|
ignoreInitial: true
|
|
4734
5691
|
});
|
|
4735
5692
|
let server;
|
|
5693
|
+
const environmentServices = {};
|
|
5694
|
+
let environmentDriversStarted = false;
|
|
5695
|
+
const logCloseError = (target, error) => {
|
|
5696
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
5697
|
+
logger.error(`[nasti] failed to close ${target}`, { error: normalized });
|
|
5698
|
+
};
|
|
5699
|
+
const startEnvironmentDrivers = async () => {
|
|
5700
|
+
if (environmentDriversStarted) return;
|
|
5701
|
+
environmentDriversStarted = true;
|
|
5702
|
+
const started = [];
|
|
5703
|
+
const attempted = [];
|
|
5704
|
+
try {
|
|
5705
|
+
for (const [name, environment] of Object.entries(environments)) {
|
|
5706
|
+
if (!environment.driver?.serve) continue;
|
|
5707
|
+
attempted.push(environment);
|
|
5708
|
+
const result = await environment.driver.serve({
|
|
5709
|
+
...environment.getDriverContext(),
|
|
5710
|
+
server
|
|
5711
|
+
});
|
|
5712
|
+
started.push({ name, environment, service: result ?? {} });
|
|
5713
|
+
}
|
|
5714
|
+
for (const { name, service } of started) {
|
|
5715
|
+
environmentServices[name] = service;
|
|
5716
|
+
if (service.middleware) app.use(service.middleware);
|
|
5717
|
+
}
|
|
5718
|
+
} catch (error) {
|
|
5719
|
+
environmentDriversStarted = false;
|
|
5720
|
+
for (const { name } of started) {
|
|
5721
|
+
delete environmentServices[name];
|
|
5722
|
+
}
|
|
5723
|
+
for (const environment of attempted.reverse()) {
|
|
5724
|
+
try {
|
|
5725
|
+
await environment.driver?.close?.(environment.getDriverContext());
|
|
5726
|
+
} catch (closeError) {
|
|
5727
|
+
logCloseError(`environment driver "${environment.driver.name}"`, closeError);
|
|
5728
|
+
}
|
|
5729
|
+
}
|
|
5730
|
+
throw error;
|
|
5731
|
+
}
|
|
5732
|
+
};
|
|
5733
|
+
const notifyEnvironmentDrivers = (file, event) => {
|
|
5734
|
+
for (const environment of Object.values(environments)) {
|
|
5735
|
+
if (!environment.driver?.watchChange) continue;
|
|
5736
|
+
void Promise.resolve(
|
|
5737
|
+
environment.driver.watchChange(file, event, environment.getDriverContext())
|
|
5738
|
+
).catch((error) => {
|
|
5739
|
+
logger.error(
|
|
5740
|
+
`[nasti] environment driver "${environment.driver.name}" watchChange failed`,
|
|
5741
|
+
{ error }
|
|
5742
|
+
);
|
|
5743
|
+
});
|
|
5744
|
+
}
|
|
5745
|
+
};
|
|
4736
5746
|
watcher.on("change", (file) => {
|
|
4737
5747
|
ssrRunner?.invalidateFile(file);
|
|
4738
5748
|
handleFileChange(file, server);
|
|
5749
|
+
notifyEnvironmentDrivers(file, "change");
|
|
4739
5750
|
});
|
|
4740
5751
|
watcher.on("add", (file) => {
|
|
4741
5752
|
ssrRunner?.invalidateFile(file);
|
|
4742
5753
|
handleFileChange(file, server);
|
|
5754
|
+
notifyEnvironmentDrivers(file, "add");
|
|
5755
|
+
});
|
|
5756
|
+
watcher.on("unlink", (file) => {
|
|
5757
|
+
ssrRunner?.invalidateFile(file);
|
|
5758
|
+
notifyEnvironmentDrivers(file, "unlink");
|
|
4743
5759
|
});
|
|
4744
5760
|
server = {
|
|
4745
5761
|
config: configWithPlugins,
|
|
@@ -4748,10 +5764,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4748
5764
|
watcher,
|
|
4749
5765
|
ws,
|
|
4750
5766
|
environments,
|
|
5767
|
+
environmentServices,
|
|
4751
5768
|
async listen(port) {
|
|
4752
5769
|
const finalPort = port ?? config.server.port;
|
|
4753
5770
|
const host = config.server.host === true ? "0.0.0.0" : config.server.host;
|
|
4754
5771
|
await pluginContainer.buildStart();
|
|
5772
|
+
await startEnvironmentDrivers();
|
|
4755
5773
|
return new Promise((resolve, reject) => {
|
|
4756
5774
|
let currentPort = finalPort;
|
|
4757
5775
|
const onListening = () => {
|
|
@@ -4759,15 +5777,20 @@ async function createServer(inlineConfig = {}) {
|
|
|
4759
5777
|
config.server.port = actualPort;
|
|
4760
5778
|
const localUrl = `http://localhost:${actualPort}/`;
|
|
4761
5779
|
const networkUrl = host === "0.0.0.0" ? `http://${getNetworkAddress()}:${actualPort}/` : null;
|
|
5780
|
+
const driverLocalUrls = Object.values(environmentServices).flatMap((service) => service.localUrls ?? []);
|
|
5781
|
+
const driverNetworkUrls = Object.values(environmentServices).flatMap((service) => service.networkUrls ?? []);
|
|
4762
5782
|
logger.clearScreen("info");
|
|
4763
5783
|
const readyIn = Math.ceil(performance.now() - startTime);
|
|
4764
5784
|
logger.info(
|
|
4765
5785
|
`
|
|
4766
|
-
${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.
|
|
5786
|
+
${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.4.0"}`)} ${import_picocolors9.default.dim("ready in")} ${import_picocolors9.default.bold(readyIn)} ${import_picocolors9.default.dim("ms")}
|
|
4767
5787
|
`
|
|
4768
5788
|
);
|
|
4769
5789
|
printServerUrls(
|
|
4770
|
-
{
|
|
5790
|
+
{
|
|
5791
|
+
local: [localUrl, ...driverLocalUrls],
|
|
5792
|
+
network: [...networkUrl ? [networkUrl] : [], ...driverNetworkUrls]
|
|
5793
|
+
},
|
|
4771
5794
|
logger.info
|
|
4772
5795
|
);
|
|
4773
5796
|
logger.info("");
|
|
@@ -4788,7 +5811,12 @@ async function createServer(inlineConfig = {}) {
|
|
|
4788
5811
|
},
|
|
4789
5812
|
async transformRequest(url) {
|
|
4790
5813
|
const { transformRequest: transformRequest2 } = await Promise.resolve().then(() => (init_middleware(), middleware_exports));
|
|
4791
|
-
return transformRequest2(url, {
|
|
5814
|
+
return transformRequest2(url, {
|
|
5815
|
+
config: configWithPlugins,
|
|
5816
|
+
pluginContainer,
|
|
5817
|
+
moduleGraph,
|
|
5818
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5819
|
+
});
|
|
4792
5820
|
},
|
|
4793
5821
|
async ssrLoadModule(url) {
|
|
4794
5822
|
const runner = await getSsrRunner();
|
|
@@ -4797,11 +5825,63 @@ async function createServer(inlineConfig = {}) {
|
|
|
4797
5825
|
async close() {
|
|
4798
5826
|
await pluginContainer.buildEnd();
|
|
4799
5827
|
await bundledServer?.close();
|
|
4800
|
-
|
|
5828
|
+
let environmentCloseFailed = false;
|
|
5829
|
+
let firstEnvironmentCloseError;
|
|
5830
|
+
for (const environment of Object.values(environments).reverse()) {
|
|
5831
|
+
try {
|
|
5832
|
+
await environment.close();
|
|
5833
|
+
} catch (error) {
|
|
5834
|
+
if (!environmentCloseFailed) {
|
|
5835
|
+
environmentCloseFailed = true;
|
|
5836
|
+
firstEnvironmentCloseError = error;
|
|
5837
|
+
}
|
|
5838
|
+
logCloseError(`environment "${environment.name}"`, error);
|
|
5839
|
+
}
|
|
5840
|
+
}
|
|
5841
|
+
await watcher.close();
|
|
4801
5842
|
ws.close();
|
|
4802
5843
|
httpServer.close();
|
|
5844
|
+
if (environmentCloseFailed) {
|
|
5845
|
+
throw firstEnvironmentCloseError;
|
|
5846
|
+
}
|
|
4803
5847
|
}
|
|
4804
5848
|
};
|
|
5849
|
+
try {
|
|
5850
|
+
await startEnvironmentDrivers();
|
|
5851
|
+
} catch (error) {
|
|
5852
|
+
if (bundledServer) {
|
|
5853
|
+
try {
|
|
5854
|
+
await bundledServer.close();
|
|
5855
|
+
} catch (closeError) {
|
|
5856
|
+
logCloseError("bundled dev server after driver startup failure", closeError);
|
|
5857
|
+
}
|
|
5858
|
+
}
|
|
5859
|
+
try {
|
|
5860
|
+
await watcher.close();
|
|
5861
|
+
} catch (closeError) {
|
|
5862
|
+
logCloseError("file watcher after driver startup failure", closeError);
|
|
5863
|
+
}
|
|
5864
|
+
try {
|
|
5865
|
+
ws.close();
|
|
5866
|
+
} catch (closeError) {
|
|
5867
|
+
logCloseError("WebSocket server after driver startup failure", closeError);
|
|
5868
|
+
}
|
|
5869
|
+
try {
|
|
5870
|
+
httpServer.close();
|
|
5871
|
+
} catch (closeError) {
|
|
5872
|
+
logCloseError("HTTP server after driver startup failure", closeError);
|
|
5873
|
+
}
|
|
5874
|
+
throw error;
|
|
5875
|
+
}
|
|
5876
|
+
app.use(transformMiddleware({
|
|
5877
|
+
config: configWithPlugins,
|
|
5878
|
+
pluginContainer,
|
|
5879
|
+
moduleGraph,
|
|
5880
|
+
onPrune: (paths) => ws.send({ type: "prune", paths })
|
|
5881
|
+
}));
|
|
5882
|
+
const publicDir = import_node_path16.default.resolve(config.root, "public");
|
|
5883
|
+
app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
|
|
5884
|
+
app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
|
|
4805
5885
|
const postMiddlewares = [];
|
|
4806
5886
|
for (const plugin of allPlugins) {
|
|
4807
5887
|
if (plugin.configureServer) {
|
|
@@ -4825,12 +5905,12 @@ function getNetworkAddress() {
|
|
|
4825
5905
|
}
|
|
4826
5906
|
return "localhost";
|
|
4827
5907
|
}
|
|
4828
|
-
var import_node_http,
|
|
5908
|
+
var import_node_http, import_node_path16, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors9;
|
|
4829
5909
|
var init_server = __esm({
|
|
4830
5910
|
"src/server/index.ts"() {
|
|
4831
5911
|
"use strict";
|
|
4832
5912
|
import_node_http = __toESM(require("http"), 1);
|
|
4833
|
-
|
|
5913
|
+
import_node_path16 = __toESM(require("path"), 1);
|
|
4834
5914
|
import_node_os = __toESM(require("os"), 1);
|
|
4835
5915
|
import_connect = __toESM(require("connect"), 1);
|
|
4836
5916
|
import_sirv = __toESM(require("sirv"), 1);
|
|
@@ -4844,6 +5924,7 @@ var init_server = __esm({
|
|
|
4844
5924
|
init_middleware();
|
|
4845
5925
|
init_hmr();
|
|
4846
5926
|
init_builtins();
|
|
5927
|
+
init_plugin_api();
|
|
4847
5928
|
}
|
|
4848
5929
|
});
|
|
4849
5930
|
|
|
@@ -4856,12 +5937,15 @@ __export(src_exports, {
|
|
|
4856
5937
|
buildElectron: () => buildElectron,
|
|
4857
5938
|
buildEnvDefine: () => buildEnvDefine,
|
|
4858
5939
|
createDebugger: () => createDebugger,
|
|
5940
|
+
createElectronRendererConfig: () => createElectronRendererConfig,
|
|
4859
5941
|
createLogger: () => createLogger,
|
|
4860
5942
|
createNoopHotChannel: () => createNoopHotChannel,
|
|
4861
5943
|
createServer: () => createServer,
|
|
4862
5944
|
createWsHotChannel: () => createWsHotChannel,
|
|
4863
5945
|
defineConfig: () => defineConfig,
|
|
5946
|
+
detectFramework: () => detectFramework,
|
|
4864
5947
|
electronPlugin: () => electronPlugin,
|
|
5948
|
+
electronRendererDevPath: () => electronRendererDevPath,
|
|
4865
5949
|
loadEnv: () => loadEnv,
|
|
4866
5950
|
monacoEditorPlugin: () => monacoEditorPlugin,
|
|
4867
5951
|
printServerUrls: () => printServerUrls,
|
|
@@ -4875,8 +5959,8 @@ init_config();
|
|
|
4875
5959
|
init_build();
|
|
4876
5960
|
|
|
4877
5961
|
// src/build/electron.ts
|
|
4878
|
-
var
|
|
4879
|
-
var
|
|
5962
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
5963
|
+
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
4880
5964
|
var import_rolldown2 = require("rolldown");
|
|
4881
5965
|
var import_picocolors5 = __toESM(require("picocolors"), 1);
|
|
4882
5966
|
init_config();
|
|
@@ -4922,28 +6006,26 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4922
6006
|
const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
|
|
4923
6007
|
const startTime = performance.now();
|
|
4924
6008
|
assertElectronVersion(config);
|
|
4925
|
-
console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.
|
|
6009
|
+
console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.4.0"}`));
|
|
4926
6010
|
console.log(import_picocolors5.default.dim(` root: ${config.root}`));
|
|
4927
6011
|
console.log(import_picocolors5.default.dim(` mode: ${config.mode}`));
|
|
4928
6012
|
console.log(import_picocolors5.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
|
|
4929
|
-
const outDir =
|
|
4930
|
-
if (config.build.emptyOutDir &&
|
|
4931
|
-
|
|
6013
|
+
const outDir = import_node_path11.default.resolve(config.root, config.build.outDir);
|
|
6014
|
+
if (config.build.emptyOutDir && import_node_fs8.default.existsSync(outDir)) {
|
|
6015
|
+
import_node_fs8.default.rmSync(outDir, { recursive: true, force: true });
|
|
4932
6016
|
}
|
|
4933
|
-
|
|
4934
|
-
const rendererOutDir =
|
|
6017
|
+
import_node_fs8.default.mkdirSync(outDir, { recursive: true });
|
|
6018
|
+
const rendererOutDir = import_node_path11.default.join(outDir, "renderer");
|
|
4935
6019
|
const { build: build2 } = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
4936
|
-
await build2({
|
|
4937
|
-
...inlineConfig,
|
|
4938
|
-
target: "web",
|
|
6020
|
+
await build2(createElectronRendererConfig(config, inlineConfig, {
|
|
4939
6021
|
build: {
|
|
4940
6022
|
...inlineConfig.build,
|
|
4941
6023
|
outDir: rendererOutDir,
|
|
4942
6024
|
emptyOutDir: false
|
|
4943
6025
|
}
|
|
4944
|
-
});
|
|
4945
|
-
const mainEntry =
|
|
4946
|
-
if (!
|
|
6026
|
+
}));
|
|
6027
|
+
const mainEntry = import_node_path11.default.resolve(config.root, config.electron.main);
|
|
6028
|
+
if (!import_node_fs8.default.existsSync(mainEntry)) {
|
|
4947
6029
|
throw new Error(
|
|
4948
6030
|
`Electron main entry not found: ${config.electron.main}
|
|
4949
6031
|
\u5728 nasti.config.ts \u7684 electron.main \u6307\u5B9A\u4E3B\u8FDB\u7A0B\u5165\u53E3\u6587\u4EF6\u3002`
|
|
@@ -4957,11 +6039,11 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4957
6039
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
4958
6040
|
const preloadFiles = [];
|
|
4959
6041
|
for (const entry of preloadEntries) {
|
|
4960
|
-
if (!
|
|
6042
|
+
if (!import_node_fs8.default.existsSync(entry)) {
|
|
4961
6043
|
console.warn(import_picocolors5.default.yellow(` \u26A0 preload entry not found, skipped: ${entry}`));
|
|
4962
6044
|
continue;
|
|
4963
6045
|
}
|
|
4964
|
-
const base =
|
|
6046
|
+
const base = import_node_path11.default.basename(entry).replace(/\.[^.]+$/, "");
|
|
4965
6047
|
const out = outFileName(outDir, base, config.electron.preloadFormat);
|
|
4966
6048
|
await bundleNode(config, entry, {
|
|
4967
6049
|
outFile: out,
|
|
@@ -4973,10 +6055,10 @@ async function buildElectron(inlineConfig = {}) {
|
|
|
4973
6055
|
const elapsed = ((performance.now() - startTime) / 1e3).toFixed(2);
|
|
4974
6056
|
console.log(import_picocolors5.default.green(`
|
|
4975
6057
|
\u2713 Electron build complete in ${elapsed}s`));
|
|
4976
|
-
console.log(import_picocolors5.default.dim(` renderer: ${
|
|
4977
|
-
console.log(import_picocolors5.default.dim(` main: ${
|
|
6058
|
+
console.log(import_picocolors5.default.dim(` renderer: ${import_node_path11.default.relative(config.root, rendererOutDir)}/`));
|
|
6059
|
+
console.log(import_picocolors5.default.dim(` main: ${import_node_path11.default.relative(config.root, mainFile)}`));
|
|
4978
6060
|
for (const pf of preloadFiles) {
|
|
4979
|
-
console.log(import_picocolors5.default.dim(` preload: ${
|
|
6061
|
+
console.log(import_picocolors5.default.dim(` preload: ${import_node_path11.default.relative(config.root, pf)}`));
|
|
4980
6062
|
}
|
|
4981
6063
|
console.log();
|
|
4982
6064
|
return { rendererOutDir, mainFile, preloadFiles };
|
|
@@ -4995,7 +6077,8 @@ async function bundleNode(config, entry, opts) {
|
|
|
4995
6077
|
const result = transformCode(id, code, {
|
|
4996
6078
|
sourcemap: !!config.build.sourcemap,
|
|
4997
6079
|
jsxRuntime: "automatic",
|
|
4998
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6080
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6081
|
+
target: config.electron.nodeTarget
|
|
4999
6082
|
});
|
|
5000
6083
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
5001
6084
|
}
|
|
@@ -5006,10 +6089,14 @@ async function bundleNode(config, entry, opts) {
|
|
|
5006
6089
|
...restInputOptions,
|
|
5007
6090
|
input: entry,
|
|
5008
6091
|
platform: "node",
|
|
5009
|
-
transform: {
|
|
6092
|
+
transform: {
|
|
6093
|
+
...userTransform,
|
|
6094
|
+
target: config.electron.nodeTarget,
|
|
6095
|
+
define: mergedDefine
|
|
6096
|
+
},
|
|
5010
6097
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
5011
6098
|
});
|
|
5012
|
-
|
|
6099
|
+
import_node_fs8.default.mkdirSync(import_node_path11.default.dirname(opts.outFile), { recursive: true });
|
|
5013
6100
|
await bundle2.write({
|
|
5014
6101
|
sourcemap: !!config.build.sourcemap,
|
|
5015
6102
|
minify: !!config.build.minify,
|
|
@@ -5020,16 +6107,35 @@ async function bundleNode(config, entry, opts) {
|
|
|
5020
6107
|
codeSplitting: false
|
|
5021
6108
|
});
|
|
5022
6109
|
await bundle2.close();
|
|
5023
|
-
console.log(import_picocolors5.default.dim(` \u2713 ${opts.label} \u2192 ${
|
|
6110
|
+
console.log(import_picocolors5.default.dim(` \u2713 ${opts.label} \u2192 ${import_node_path11.default.relative(config.root, opts.outFile)}`));
|
|
5024
6111
|
return opts.outFile;
|
|
5025
6112
|
}
|
|
6113
|
+
function createElectronRendererConfig(config, inlineConfig = {}, overrides = {}) {
|
|
6114
|
+
const inlineClient = inlineConfig.environments?.client ?? {};
|
|
6115
|
+
return {
|
|
6116
|
+
...inlineConfig,
|
|
6117
|
+
...overrides,
|
|
6118
|
+
root: config.root,
|
|
6119
|
+
mode: config.mode,
|
|
6120
|
+
target: "web",
|
|
6121
|
+
framework: config.framework,
|
|
6122
|
+
base: config.base === "/" ? "./" : config.base,
|
|
6123
|
+
environments: {
|
|
6124
|
+
...inlineConfig.environments ?? {},
|
|
6125
|
+
client: {
|
|
6126
|
+
...inlineClient,
|
|
6127
|
+
html: config.electron.renderer
|
|
6128
|
+
}
|
|
6129
|
+
}
|
|
6130
|
+
};
|
|
6131
|
+
}
|
|
5026
6132
|
function outFileName(outDir, base, format) {
|
|
5027
6133
|
const ext = format === "cjs" ? ".cjs" : ".mjs";
|
|
5028
|
-
return
|
|
6134
|
+
return import_node_path11.default.join(outDir, base + ext);
|
|
5029
6135
|
}
|
|
5030
6136
|
function normalizePreload(preload, root) {
|
|
5031
6137
|
const list = Array.isArray(preload) ? preload : preload ? [preload] : [];
|
|
5032
|
-
return list.map((p) =>
|
|
6138
|
+
return list.map((p) => import_node_path11.default.resolve(root, p));
|
|
5033
6139
|
}
|
|
5034
6140
|
function assertElectronVersion(config) {
|
|
5035
6141
|
const min = config.electron.minVersion;
|
|
@@ -5044,9 +6150,9 @@ function assertElectronVersion(config) {
|
|
|
5044
6150
|
}
|
|
5045
6151
|
function detectInstalledElectron(root) {
|
|
5046
6152
|
try {
|
|
5047
|
-
const pkgPath =
|
|
5048
|
-
if (!
|
|
5049
|
-
const pkg = JSON.parse(
|
|
6153
|
+
const pkgPath = import_node_path11.default.resolve(root, "node_modules/electron/package.json");
|
|
6154
|
+
if (!import_node_fs8.default.existsSync(pkgPath)) return null;
|
|
6155
|
+
const pkg = JSON.parse(import_node_fs8.default.readFileSync(pkgPath, "utf-8"));
|
|
5050
6156
|
const major = parseInt(String(pkg.version).split(".")[0], 10);
|
|
5051
6157
|
return Number.isFinite(major) ? major : null;
|
|
5052
6158
|
} catch {
|
|
@@ -5058,8 +6164,8 @@ function detectInstalledElectron(root) {
|
|
|
5058
6164
|
init_server();
|
|
5059
6165
|
|
|
5060
6166
|
// src/server/electron-dev.ts
|
|
5061
|
-
var
|
|
5062
|
-
var
|
|
6167
|
+
var import_node_path17 = __toESM(require("path"), 1);
|
|
6168
|
+
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
5063
6169
|
var import_node_module7 = require("module");
|
|
5064
6170
|
var import_node_child_process = require("child_process");
|
|
5065
6171
|
var import_chokidar2 = __toESM(require("chokidar"), 1);
|
|
@@ -5073,17 +6179,21 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5073
6179
|
const { noSpawn, ...rest } = inlineConfig;
|
|
5074
6180
|
const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
|
|
5075
6181
|
warnElectronVersion(config);
|
|
5076
|
-
console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.
|
|
6182
|
+
console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.4.0"}`));
|
|
5077
6183
|
const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
5078
|
-
const server = await createServer2({
|
|
6184
|
+
const server = await createServer2({
|
|
6185
|
+
...rest,
|
|
6186
|
+
target: "electron",
|
|
6187
|
+
framework: config.framework
|
|
6188
|
+
});
|
|
5079
6189
|
await server.listen();
|
|
5080
|
-
const devUrl = `http://localhost:${server.config.server.port}
|
|
6190
|
+
const devUrl = `http://localhost:${server.config.server.port}` + electronRendererDevPath(config.electron.renderer);
|
|
5081
6191
|
console.log(import_picocolors10.default.dim(` renderer: ${devUrl}`));
|
|
5082
|
-
const stageDir =
|
|
5083
|
-
|
|
5084
|
-
const mainEntry =
|
|
6192
|
+
const stageDir = import_node_path17.default.resolve(config.root, ".nasti");
|
|
6193
|
+
import_node_fs12.default.mkdirSync(stageDir, { recursive: true });
|
|
6194
|
+
const mainEntry = import_node_path17.default.resolve(config.root, config.electron.main);
|
|
5085
6195
|
const preloadEntries = normalizePreload(config.electron.preload, config.root);
|
|
5086
|
-
const builtMainFile =
|
|
6196
|
+
const builtMainFile = import_node_path17.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
|
|
5087
6197
|
const builtPreloadFiles = [];
|
|
5088
6198
|
const compileAll = async () => {
|
|
5089
6199
|
await compileNode(config, mainEntry, {
|
|
@@ -5093,9 +6203,9 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5093
6203
|
});
|
|
5094
6204
|
builtPreloadFiles.length = 0;
|
|
5095
6205
|
for (const entry of preloadEntries) {
|
|
5096
|
-
if (!
|
|
5097
|
-
const base =
|
|
5098
|
-
const out =
|
|
6206
|
+
if (!import_node_fs12.default.existsSync(entry)) continue;
|
|
6207
|
+
const base = import_node_path17.default.basename(entry).replace(/\.[^.]+$/, "");
|
|
6208
|
+
const out = import_node_path17.default.join(stageDir, base + extFor(config.electron.preloadFormat));
|
|
5099
6209
|
await compileNode(config, entry, {
|
|
5100
6210
|
outFile: out,
|
|
5101
6211
|
format: config.electron.preloadFormat,
|
|
@@ -5134,7 +6244,7 @@ async function startElectronDev(inlineConfig = {}) {
|
|
|
5134
6244
|
};
|
|
5135
6245
|
spawnElectron();
|
|
5136
6246
|
if (config.electron.autoRestart) {
|
|
5137
|
-
const watchTargets = [mainEntry, ...preloadEntries].filter(
|
|
6247
|
+
const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs12.default.existsSync);
|
|
5138
6248
|
const watcher = import_chokidar2.default.watch(watchTargets, { ignoreInitial: true });
|
|
5139
6249
|
let restarting = null;
|
|
5140
6250
|
let pending = false;
|
|
@@ -5199,18 +6309,22 @@ async function compileNode(config, entry, opts) {
|
|
|
5199
6309
|
const result = transformCode(id, code, {
|
|
5200
6310
|
sourcemap: true,
|
|
5201
6311
|
jsxRuntime: "automatic",
|
|
5202
|
-
jsxImportSource: config.framework === "vue" ? "vue" : "react"
|
|
6312
|
+
jsxImportSource: config.framework === "vue" ? "vue" : "react",
|
|
6313
|
+
target: config.electron.nodeTarget
|
|
5203
6314
|
});
|
|
5204
6315
|
return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
|
|
5205
6316
|
}
|
|
5206
6317
|
};
|
|
5207
6318
|
const bundle2 = await (0, import_rolldown3.rolldown)({
|
|
5208
6319
|
input: entry,
|
|
5209
|
-
transform: {
|
|
6320
|
+
transform: {
|
|
6321
|
+
target: config.electron.nodeTarget,
|
|
6322
|
+
define: envDefine
|
|
6323
|
+
},
|
|
5210
6324
|
platform: "node",
|
|
5211
6325
|
plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
|
|
5212
6326
|
});
|
|
5213
|
-
|
|
6327
|
+
import_node_fs12.default.mkdirSync(import_node_path17.default.dirname(opts.outFile), { recursive: true });
|
|
5214
6328
|
await bundle2.write({
|
|
5215
6329
|
file: opts.outFile,
|
|
5216
6330
|
format: opts.format === "cjs" ? "cjs" : "esm",
|
|
@@ -5222,15 +6336,19 @@ async function compileNode(config, entry, opts) {
|
|
|
5222
6336
|
});
|
|
5223
6337
|
await bundle2.close();
|
|
5224
6338
|
}
|
|
6339
|
+
function electronRendererDevPath(renderer) {
|
|
6340
|
+
const normalized = renderer.split(import_node_path17.default.sep).join("/").replace(/^\.?\//, "");
|
|
6341
|
+
return normalized === "index.html" ? "/" : `/${normalized}`;
|
|
6342
|
+
}
|
|
5225
6343
|
function resolveElectronBinary(config) {
|
|
5226
|
-
if (config.electron.electronPath &&
|
|
6344
|
+
if (config.electron.electronPath && import_node_fs12.default.existsSync(config.electron.electronPath)) {
|
|
5227
6345
|
return config.electron.electronPath;
|
|
5228
6346
|
}
|
|
5229
6347
|
try {
|
|
5230
|
-
const require2 = (0, import_node_module7.createRequire)(
|
|
6348
|
+
const require2 = (0, import_node_module7.createRequire)(import_node_path17.default.resolve(config.root, "package.json"));
|
|
5231
6349
|
const pathFile = require2.resolve("electron");
|
|
5232
6350
|
const electronModule = require2(pathFile);
|
|
5233
|
-
if (typeof electronModule === "string" &&
|
|
6351
|
+
if (typeof electronModule === "string" && import_node_fs12.default.existsSync(electronModule)) {
|
|
5234
6352
|
return electronModule;
|
|
5235
6353
|
}
|
|
5236
6354
|
} catch {
|
|
@@ -5257,8 +6375,8 @@ function warnElectronVersion(config) {
|
|
|
5257
6375
|
}
|
|
5258
6376
|
|
|
5259
6377
|
// src/plugins/monaco-editor.ts
|
|
5260
|
-
var
|
|
5261
|
-
var
|
|
6378
|
+
var import_node_path18 = __toESM(require("path"), 1);
|
|
6379
|
+
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
5262
6380
|
var import_node_crypto4 = __toESM(require("crypto"), 1);
|
|
5263
6381
|
var import_node_module8 = require("module");
|
|
5264
6382
|
var DEFAULT_WORKERS = {
|
|
@@ -5279,9 +6397,9 @@ function normalizePublicPath(p) {
|
|
|
5279
6397
|
}
|
|
5280
6398
|
function readMonacoVersion(root) {
|
|
5281
6399
|
try {
|
|
5282
|
-
const require2 = (0, import_node_module8.createRequire)(
|
|
6400
|
+
const require2 = (0, import_node_module8.createRequire)(import_node_path18.default.resolve(root, "package.json"));
|
|
5283
6401
|
const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
|
|
5284
|
-
const pkg = JSON.parse(
|
|
6402
|
+
const pkg = JSON.parse(import_node_fs13.default.readFileSync(pkgJsonPath, "utf-8"));
|
|
5285
6403
|
return typeof pkg.version === "string" ? pkg.version : "unknown";
|
|
5286
6404
|
} catch {
|
|
5287
6405
|
return "unknown";
|
|
@@ -5301,20 +6419,20 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5301
6419
|
let cacheDir = "";
|
|
5302
6420
|
const building = /* @__PURE__ */ new Map();
|
|
5303
6421
|
async function buildWorker(worker) {
|
|
5304
|
-
const cacheFile =
|
|
5305
|
-
if (
|
|
6422
|
+
const cacheFile = import_node_path18.default.join(cacheDir, `${worker.label}.worker.js`);
|
|
6423
|
+
if (import_node_fs13.default.existsSync(cacheFile)) return cacheFile;
|
|
5306
6424
|
const existing = building.get(worker.label);
|
|
5307
6425
|
if (existing) return existing;
|
|
5308
6426
|
const task = (async () => {
|
|
5309
6427
|
const { rolldown: rolldown4 } = await import("rolldown");
|
|
5310
|
-
const require2 = (0, import_node_module8.createRequire)(
|
|
6428
|
+
const require2 = (0, import_node_module8.createRequire)(import_node_path18.default.resolve(resolvedConfig.root, "package.json"));
|
|
5311
6429
|
let entry;
|
|
5312
6430
|
try {
|
|
5313
6431
|
entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
|
|
5314
6432
|
} catch {
|
|
5315
6433
|
entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
|
|
5316
6434
|
}
|
|
5317
|
-
|
|
6435
|
+
import_node_fs13.default.mkdirSync(cacheDir, { recursive: true });
|
|
5318
6436
|
const bundle2 = await rolldown4({
|
|
5319
6437
|
input: entry,
|
|
5320
6438
|
platform: "browser"
|
|
@@ -5374,12 +6492,12 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5374
6492
|
resolvedConfig = config;
|
|
5375
6493
|
const version = readMonacoVersion(config.root);
|
|
5376
6494
|
const key = import_node_crypto4.default.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
|
|
5377
|
-
cacheDir =
|
|
6495
|
+
cacheDir = import_node_path18.default.resolve(config.root, "node_modules/.nasti/monaco", key);
|
|
5378
6496
|
},
|
|
5379
6497
|
async configureServer(server) {
|
|
5380
6498
|
const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
|
|
5381
6499
|
const watcher = server.watcher;
|
|
5382
|
-
const monacoDir =
|
|
6500
|
+
const monacoDir = import_node_path18.default.resolve(resolvedConfig.root, "node_modules/monaco-editor");
|
|
5383
6501
|
try {
|
|
5384
6502
|
watcher?.unwatch?.(monacoDir);
|
|
5385
6503
|
} catch {
|
|
@@ -5409,7 +6527,7 @@ function monacoEditorPlugin(options = {}) {
|
|
|
5409
6527
|
const file = await buildWorker(worker);
|
|
5410
6528
|
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
5411
6529
|
res.setHeader("Cache-Control", "public, max-age=604800, immutable");
|
|
5412
|
-
|
|
6530
|
+
import_node_fs13.default.createReadStream(file).pipe(res);
|
|
5413
6531
|
} catch (e) {
|
|
5414
6532
|
res.statusCode = 500;
|
|
5415
6533
|
res.end(`Monaco worker build failed: ${e.message}`);
|
|
@@ -5444,16 +6562,16 @@ self.monaco = monaco;`,
|
|
|
5444
6562
|
resolvedConfig.root,
|
|
5445
6563
|
resolvedConfig.build.outDir,
|
|
5446
6564
|
resolvedConfig.base
|
|
5447
|
-
) : isCDN(publicPath) ?
|
|
6565
|
+
) : isCDN(publicPath) ? import_node_path18.default.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : import_node_path18.default.resolve(
|
|
5448
6566
|
resolvedConfig.root,
|
|
5449
6567
|
resolvedConfig.build.outDir,
|
|
5450
6568
|
publicPath.replace(/^\//, "")
|
|
5451
6569
|
);
|
|
5452
|
-
|
|
6570
|
+
import_node_fs13.default.mkdirSync(outDir, { recursive: true });
|
|
5453
6571
|
for (const worker of workers) {
|
|
5454
6572
|
try {
|
|
5455
6573
|
const cacheFile = await buildWorker(worker);
|
|
5456
|
-
|
|
6574
|
+
import_node_fs13.default.copyFileSync(cacheFile, import_node_path18.default.join(outDir, `${worker.label}.worker.js`));
|
|
5457
6575
|
} catch (e) {
|
|
5458
6576
|
throw new Error(
|
|
5459
6577
|
`[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
|
|
@@ -5479,12 +6597,15 @@ init_env();
|
|
|
5479
6597
|
buildElectron,
|
|
5480
6598
|
buildEnvDefine,
|
|
5481
6599
|
createDebugger,
|
|
6600
|
+
createElectronRendererConfig,
|
|
5482
6601
|
createLogger,
|
|
5483
6602
|
createNoopHotChannel,
|
|
5484
6603
|
createServer,
|
|
5485
6604
|
createWsHotChannel,
|
|
5486
6605
|
defineConfig,
|
|
6606
|
+
detectFramework,
|
|
5487
6607
|
electronPlugin,
|
|
6608
|
+
electronRendererDevPath,
|
|
5488
6609
|
loadEnv,
|
|
5489
6610
|
monacoEditorPlugin,
|
|
5490
6611
|
printServerUrls,
|