@4399ywkf/core 5.1.5 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +136 -48
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +3 -3
- package/dist/config/index.js +3 -1
- package/dist/config/index.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +697 -67
- package/dist/index.js.map +1 -1
- package/dist/plugin/index.d.ts +3 -3
- package/dist/router/index.js +12 -9
- package/dist/router/index.js.map +1 -1
- package/dist/rspack/index.d.ts +2 -2
- package/dist/rspack/index.js +101 -15
- package/dist/rspack/index.js.map +1 -1
- package/dist/runtime/index.d.ts +86 -4
- package/dist/runtime/index.js +578 -19
- package/dist/runtime/index.js.map +1 -1
- package/dist/{schema-CuEnqbqQ.d.ts → schema-QzJlmn39.d.ts} +16 -1
- package/dist/{types-BYqzyGAY.d.ts → types-ZJhd87ue.d.ts} +51 -1
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -876,7 +876,7 @@ function createMockMiddleware(mockPath, options) {
|
|
|
876
876
|
scanMockFiles(mockPath);
|
|
877
877
|
return async (_req, _res, next) => {
|
|
878
878
|
if (delay > 0) {
|
|
879
|
-
await new Promise((
|
|
879
|
+
await new Promise((resolve6) => setTimeout(resolve6, delay));
|
|
880
880
|
}
|
|
881
881
|
next();
|
|
882
882
|
};
|
|
@@ -1830,11 +1830,11 @@ var zustandPlugin = createPlugin((options = {}) => ({
|
|
|
1830
1830
|
const hooks = {
|
|
1831
1831
|
modifyRspackConfig(rspackConfig) {
|
|
1832
1832
|
logger.info("Zustand \u5DF2\u542F\u7528");
|
|
1833
|
-
const
|
|
1834
|
-
const alias =
|
|
1833
|
+
const resolve6 = rspackConfig.resolve || {};
|
|
1834
|
+
const alias = resolve6.alias || {};
|
|
1835
1835
|
alias["@store"] = storePath;
|
|
1836
|
-
|
|
1837
|
-
rspackConfig.resolve =
|
|
1836
|
+
resolve6.alias = alias;
|
|
1837
|
+
rspackConfig.resolve = resolve6;
|
|
1838
1838
|
return rspackConfig;
|
|
1839
1839
|
},
|
|
1840
1840
|
generateFiles(_ctx) {
|
|
@@ -2175,7 +2175,9 @@ var defaultConfig = {
|
|
|
2175
2175
|
tools: {},
|
|
2176
2176
|
env: {
|
|
2177
2177
|
publicEnvFile: "config/env/.env.public",
|
|
2178
|
-
envDir: "config/env"
|
|
2178
|
+
envDir: "config/env",
|
|
2179
|
+
expose: [],
|
|
2180
|
+
exposePrefixes: ["YWKF_PUBLIC_", "NEXT_PUBLIC_"]
|
|
2179
2181
|
},
|
|
2180
2182
|
alias: {},
|
|
2181
2183
|
plugins: []
|
|
@@ -2743,12 +2745,13 @@ function LazyRoute({
|
|
|
2743
2745
|
|
|
2744
2746
|
import React, { lazy, Suspense } from "react";
|
|
2745
2747
|
import { createBrowserRouter, type RouteObject } from "react-router";
|
|
2748
|
+
import { RouteErrorBoundary } from "@4399ywkf/core/runtime";
|
|
2749
|
+
${errorImports.length > 0 ? `
|
|
2750
|
+
// \u540C\u6B65\u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6
|
|
2751
|
+
${errorImports.join("\n")}` : ""}
|
|
2746
2752
|
|
|
2747
2753
|
// \u61D2\u52A0\u8F7D\u9875\u9762\u7EC4\u4EF6
|
|
2748
2754
|
${lazyImports.join("\n")}
|
|
2749
|
-
${errorImports.length > 0 ? `
|
|
2750
|
-
// \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6
|
|
2751
|
-
${errorImports.join("\n")}` : ""}
|
|
2752
2755
|
${loadingImports.length > 0 ? `
|
|
2753
2756
|
// \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6
|
|
2754
2757
|
${loadingImports.join("\n")}` : ""}
|
|
@@ -2783,7 +2786,7 @@ export default routes;
|
|
|
2783
2786
|
}
|
|
2784
2787
|
if (route.errorFile) {
|
|
2785
2788
|
errorImports.push(
|
|
2786
|
-
`
|
|
2789
|
+
`import ${name}Error from "@/pages/${toImportPath(route.errorFile)}";`
|
|
2787
2790
|
);
|
|
2788
2791
|
}
|
|
2789
2792
|
if (route.loadingFile) {
|
|
@@ -2798,13 +2801,13 @@ export default routes;
|
|
|
2798
2801
|
}
|
|
2799
2802
|
}
|
|
2800
2803
|
}
|
|
2801
|
-
emitRouteArray(routes, parentPath) {
|
|
2802
|
-
const items = routes.map((r) => this.emitRouteObject(r, parentPath));
|
|
2804
|
+
emitRouteArray(routes, parentPath, depth = 0) {
|
|
2805
|
+
const items = routes.map((r) => this.emitRouteObject(r, parentPath, depth));
|
|
2803
2806
|
return `[
|
|
2804
2807
|
${items.join(",\n ")}
|
|
2805
2808
|
]`;
|
|
2806
2809
|
}
|
|
2807
|
-
emitRouteObject(route, parentPath) {
|
|
2810
|
+
emitRouteObject(route, parentPath, depth) {
|
|
2808
2811
|
const parts = [];
|
|
2809
2812
|
const name = route.name;
|
|
2810
2813
|
if (route.index) {
|
|
@@ -2825,11 +2828,13 @@ export default routes;
|
|
|
2825
2828
|
parts.push(`element: <LazyRoute Component={${name}Page} />`);
|
|
2826
2829
|
}
|
|
2827
2830
|
if (route.errorFile) {
|
|
2828
|
-
parts.push(`errorElement: <
|
|
2831
|
+
parts.push(`errorElement: <RouteErrorBoundary fallback={<${name}Error />} />`);
|
|
2832
|
+
} else if (depth === 0) {
|
|
2833
|
+
parts.push(`errorElement: <RouteErrorBoundary />`);
|
|
2829
2834
|
}
|
|
2830
2835
|
if (route.children && route.children.length > 0) {
|
|
2831
2836
|
const childParent = route.pathless ? parentPath : route.path;
|
|
2832
|
-
parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);
|
|
2837
|
+
parts.push(`children: ${this.emitRouteArray(route.children, childParent, depth + 1)}`);
|
|
2833
2838
|
}
|
|
2834
2839
|
return `{
|
|
2835
2840
|
${parts.join(",\n ")}
|
|
@@ -3437,14 +3442,93 @@ var YwkfGeneratorPlugin = class {
|
|
|
3437
3442
|
}
|
|
3438
3443
|
};
|
|
3439
3444
|
|
|
3445
|
+
// src/rspack/client-env.ts
|
|
3446
|
+
import { existsSync as existsSync12, readFileSync as readFileSync4 } from "fs";
|
|
3447
|
+
import { resolve as resolve3 } from "path";
|
|
3448
|
+
import dotenv from "dotenv";
|
|
3449
|
+
var FRAMEWORK_ENV_KEYS = [
|
|
3450
|
+
"APP_CNAME",
|
|
3451
|
+
"APP_HOST",
|
|
3452
|
+
"APP_MODE",
|
|
3453
|
+
"APP_NAME",
|
|
3454
|
+
"APP_PORT",
|
|
3455
|
+
"DEBUG",
|
|
3456
|
+
"NODE_ENV",
|
|
3457
|
+
"OUTPUT_PATH",
|
|
3458
|
+
"PUBLIC_PATH",
|
|
3459
|
+
"YWKF_BUILD_ID",
|
|
3460
|
+
"YWKF_PREFIX_CLS"
|
|
3461
|
+
];
|
|
3462
|
+
var DEFAULT_EXPOSE_PREFIXES = ["YWKF_PUBLIC_", "NEXT_PUBLIC_"];
|
|
3463
|
+
var SECRET_KEY_PATTERN = /TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|PRIVATE|AUTH|ACCESS_KEY|API_KEY|SIGNING_KEY/i;
|
|
3464
|
+
var SECRET_VALUE_PATTERN = /^(sntry[su]_|sk-|ghp_|gho_|ghu_|ghs_|github_pat_|glpat-|xox[abprs]-|AKIA|ya29\.)/;
|
|
3465
|
+
function readEnvFileKeys(filePath) {
|
|
3466
|
+
if (!existsSync12(filePath)) return [];
|
|
3467
|
+
try {
|
|
3468
|
+
return Object.keys(dotenv.parse(readFileSync4(filePath, "utf-8")));
|
|
3469
|
+
} catch {
|
|
3470
|
+
return [];
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
function collectClientEnvKeys(options) {
|
|
3474
|
+
const { cwd, env = {}, mode = process.env.APP_MODE || "development" } = options;
|
|
3475
|
+
const keys = new Set(FRAMEWORK_ENV_KEYS);
|
|
3476
|
+
const files = [
|
|
3477
|
+
env.publicEnvFile ?? "config/env/.env.public",
|
|
3478
|
+
".env.public",
|
|
3479
|
+
".env",
|
|
3480
|
+
`${env.envDir ?? "config/env"}/.env.${mode}`,
|
|
3481
|
+
`.env.${mode}`
|
|
3482
|
+
];
|
|
3483
|
+
for (const file of files) {
|
|
3484
|
+
for (const key of readEnvFileKeys(resolve3(cwd, file))) keys.add(key);
|
|
3485
|
+
}
|
|
3486
|
+
for (const key of env.expose ?? []) keys.add(key);
|
|
3487
|
+
return keys;
|
|
3488
|
+
}
|
|
3489
|
+
function buildClientEnv(options) {
|
|
3490
|
+
const { cwd, env = {}, mode, processEnv = process.env } = options;
|
|
3491
|
+
const prefixes = env.exposePrefixes ?? DEFAULT_EXPOSE_PREFIXES;
|
|
3492
|
+
const allowed = collectClientEnvKeys({ cwd, env, mode });
|
|
3493
|
+
const result = {};
|
|
3494
|
+
const dropped = [];
|
|
3495
|
+
for (const [key, value] of Object.entries(processEnv)) {
|
|
3496
|
+
if (value === void 0) continue;
|
|
3497
|
+
const isAllowed = allowed.has(key) || prefixes.some((prefix) => key.startsWith(prefix));
|
|
3498
|
+
if (!isAllowed) continue;
|
|
3499
|
+
if (SECRET_KEY_PATTERN.test(key) || SECRET_VALUE_PATTERN.test(value)) {
|
|
3500
|
+
dropped.push(key);
|
|
3501
|
+
continue;
|
|
3502
|
+
}
|
|
3503
|
+
result[key] = value;
|
|
3504
|
+
}
|
|
3505
|
+
return { env: result, dropped };
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3440
3508
|
// src/rspack/base.ts
|
|
3441
3509
|
var require2 = createRequire(import.meta.url);
|
|
3442
3510
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
3443
3511
|
var coreNodeModules = join12(__dirname, "../../node_modules");
|
|
3512
|
+
function resolveYwkfBuildId(appName) {
|
|
3513
|
+
const releaseId = [
|
|
3514
|
+
process.env.YWKF_BUILD_ID,
|
|
3515
|
+
process.env.CI_COMMIT_SHA,
|
|
3516
|
+
process.env.GITHUB_SHA,
|
|
3517
|
+
process.env.GIT_COMMIT
|
|
3518
|
+
].find((value) => value?.trim())?.trim();
|
|
3519
|
+
return `${appName}:${releaseId || Date.now().toString(36)}`;
|
|
3520
|
+
}
|
|
3444
3521
|
function createBaseConfig(config, cwd, options = {}) {
|
|
3445
3522
|
const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
|
|
3446
3523
|
const { resolveApp } = createPathResolver(cwd);
|
|
3447
3524
|
const { appName, appCName, output, html, alias: userAlias, microFrontend, router, reactCompiler } = config;
|
|
3525
|
+
const buildId = resolveYwkfBuildId(appName);
|
|
3526
|
+
const { env: clientEnv, dropped: droppedEnvKeys } = buildClientEnv({ cwd, env: config.env });
|
|
3527
|
+
if (droppedEnvKeys.length > 0) {
|
|
3528
|
+
console.warn(
|
|
3529
|
+
`[ywkf] \u4EE5\u4E0B\u73AF\u5883\u53D8\u91CF\u7591\u4F3C\u5BC6\u94A5,\u5DF2\u4ECE\u5BA2\u6237\u7AEF\u4EA7\u7269\u4E2D\u5254\u9664:${droppedEnvKeys.join(", ")}\u3002\u5982\u786E\u4E3A\u516C\u5F00\u914D\u7F6E,\u8BF7\u91CD\u547D\u540D\u6216\u8C03\u6574 env.expose\u3002`
|
|
3530
|
+
);
|
|
3531
|
+
}
|
|
3448
3532
|
const ywkfOutputDir = resolveApp(".ywkf");
|
|
3449
3533
|
const defaultAlias = {
|
|
3450
3534
|
"@": resolveApp("src"),
|
|
@@ -3568,7 +3652,11 @@ function createBaseConfig(config, cwd, options = {}) {
|
|
|
3568
3652
|
Buffer: ["buffer", "Buffer"]
|
|
3569
3653
|
}),
|
|
3570
3654
|
new rspack2.DefinePlugin({
|
|
3571
|
-
"
|
|
3655
|
+
"globalThis.__YWKF_BUILD_ID__": JSON.stringify(buildId),
|
|
3656
|
+
// 只内联白名单内的公开配置。整包 process.env 会把构建机环境(CI 凭据、内网地址)
|
|
3657
|
+
// 写进公网可下载的产物,见 client-env.ts。外层括号不可省:该值以 `{` 开头,
|
|
3658
|
+
// `() => process.env.X` 会被替换成 `() => {…}` 而当成函数块体,导致整条 chunk 语法失败。
|
|
3659
|
+
"process.env": `(${JSON.stringify(clientEnv)})`
|
|
3572
3660
|
}),
|
|
3573
3661
|
new rspack2.HtmlRspackPlugin({
|
|
3574
3662
|
template: resolveApp(html.template ?? "public/index.html"),
|
|
@@ -4086,28 +4174,28 @@ function createRspackConfig(config, cwd, options = {}) {
|
|
|
4086
4174
|
}
|
|
4087
4175
|
|
|
4088
4176
|
// src/cli/env.ts
|
|
4089
|
-
import { existsSync as
|
|
4090
|
-
import { resolve as
|
|
4091
|
-
import
|
|
4177
|
+
import { existsSync as existsSync13, readFileSync as readFileSync5 } from "fs";
|
|
4178
|
+
import { resolve as resolve4 } from "path";
|
|
4179
|
+
import dotenv2 from "dotenv";
|
|
4092
4180
|
function preloadEnv(cwd, mode, nodeEnv) {
|
|
4093
4181
|
process.env.NODE_ENV = nodeEnv;
|
|
4094
4182
|
process.env.APP_MODE = mode;
|
|
4095
4183
|
const defaultPaths = [
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4184
|
+
resolve4(cwd, "config/env/.env.public"),
|
|
4185
|
+
resolve4(cwd, ".env.public"),
|
|
4186
|
+
resolve4(cwd, ".env")
|
|
4099
4187
|
];
|
|
4100
4188
|
for (const envPath of defaultPaths) {
|
|
4101
|
-
if (
|
|
4102
|
-
|
|
4189
|
+
if (existsSync13(envPath)) {
|
|
4190
|
+
dotenv2.config({ path: envPath });
|
|
4103
4191
|
break;
|
|
4104
4192
|
}
|
|
4105
4193
|
}
|
|
4106
|
-
const modeEnvPaths = [
|
|
4194
|
+
const modeEnvPaths = [resolve4(cwd, `config/env/.env.${mode}`), resolve4(cwd, `.env.${mode}`)];
|
|
4107
4195
|
for (const envPath of modeEnvPaths) {
|
|
4108
|
-
if (
|
|
4109
|
-
const envContent =
|
|
4110
|
-
const parsed =
|
|
4196
|
+
if (existsSync13(envPath)) {
|
|
4197
|
+
const envContent = readFileSync5(envPath, "utf-8");
|
|
4198
|
+
const parsed = dotenv2.parse(envContent);
|
|
4111
4199
|
for (const key in parsed) {
|
|
4112
4200
|
process.env[key] = parsed[key];
|
|
4113
4201
|
}
|
|
@@ -4119,14 +4207,14 @@ function preloadEnv(cwd, mode, nodeEnv) {
|
|
|
4119
4207
|
}
|
|
4120
4208
|
function loadEnv(config, cwd, mode, nodeEnv) {
|
|
4121
4209
|
const { env } = config;
|
|
4122
|
-
const publicEnvPath =
|
|
4123
|
-
if (
|
|
4124
|
-
|
|
4125
|
-
}
|
|
4126
|
-
const modeEnvPath =
|
|
4127
|
-
if (
|
|
4128
|
-
const envContent =
|
|
4129
|
-
const parsed =
|
|
4210
|
+
const publicEnvPath = resolve4(cwd, env.publicEnvFile ?? "config/env/.env.public");
|
|
4211
|
+
if (existsSync13(publicEnvPath)) {
|
|
4212
|
+
dotenv2.config({ path: publicEnvPath });
|
|
4213
|
+
}
|
|
4214
|
+
const modeEnvPath = resolve4(cwd, env.envDir ?? "config/env", `.env.${mode}`);
|
|
4215
|
+
if (existsSync13(modeEnvPath)) {
|
|
4216
|
+
const envContent = readFileSync5(modeEnvPath, "utf-8");
|
|
4217
|
+
const parsed = dotenv2.parse(envContent);
|
|
4130
4218
|
for (const key in parsed) {
|
|
4131
4219
|
process.env[key] = parsed[key];
|
|
4132
4220
|
}
|
|
@@ -4404,7 +4492,7 @@ async function build(options = {}) {
|
|
|
4404
4492
|
rspackConfig.stats = "none";
|
|
4405
4493
|
rspackConfig.infrastructureLogging = { level: "none" };
|
|
4406
4494
|
const compiler = rspack4(rspackConfig);
|
|
4407
|
-
const stats = await new Promise((
|
|
4495
|
+
const stats = await new Promise((resolve6, reject) => {
|
|
4408
4496
|
compiler.run((err, stats2) => {
|
|
4409
4497
|
if (err) {
|
|
4410
4498
|
reject(err);
|
|
@@ -4414,13 +4502,13 @@ async function build(options = {}) {
|
|
|
4414
4502
|
reject(new Error("Build failed: no stats available"));
|
|
4415
4503
|
return;
|
|
4416
4504
|
}
|
|
4417
|
-
|
|
4505
|
+
resolve6(stats2);
|
|
4418
4506
|
});
|
|
4419
4507
|
});
|
|
4420
|
-
await new Promise((
|
|
4508
|
+
await new Promise((resolve6, reject) => {
|
|
4421
4509
|
compiler.close((err) => {
|
|
4422
4510
|
if (err) reject(err);
|
|
4423
|
-
else
|
|
4511
|
+
else resolve6();
|
|
4424
4512
|
});
|
|
4425
4513
|
});
|
|
4426
4514
|
const hasErrors = stats.hasErrors();
|
|
@@ -4462,7 +4550,7 @@ var PortInUseError = class extends Error {
|
|
|
4462
4550
|
}
|
|
4463
4551
|
};
|
|
4464
4552
|
function ensurePortAvailable(port, host) {
|
|
4465
|
-
return new Promise((
|
|
4553
|
+
return new Promise((resolve6, reject) => {
|
|
4466
4554
|
const server = net.createServer();
|
|
4467
4555
|
server.once("error", (err) => {
|
|
4468
4556
|
if (err.code === "EADDRINUSE") {
|
|
@@ -4472,7 +4560,7 @@ function ensurePortAvailable(port, host) {
|
|
|
4472
4560
|
}
|
|
4473
4561
|
});
|
|
4474
4562
|
server.once("listening", () => {
|
|
4475
|
-
server.close(() =>
|
|
4563
|
+
server.close(() => resolve6());
|
|
4476
4564
|
});
|
|
4477
4565
|
server.listen(port, host);
|
|
4478
4566
|
});
|
|
@@ -4520,8 +4608,8 @@ function parseWindowsNetstatPid(stdout, port) {
|
|
|
4520
4608
|
}
|
|
4521
4609
|
|
|
4522
4610
|
// src/cli/restart-watcher.ts
|
|
4523
|
-
import { existsSync as
|
|
4524
|
-
import { resolve as
|
|
4611
|
+
import { existsSync as existsSync14, watch as watch2 } from "fs";
|
|
4612
|
+
import { resolve as resolve5 } from "path";
|
|
4525
4613
|
function isTriggerFile(filename, mode) {
|
|
4526
4614
|
if (!filename) return false;
|
|
4527
4615
|
if (CONFIG_FILES.includes(filename)) return true;
|
|
@@ -4551,8 +4639,8 @@ function watchForRestart(opts) {
|
|
|
4551
4639
|
}, debounceMs);
|
|
4552
4640
|
};
|
|
4553
4641
|
watchers.push(watch2(cwd, { recursive: false }, (_event, filename) => trigger(filename)));
|
|
4554
|
-
const envDir =
|
|
4555
|
-
if (
|
|
4642
|
+
const envDir = resolve5(cwd, "config/env");
|
|
4643
|
+
if (existsSync14(envDir)) {
|
|
4556
4644
|
watchers.push(watch2(envDir, { recursive: false }, (_event, filename) => trigger(filename)));
|
|
4557
4645
|
}
|
|
4558
4646
|
return {
|
|
@@ -4659,10 +4747,10 @@ async function startDevServer(cwd, config) {
|
|
|
4659
4747
|
if (closed) return;
|
|
4660
4748
|
closed = true;
|
|
4661
4749
|
await server.stop();
|
|
4662
|
-
await new Promise((
|
|
4750
|
+
await new Promise((resolve6, reject) => {
|
|
4663
4751
|
compiler.close((err) => {
|
|
4664
4752
|
if (err) reject(err);
|
|
4665
|
-
else
|
|
4753
|
+
else resolve6();
|
|
4666
4754
|
});
|
|
4667
4755
|
});
|
|
4668
4756
|
};
|
|
@@ -4757,7 +4845,7 @@ async function dev(options = {}) {
|
|
|
4757
4845
|
}
|
|
4758
4846
|
|
|
4759
4847
|
// src/router/plugin.ts
|
|
4760
|
-
import { existsSync as
|
|
4848
|
+
import { existsSync as existsSync15, watch as watch3 } from "fs";
|
|
4761
4849
|
import { join as join14 } from "path";
|
|
4762
4850
|
var ConventionalRoutePlugin = class {
|
|
4763
4851
|
options;
|
|
@@ -4813,7 +4901,7 @@ var ConventionalRoutePlugin = class {
|
|
|
4813
4901
|
* 监听页面目录变化
|
|
4814
4902
|
*/
|
|
4815
4903
|
watchPages(compiler) {
|
|
4816
|
-
if (!
|
|
4904
|
+
if (!existsSync15(this.options.pagesDir)) {
|
|
4817
4905
|
return;
|
|
4818
4906
|
}
|
|
4819
4907
|
this.isWatching = true;
|
|
@@ -4840,6 +4928,370 @@ var ConventionalRoutePlugin = class {
|
|
|
4840
4928
|
}
|
|
4841
4929
|
};
|
|
4842
4930
|
|
|
4931
|
+
// src/runtime/chunk-recovery.ts
|
|
4932
|
+
var DEFAULT_CHUNK_RECOVERY_COOLDOWN_MS = 3e4;
|
|
4933
|
+
var CHUNK_RECOVERY_STORAGE_KEY = "@4399ywkf/core:chunk-recovery-attempt";
|
|
4934
|
+
var CHUNK_RECOVERY_CACHE_BUST_PARAM = "__ywkf_chunk_retry";
|
|
4935
|
+
var CHUNK_RECOVERY_ACTIVE_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
4936
|
+
"@4399ywkf/core/chunk-recovery-active"
|
|
4937
|
+
);
|
|
4938
|
+
var CHUNK_RECOVERY_REGISTRY_SYMBOL = /* @__PURE__ */ Symbol.for(
|
|
4939
|
+
"@4399ywkf/core/chunk-recovery-registry"
|
|
4940
|
+
);
|
|
4941
|
+
var CHUNK_LOAD_ERROR_PATTERNS = [
|
|
4942
|
+
/\bChunkLoadError\b/i,
|
|
4943
|
+
/\bLoading (?:CSS )?chunk\s+\S+\s+failed\b/i,
|
|
4944
|
+
/\bFailed to fetch dynamically imported module\b/i,
|
|
4945
|
+
/\bImporting a module script failed\b/i,
|
|
4946
|
+
/\berror loading dynamically imported module\b/i,
|
|
4947
|
+
/\bUnable to preload CSS for\b/i,
|
|
4948
|
+
/\bFailed to load module script\b/i
|
|
4949
|
+
];
|
|
4950
|
+
function getErrorLikeValue(error, key) {
|
|
4951
|
+
if ((typeof error !== "object" || error === null) && typeof error !== "function") {
|
|
4952
|
+
return void 0;
|
|
4953
|
+
}
|
|
4954
|
+
try {
|
|
4955
|
+
return error[key];
|
|
4956
|
+
} catch {
|
|
4957
|
+
return void 0;
|
|
4958
|
+
}
|
|
4959
|
+
}
|
|
4960
|
+
function matchesChunkLoadError(error, depth) {
|
|
4961
|
+
if (depth > 3) {
|
|
4962
|
+
return false;
|
|
4963
|
+
}
|
|
4964
|
+
if (typeof error === "string") {
|
|
4965
|
+
return CHUNK_LOAD_ERROR_PATTERNS.some((pattern) => pattern.test(error));
|
|
4966
|
+
}
|
|
4967
|
+
const name = getErrorLikeValue(error, "name");
|
|
4968
|
+
const message = getErrorLikeValue(error, "message");
|
|
4969
|
+
const code = getErrorLikeValue(error, "code");
|
|
4970
|
+
const signature = [name, message].filter((value) => typeof value === "string").join(": ");
|
|
4971
|
+
if (code === "CSS_CHUNK_LOAD_FAILED" || CHUNK_LOAD_ERROR_PATTERNS.some((pattern) => pattern.test(signature))) {
|
|
4972
|
+
return true;
|
|
4973
|
+
}
|
|
4974
|
+
const cause = getErrorLikeValue(error, "cause");
|
|
4975
|
+
return cause !== void 0 && cause !== error && matchesChunkLoadError(cause, depth + 1);
|
|
4976
|
+
}
|
|
4977
|
+
function isChunkLoadError(error) {
|
|
4978
|
+
return matchesChunkLoadError(error, 0);
|
|
4979
|
+
}
|
|
4980
|
+
function hashRecoveryIdentity(value) {
|
|
4981
|
+
let hash = 2166136261;
|
|
4982
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
4983
|
+
hash ^= value.charCodeAt(index);
|
|
4984
|
+
hash = Math.imul(hash, 16777619);
|
|
4985
|
+
}
|
|
4986
|
+
return (hash >>> 0).toString(36);
|
|
4987
|
+
}
|
|
4988
|
+
function getFrameworkBuildId() {
|
|
4989
|
+
const buildId = globalThis.__YWKF_BUILD_ID__;
|
|
4990
|
+
return typeof buildId === "string" ? buildId.trim() : "";
|
|
4991
|
+
}
|
|
4992
|
+
function resolveRecoveryId(error, config) {
|
|
4993
|
+
const configuredBuildId = typeof config === "object" && typeof config.buildId === "string" ? config.buildId.trim() : "";
|
|
4994
|
+
const buildId = configuredBuildId || getFrameworkBuildId();
|
|
4995
|
+
if (buildId) {
|
|
4996
|
+
return `build-${hashRecoveryIdentity(buildId)}`;
|
|
4997
|
+
}
|
|
4998
|
+
const request = getErrorLikeValue(error, "request");
|
|
4999
|
+
const name = getErrorLikeValue(error, "name");
|
|
5000
|
+
const message = getErrorLikeValue(error, "message");
|
|
5001
|
+
const signature = [request, name, message].filter((value) => typeof value === "string").join(": ");
|
|
5002
|
+
return `error-${hashRecoveryIdentity(signature || String(error))}`;
|
|
5003
|
+
}
|
|
5004
|
+
function toError(error, fallbackMessage = "Chunk loading failed") {
|
|
5005
|
+
if (error instanceof Error) {
|
|
5006
|
+
return error;
|
|
5007
|
+
}
|
|
5008
|
+
if (typeof error === "string") {
|
|
5009
|
+
return new Error(error);
|
|
5010
|
+
}
|
|
5011
|
+
const message = getErrorLikeValue(error, "message");
|
|
5012
|
+
const name = getErrorLikeValue(error, "name");
|
|
5013
|
+
const normalizedError = new Error(typeof message === "string" ? message : fallbackMessage);
|
|
5014
|
+
if (typeof name === "string") {
|
|
5015
|
+
normalizedError.name = name;
|
|
5016
|
+
}
|
|
5017
|
+
return normalizedError;
|
|
5018
|
+
}
|
|
5019
|
+
function normalizeCooldownMs(value) {
|
|
5020
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 1e3) {
|
|
5021
|
+
return DEFAULT_CHUNK_RECOVERY_COOLDOWN_MS;
|
|
5022
|
+
}
|
|
5023
|
+
return value;
|
|
5024
|
+
}
|
|
5025
|
+
function resolveChunkRecoveryPolicy(config, context) {
|
|
5026
|
+
const options = typeof config === "object" ? config : void 0;
|
|
5027
|
+
const configuredEnabled = typeof config === "boolean" ? config : options?.enabled;
|
|
5028
|
+
const enabledForEnvironment = configuredEnabled ?? context.isProduction;
|
|
5029
|
+
if (!enabledForEnvironment) {
|
|
5030
|
+
return {
|
|
5031
|
+
enabled: false,
|
|
5032
|
+
disabledReason: configuredEnabled === false ? "configuration" : "environment",
|
|
5033
|
+
cooldownMs: normalizeCooldownMs(options?.cooldownMs),
|
|
5034
|
+
globalHandlers: options?.globalHandlers === true
|
|
5035
|
+
};
|
|
5036
|
+
}
|
|
5037
|
+
if (context.isMicroApp && options?.allowInMicroApp !== true) {
|
|
5038
|
+
return {
|
|
5039
|
+
enabled: false,
|
|
5040
|
+
disabledReason: "micro-app",
|
|
5041
|
+
cooldownMs: normalizeCooldownMs(options?.cooldownMs),
|
|
5042
|
+
globalHandlers: options?.globalHandlers === true
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5045
|
+
return {
|
|
5046
|
+
enabled: true,
|
|
5047
|
+
cooldownMs: normalizeCooldownMs(options?.cooldownMs),
|
|
5048
|
+
globalHandlers: options?.globalHandlers === true
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
function parseStoredChunkRecoveryState(value) {
|
|
5052
|
+
if (value === null) {
|
|
5053
|
+
return { attempts: [] };
|
|
5054
|
+
}
|
|
5055
|
+
const parsed = JSON.parse(value);
|
|
5056
|
+
if (!Array.isArray(parsed.attempts)) {
|
|
5057
|
+
throw new Error("Invalid chunk recovery state");
|
|
5058
|
+
}
|
|
5059
|
+
const attempts = parsed.attempts.map((attempt) => {
|
|
5060
|
+
if (typeof attempt !== "object" || attempt === null || typeof attempt.recoveryId !== "string" || typeof attempt.attemptedAt !== "number" || !Number.isFinite(attempt.attemptedAt)) {
|
|
5061
|
+
throw new Error("Invalid chunk recovery attempt");
|
|
5062
|
+
}
|
|
5063
|
+
return attempt;
|
|
5064
|
+
});
|
|
5065
|
+
if (parsed.lastAttemptAt !== void 0 && (typeof parsed.lastAttemptAt !== "number" || !Number.isFinite(parsed.lastAttemptAt))) {
|
|
5066
|
+
throw new Error("Invalid chunk recovery timestamp");
|
|
5067
|
+
}
|
|
5068
|
+
return { attempts, lastAttemptAt: parsed.lastAttemptAt };
|
|
5069
|
+
}
|
|
5070
|
+
function claimChunkRecoveryAttempt(storage, options) {
|
|
5071
|
+
const {
|
|
5072
|
+
cooldownMs = DEFAULT_CHUNK_RECOVERY_COOLDOWN_MS,
|
|
5073
|
+
now,
|
|
5074
|
+
recoveryId,
|
|
5075
|
+
storageKey = CHUNK_RECOVERY_STORAGE_KEY
|
|
5076
|
+
} = options;
|
|
5077
|
+
let state;
|
|
5078
|
+
try {
|
|
5079
|
+
state = parseStoredChunkRecoveryState(storage.getItem(storageKey));
|
|
5080
|
+
} catch {
|
|
5081
|
+
return { claimed: false, reason: "storage-unavailable" };
|
|
5082
|
+
}
|
|
5083
|
+
const existingAttempt = state.attempts.find((attempt) => attempt.recoveryId === recoveryId);
|
|
5084
|
+
if (existingAttempt) {
|
|
5085
|
+
return {
|
|
5086
|
+
claimed: false,
|
|
5087
|
+
reason: "already-attempted",
|
|
5088
|
+
attemptedAt: existingAttempt.attemptedAt
|
|
5089
|
+
};
|
|
5090
|
+
}
|
|
5091
|
+
const inCooldown = state.lastAttemptAt !== void 0 && (state.lastAttemptAt > now || now - state.lastAttemptAt < cooldownMs);
|
|
5092
|
+
if (inCooldown) {
|
|
5093
|
+
return { claimed: false, reason: "cooldown", attemptedAt: state.lastAttemptAt };
|
|
5094
|
+
}
|
|
5095
|
+
try {
|
|
5096
|
+
storage.setItem(
|
|
5097
|
+
storageKey,
|
|
5098
|
+
JSON.stringify({
|
|
5099
|
+
attempts: [...state.attempts, { attemptedAt: now, recoveryId }],
|
|
5100
|
+
lastAttemptAt: now
|
|
5101
|
+
})
|
|
5102
|
+
);
|
|
5103
|
+
} catch {
|
|
5104
|
+
return { claimed: false, reason: "storage-unavailable" };
|
|
5105
|
+
}
|
|
5106
|
+
return { claimed: true, attemptedAt: now };
|
|
5107
|
+
}
|
|
5108
|
+
function isMicroAppRuntime() {
|
|
5109
|
+
if (typeof window === "undefined") {
|
|
5110
|
+
return false;
|
|
5111
|
+
}
|
|
5112
|
+
const runtimeWindow = window;
|
|
5113
|
+
return Boolean(runtimeWindow.__POWERED_BY_QIANKUN__ || runtimeWindow.__GARFISH__);
|
|
5114
|
+
}
|
|
5115
|
+
function getSessionStorage() {
|
|
5116
|
+
if (typeof window === "undefined") {
|
|
5117
|
+
return null;
|
|
5118
|
+
}
|
|
5119
|
+
try {
|
|
5120
|
+
return window.sessionStorage;
|
|
5121
|
+
} catch {
|
|
5122
|
+
return null;
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
function invokeSafely(callback, label) {
|
|
5126
|
+
if (!callback) {
|
|
5127
|
+
return;
|
|
5128
|
+
}
|
|
5129
|
+
try {
|
|
5130
|
+
callback();
|
|
5131
|
+
} catch (error) {
|
|
5132
|
+
console.error(`[ywkf] ${label} \u6267\u884C\u5931\u8D25:`, error);
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
function schedulePageReplace(timestamp) {
|
|
5136
|
+
setTimeout(() => {
|
|
5137
|
+
try {
|
|
5138
|
+
const reloadUrl = new URL(window.location.href);
|
|
5139
|
+
reloadUrl.searchParams.set(CHUNK_RECOVERY_CACHE_BUST_PARAM, String(timestamp));
|
|
5140
|
+
window.location.replace(reloadUrl.toString());
|
|
5141
|
+
} catch (error) {
|
|
5142
|
+
console.error("[ywkf] chunk \u6062\u590D\u5237\u65B0\u5931\u8D25:", error);
|
|
5143
|
+
}
|
|
5144
|
+
}, 0);
|
|
5145
|
+
}
|
|
5146
|
+
function clearChunkRecoveryCacheBustParam() {
|
|
5147
|
+
if (typeof window === "undefined") {
|
|
5148
|
+
return;
|
|
5149
|
+
}
|
|
5150
|
+
try {
|
|
5151
|
+
const currentUrl = new URL(window.location.href);
|
|
5152
|
+
if (!currentUrl.searchParams.has(CHUNK_RECOVERY_CACHE_BUST_PARAM)) {
|
|
5153
|
+
return;
|
|
5154
|
+
}
|
|
5155
|
+
currentUrl.searchParams.delete(CHUNK_RECOVERY_CACHE_BUST_PARAM);
|
|
5156
|
+
window.history.replaceState(window.history.state, "", currentUrl.toString());
|
|
5157
|
+
} catch (error) {
|
|
5158
|
+
console.error("[ywkf] \u6E05\u7406 chunk \u6062\u590D\u53C2\u6570\u5931\u8D25:", error);
|
|
5159
|
+
}
|
|
5160
|
+
}
|
|
5161
|
+
function handleChunkLoadErrorInternal(reason, options, trustedChunkEvent) {
|
|
5162
|
+
if (!trustedChunkEvent && !isChunkLoadError(reason)) {
|
|
5163
|
+
return null;
|
|
5164
|
+
}
|
|
5165
|
+
const error = toError(reason);
|
|
5166
|
+
const timestamp = Date.now();
|
|
5167
|
+
const recoveryId = resolveRecoveryId(reason, options.config);
|
|
5168
|
+
const isMicroApp = options.isMicroApp ?? isMicroAppRuntime();
|
|
5169
|
+
const policy = resolveChunkRecoveryPolicy(options.config, {
|
|
5170
|
+
isProduction: process.env.NODE_ENV === "production",
|
|
5171
|
+
isMicroApp
|
|
5172
|
+
});
|
|
5173
|
+
let outcome;
|
|
5174
|
+
if (!policy.enabled) {
|
|
5175
|
+
outcome = policy.disabledReason === "micro-app" ? "reload-skipped-micro-app" : "reload-skipped-disabled";
|
|
5176
|
+
} else {
|
|
5177
|
+
const storage = getSessionStorage();
|
|
5178
|
+
const claim = storage ? claimChunkRecoveryAttempt(storage, {
|
|
5179
|
+
cooldownMs: policy.cooldownMs,
|
|
5180
|
+
now: timestamp,
|
|
5181
|
+
recoveryId
|
|
5182
|
+
}) : { claimed: false, reason: "storage-unavailable" };
|
|
5183
|
+
if (claim.claimed) {
|
|
5184
|
+
outcome = "reload-scheduled";
|
|
5185
|
+
} else if (claim.reason === "already-attempted") {
|
|
5186
|
+
outcome = "reload-skipped-already-attempted";
|
|
5187
|
+
} else if (claim.reason === "cooldown") {
|
|
5188
|
+
outcome = "reload-skipped-cooldown";
|
|
5189
|
+
} else {
|
|
5190
|
+
outcome = "reload-skipped-storage-unavailable";
|
|
5191
|
+
}
|
|
5192
|
+
}
|
|
5193
|
+
const event = {
|
|
5194
|
+
error,
|
|
5195
|
+
source: options.source,
|
|
5196
|
+
outcome,
|
|
5197
|
+
timestamp,
|
|
5198
|
+
cooldownMs: policy.cooldownMs,
|
|
5199
|
+
recoveryId
|
|
5200
|
+
};
|
|
5201
|
+
invokeSafely(() => options.onError?.(error), "onError");
|
|
5202
|
+
invokeSafely(() => options.onRecoveryEvent?.(event), "onRecoveryEvent");
|
|
5203
|
+
if (outcome === "reload-scheduled") {
|
|
5204
|
+
schedulePageReplace(timestamp);
|
|
5205
|
+
}
|
|
5206
|
+
return event;
|
|
5207
|
+
}
|
|
5208
|
+
function handleChunkLoadError(reason, options) {
|
|
5209
|
+
return handleChunkLoadErrorInternal(reason, options, false);
|
|
5210
|
+
}
|
|
5211
|
+
function getLatestSubscriber(registry) {
|
|
5212
|
+
let latest;
|
|
5213
|
+
for (const subscriber of registry.subscribers.values()) {
|
|
5214
|
+
latest = subscriber;
|
|
5215
|
+
}
|
|
5216
|
+
return latest;
|
|
5217
|
+
}
|
|
5218
|
+
function createGlobalChunkRecoveryRegistry() {
|
|
5219
|
+
const registry = {
|
|
5220
|
+
subscribers: /* @__PURE__ */ new Map()
|
|
5221
|
+
};
|
|
5222
|
+
registry.handleUnhandledRejection = (event) => {
|
|
5223
|
+
const subscriber = getLatestSubscriber(registry);
|
|
5224
|
+
if (!subscriber) return;
|
|
5225
|
+
const recoveryEvent = handleChunkLoadError(event.reason, {
|
|
5226
|
+
...subscriber,
|
|
5227
|
+
source: "unhandled-rejection"
|
|
5228
|
+
});
|
|
5229
|
+
if (recoveryEvent?.outcome === "reload-scheduled") {
|
|
5230
|
+
event.preventDefault();
|
|
5231
|
+
}
|
|
5232
|
+
};
|
|
5233
|
+
registry.handleVitePreloadError = (event) => {
|
|
5234
|
+
const subscriber = getLatestSubscriber(registry);
|
|
5235
|
+
if (!subscriber) return;
|
|
5236
|
+
const payload = event.payload;
|
|
5237
|
+
const recoveryEvent = handleChunkLoadErrorInternal(
|
|
5238
|
+
payload,
|
|
5239
|
+
{
|
|
5240
|
+
...subscriber,
|
|
5241
|
+
source: "vite-preload-error"
|
|
5242
|
+
},
|
|
5243
|
+
true
|
|
5244
|
+
);
|
|
5245
|
+
if (recoveryEvent?.outcome === "reload-scheduled") {
|
|
5246
|
+
event.preventDefault();
|
|
5247
|
+
}
|
|
5248
|
+
};
|
|
5249
|
+
return registry;
|
|
5250
|
+
}
|
|
5251
|
+
function installGlobalChunkRecoveryHandlers(options) {
|
|
5252
|
+
if (typeof window === "undefined") {
|
|
5253
|
+
return () => {
|
|
5254
|
+
};
|
|
5255
|
+
}
|
|
5256
|
+
const isMicroApp = options.isMicroApp ?? isMicroAppRuntime();
|
|
5257
|
+
const policy = resolveChunkRecoveryPolicy(options.config, {
|
|
5258
|
+
isProduction: process.env.NODE_ENV === "production",
|
|
5259
|
+
isMicroApp
|
|
5260
|
+
});
|
|
5261
|
+
if (!policy.enabled || !policy.globalHandlers) {
|
|
5262
|
+
return () => {
|
|
5263
|
+
};
|
|
5264
|
+
}
|
|
5265
|
+
const runtimeWindow = window;
|
|
5266
|
+
let registry = runtimeWindow[CHUNK_RECOVERY_REGISTRY_SYMBOL];
|
|
5267
|
+
if (!registry && runtimeWindow[CHUNK_RECOVERY_ACTIVE_SYMBOL] === true) {
|
|
5268
|
+
return () => {
|
|
5269
|
+
};
|
|
5270
|
+
}
|
|
5271
|
+
if (!registry) {
|
|
5272
|
+
registry = createGlobalChunkRecoveryRegistry();
|
|
5273
|
+
runtimeWindow[CHUNK_RECOVERY_REGISTRY_SYMBOL] = registry;
|
|
5274
|
+
runtimeWindow[CHUNK_RECOVERY_ACTIVE_SYMBOL] = true;
|
|
5275
|
+
window.addEventListener("unhandledrejection", registry.handleUnhandledRejection);
|
|
5276
|
+
window.addEventListener("vite:preloadError", registry.handleVitePreloadError);
|
|
5277
|
+
}
|
|
5278
|
+
const subscriberId = /* @__PURE__ */ Symbol("chunk-recovery-subscriber");
|
|
5279
|
+
registry.subscribers.set(subscriberId, { ...options, isMicroApp });
|
|
5280
|
+
let disposed = false;
|
|
5281
|
+
return () => {
|
|
5282
|
+
if (disposed) return;
|
|
5283
|
+
disposed = true;
|
|
5284
|
+
registry.subscribers.delete(subscriberId);
|
|
5285
|
+
if (registry.subscribers.size > 0) return;
|
|
5286
|
+
window.removeEventListener("unhandledrejection", registry.handleUnhandledRejection);
|
|
5287
|
+
window.removeEventListener("vite:preloadError", registry.handleVitePreloadError);
|
|
5288
|
+
if (runtimeWindow[CHUNK_RECOVERY_REGISTRY_SYMBOL] === registry) {
|
|
5289
|
+
delete runtimeWindow[CHUNK_RECOVERY_REGISTRY_SYMBOL];
|
|
5290
|
+
delete runtimeWindow[CHUNK_RECOVERY_ACTIVE_SYMBOL];
|
|
5291
|
+
}
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5294
|
+
|
|
4843
5295
|
// src/runtime/bootstrap.tsx
|
|
4844
5296
|
import { createRoot } from "react-dom/client";
|
|
4845
5297
|
|
|
@@ -4891,8 +5343,23 @@ function useIsDev() {
|
|
|
4891
5343
|
}
|
|
4892
5344
|
|
|
4893
5345
|
// src/runtime/error-boundary.tsx
|
|
4894
|
-
import {
|
|
5346
|
+
import {
|
|
5347
|
+
Component,
|
|
5348
|
+
createContext as createContext2,
|
|
5349
|
+
useContext as useContext2,
|
|
5350
|
+
useEffect,
|
|
5351
|
+
useMemo,
|
|
5352
|
+
useRef
|
|
5353
|
+
} from "react";
|
|
5354
|
+
import { isRouteErrorResponse, useRouteError } from "react-router";
|
|
4895
5355
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
5356
|
+
var ChunkRecoveryRuntimeContext = createContext2(null);
|
|
5357
|
+
function ChunkRecoveryRuntimeProvider({
|
|
5358
|
+
children,
|
|
5359
|
+
...value
|
|
5360
|
+
}) {
|
|
5361
|
+
return /* @__PURE__ */ jsx2(ChunkRecoveryRuntimeContext.Provider, { value, children });
|
|
5362
|
+
}
|
|
4896
5363
|
var ErrorBoundary = class extends Component {
|
|
4897
5364
|
constructor(props) {
|
|
4898
5365
|
super(props);
|
|
@@ -4902,15 +5369,31 @@ var ErrorBoundary = class extends Component {
|
|
|
4902
5369
|
return { hasError: true, error };
|
|
4903
5370
|
}
|
|
4904
5371
|
componentDidCatch(error, errorInfo) {
|
|
4905
|
-
|
|
4906
|
-
|
|
5372
|
+
const reportError = () => {
|
|
5373
|
+
console.error("[ErrorBoundary] Caught error:", error, errorInfo);
|
|
5374
|
+
this.props.onError?.(error, errorInfo);
|
|
5375
|
+
};
|
|
5376
|
+
if (this.props.chunkRecovery === void 0) {
|
|
5377
|
+
reportError();
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5380
|
+
const recoveryEvent = handleChunkLoadError(error, {
|
|
5381
|
+
source: "error-boundary",
|
|
5382
|
+
config: this.props.chunkRecovery,
|
|
5383
|
+
isMicroApp: this.props.isMicroApp,
|
|
5384
|
+
onError: reportError,
|
|
5385
|
+
onRecoveryEvent: this.props.onRecoveryEvent
|
|
5386
|
+
});
|
|
5387
|
+
if (!recoveryEvent) {
|
|
5388
|
+
reportError();
|
|
5389
|
+
}
|
|
4907
5390
|
}
|
|
4908
5391
|
reset = () => {
|
|
4909
5392
|
this.setState({ hasError: false, error: null });
|
|
4910
5393
|
};
|
|
4911
5394
|
render() {
|
|
4912
5395
|
const { hasError, error } = this.state;
|
|
4913
|
-
const { children, fallback } = this.props;
|
|
5396
|
+
const { children, chunkRecovery, fallback, isMicroApp } = this.props;
|
|
4914
5397
|
if (hasError && error) {
|
|
4915
5398
|
if (typeof fallback === "function") {
|
|
4916
5399
|
return fallback(error, this.reset);
|
|
@@ -4918,12 +5401,86 @@ var ErrorBoundary = class extends Component {
|
|
|
4918
5401
|
if (fallback) {
|
|
4919
5402
|
return fallback;
|
|
4920
5403
|
}
|
|
4921
|
-
|
|
5404
|
+
const resolvedIsMicroApp = isMicroApp ?? isMicroAppRuntime();
|
|
5405
|
+
const chunkRecoveryEnabled = chunkRecovery !== void 0 && resolveChunkRecoveryPolicy(chunkRecovery, {
|
|
5406
|
+
isProduction: process.env.NODE_ENV === "production",
|
|
5407
|
+
isMicroApp: resolvedIsMicroApp
|
|
5408
|
+
}).enabled;
|
|
5409
|
+
const canReloadPage = !resolvedIsMicroApp || typeof chunkRecovery === "object" && chunkRecovery.allowInMicroApp === true;
|
|
5410
|
+
return /* @__PURE__ */ jsx2(
|
|
5411
|
+
DefaultErrorFallback,
|
|
5412
|
+
{
|
|
5413
|
+
canReloadPage,
|
|
5414
|
+
error,
|
|
5415
|
+
isChunkError: chunkRecoveryEnabled && isChunkLoadError(error),
|
|
5416
|
+
onReset: this.reset
|
|
5417
|
+
}
|
|
5418
|
+
);
|
|
4922
5419
|
}
|
|
4923
5420
|
return children;
|
|
4924
5421
|
}
|
|
4925
5422
|
};
|
|
4926
|
-
|
|
5423
|
+
var UNHANDLED_ROUTE_ERROR = /* @__PURE__ */ Symbol("unhandled-route-error");
|
|
5424
|
+
function normalizeRouteError(reason) {
|
|
5425
|
+
if (reason instanceof Error) return reason;
|
|
5426
|
+
if (typeof reason === "string") return new Error(reason);
|
|
5427
|
+
if (isRouteErrorResponse(reason)) {
|
|
5428
|
+
const message = [reason.status, reason.statusText].filter(Boolean).join(" ");
|
|
5429
|
+
const error = new Error(message || "Route request failed");
|
|
5430
|
+
error.name = "RouteErrorResponse";
|
|
5431
|
+
return error;
|
|
5432
|
+
}
|
|
5433
|
+
return new Error("Route rendering failed");
|
|
5434
|
+
}
|
|
5435
|
+
function RouteErrorBoundary({ fallback }) {
|
|
5436
|
+
const reason = useRouteError();
|
|
5437
|
+
const error = useMemo(() => normalizeRouteError(reason), [reason]);
|
|
5438
|
+
const recoveryRuntime = useContext2(ChunkRecoveryRuntimeContext);
|
|
5439
|
+
const handledReasonRef = useRef(UNHANDLED_ROUTE_ERROR);
|
|
5440
|
+
useEffect(() => {
|
|
5441
|
+
if (Object.is(handledReasonRef.current, reason)) return;
|
|
5442
|
+
handledReasonRef.current = reason;
|
|
5443
|
+
const reportError = () => {
|
|
5444
|
+
console.error("[RouteErrorBoundary] Caught error:", error);
|
|
5445
|
+
recoveryRuntime?.onError?.(error);
|
|
5446
|
+
};
|
|
5447
|
+
if (!recoveryRuntime) {
|
|
5448
|
+
reportError();
|
|
5449
|
+
return;
|
|
5450
|
+
}
|
|
5451
|
+
const recoveryEvent = handleChunkLoadError(reason, {
|
|
5452
|
+
source: "route-error-boundary",
|
|
5453
|
+
config: recoveryRuntime.chunkRecovery,
|
|
5454
|
+
isMicroApp: recoveryRuntime.isMicroApp,
|
|
5455
|
+
onError: reportError,
|
|
5456
|
+
onRecoveryEvent: recoveryRuntime.onRecoveryEvent
|
|
5457
|
+
});
|
|
5458
|
+
if (!recoveryEvent) reportError();
|
|
5459
|
+
}, [error, reason, recoveryRuntime]);
|
|
5460
|
+
if (typeof fallback === "function") return fallback(error);
|
|
5461
|
+
if (fallback) return fallback;
|
|
5462
|
+
const chunkRecovery = recoveryRuntime?.chunkRecovery;
|
|
5463
|
+
const resolvedIsMicroApp = recoveryRuntime?.isMicroApp ?? isMicroAppRuntime();
|
|
5464
|
+
const chunkRecoveryEnabled = chunkRecovery !== void 0 && resolveChunkRecoveryPolicy(chunkRecovery, {
|
|
5465
|
+
isProduction: process.env.NODE_ENV === "production",
|
|
5466
|
+
isMicroApp: resolvedIsMicroApp
|
|
5467
|
+
}).enabled;
|
|
5468
|
+
const canReloadPage = !resolvedIsMicroApp || typeof chunkRecovery === "object" && chunkRecovery.allowInMicroApp === true;
|
|
5469
|
+
return /* @__PURE__ */ jsx2(
|
|
5470
|
+
DefaultErrorFallback,
|
|
5471
|
+
{
|
|
5472
|
+
canReloadPage,
|
|
5473
|
+
error,
|
|
5474
|
+
isChunkError: chunkRecoveryEnabled && isChunkLoadError(reason)
|
|
5475
|
+
}
|
|
5476
|
+
);
|
|
5477
|
+
}
|
|
5478
|
+
function DefaultErrorFallback({
|
|
5479
|
+
canReloadPage,
|
|
5480
|
+
error,
|
|
5481
|
+
isChunkError,
|
|
5482
|
+
onReset
|
|
5483
|
+
}) {
|
|
4927
5484
|
const isDev = process.env.NODE_ENV === "development";
|
|
4928
5485
|
return /* @__PURE__ */ jsx2(
|
|
4929
5486
|
"div",
|
|
@@ -4949,7 +5506,7 @@ function DefaultErrorFallback({ error, onReset }) {
|
|
|
4949
5506
|
},
|
|
4950
5507
|
children: [
|
|
4951
5508
|
/* @__PURE__ */ jsx2("h1", { style: { color: "#ff4d4f", marginBottom: 16 }, children: "\u9875\u9762\u51FA\u9519\u4E86" }),
|
|
4952
|
-
/* @__PURE__ */ jsx2("p", { style: { color: "#666", marginBottom: 16 }, children: "\u62B1\u6B49\uFF0C\u9875\u9762\u9047\u5230\u4E86\u4E00\u4E9B\u95EE\u9898\u3002\u8BF7\u5C1D\u8BD5\u5237\u65B0\u9875\u9762\u6216\u8054\u7CFB\u7BA1\u7406\u5458\u3002" }),
|
|
5509
|
+
/* @__PURE__ */ jsx2("p", { style: { color: "#666", marginBottom: 16 }, children: canReloadPage ? "\u62B1\u6B49\uFF0C\u9875\u9762\u9047\u5230\u4E86\u4E00\u4E9B\u95EE\u9898\u3002\u8BF7\u5C1D\u8BD5\u5237\u65B0\u9875\u9762\u6216\u8054\u7CFB\u7BA1\u7406\u5458\u3002" : "\u62B1\u6B49\uFF0C\u9875\u9762\u9047\u5230\u4E86\u4E00\u4E9B\u95EE\u9898\u3002\u8BF7\u5173\u95ED\u5F53\u524D\u9875\u9762\u540E\u91CD\u65B0\u6253\u5F00\uFF0C\u6216\u8054\u7CFB\u7BA1\u7406\u5458\u3002" }),
|
|
4953
5510
|
isDev && /* @__PURE__ */ jsxs(
|
|
4954
5511
|
"details",
|
|
4955
5512
|
{
|
|
@@ -4983,8 +5540,8 @@ function DefaultErrorFallback({ error, onReset }) {
|
|
|
4983
5540
|
]
|
|
4984
5541
|
}
|
|
4985
5542
|
),
|
|
4986
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
4987
|
-
/* @__PURE__ */ jsx2(
|
|
5543
|
+
(canReloadPage || !isChunkError && onReset) && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
5544
|
+
!isChunkError && onReset && /* @__PURE__ */ jsx2(
|
|
4988
5545
|
"button",
|
|
4989
5546
|
{
|
|
4990
5547
|
onClick: onReset,
|
|
@@ -4999,7 +5556,7 @@ function DefaultErrorFallback({ error, onReset }) {
|
|
|
4999
5556
|
children: "\u91CD\u8BD5"
|
|
5000
5557
|
}
|
|
5001
5558
|
),
|
|
5002
|
-
/* @__PURE__ */ jsx2(
|
|
5559
|
+
canReloadPage && /* @__PURE__ */ jsx2(
|
|
5003
5560
|
"button",
|
|
5004
5561
|
{
|
|
5005
5562
|
onClick: () => window.location.reload(),
|
|
@@ -5048,7 +5605,7 @@ function composeProviders(providers) {
|
|
|
5048
5605
|
}, children);
|
|
5049
5606
|
};
|
|
5050
5607
|
}
|
|
5051
|
-
function RootProvider({ config, children }) {
|
|
5608
|
+
function RootProvider({ config, children, isMicroApp }) {
|
|
5052
5609
|
const {
|
|
5053
5610
|
appName = "app",
|
|
5054
5611
|
router,
|
|
@@ -5056,7 +5613,8 @@ function RootProvider({ config, children }) {
|
|
|
5056
5613
|
strictMode = true,
|
|
5057
5614
|
antd = { enabled: true },
|
|
5058
5615
|
providers = [],
|
|
5059
|
-
lifecycle
|
|
5616
|
+
lifecycle,
|
|
5617
|
+
chunkRecovery
|
|
5060
5618
|
} = config;
|
|
5061
5619
|
const appContextValue = {
|
|
5062
5620
|
appName,
|
|
@@ -5087,8 +5645,30 @@ function RootProvider({ config, children }) {
|
|
|
5087
5645
|
...providers.map((p) => ({ ...p, order: p.order ?? 50 }))
|
|
5088
5646
|
];
|
|
5089
5647
|
const ComposedProviders = composeProviders(allProviders);
|
|
5648
|
+
const rootChunkRecovery = chunkRecovery ?? {
|
|
5649
|
+
enabled: process.env.NODE_ENV === "production"
|
|
5650
|
+
};
|
|
5651
|
+
const resolvedIsMicroApp = isMicroApp ?? isMicroAppRuntime();
|
|
5090
5652
|
const content = router ? /* @__PURE__ */ jsx3(Suspense, { fallback: /* @__PURE__ */ jsx3(DefaultLoading, {}), children: /* @__PURE__ */ jsx3(RouterProvider, { router }) }) : children;
|
|
5091
|
-
const app = /* @__PURE__ */ jsx3(
|
|
5653
|
+
const app = /* @__PURE__ */ jsx3(
|
|
5654
|
+
ErrorBoundary,
|
|
5655
|
+
{
|
|
5656
|
+
chunkRecovery: rootChunkRecovery,
|
|
5657
|
+
isMicroApp: resolvedIsMicroApp,
|
|
5658
|
+
onError: lifecycle?.onError,
|
|
5659
|
+
onRecoveryEvent: lifecycle?.onRecoveryEvent,
|
|
5660
|
+
children: /* @__PURE__ */ jsx3(
|
|
5661
|
+
ChunkRecoveryRuntimeProvider,
|
|
5662
|
+
{
|
|
5663
|
+
chunkRecovery: rootChunkRecovery,
|
|
5664
|
+
isMicroApp: resolvedIsMicroApp,
|
|
5665
|
+
onError: lifecycle?.onError,
|
|
5666
|
+
onRecoveryEvent: lifecycle?.onRecoveryEvent,
|
|
5667
|
+
children: /* @__PURE__ */ jsx3(ComposedProviders, { children: content })
|
|
5668
|
+
}
|
|
5669
|
+
)
|
|
5670
|
+
}
|
|
5671
|
+
);
|
|
5092
5672
|
if (strictMode) {
|
|
5093
5673
|
return /* @__PURE__ */ jsx3(StrictMode, { children: app });
|
|
5094
5674
|
}
|
|
@@ -5105,6 +5685,7 @@ function createProvider(component, props, order) {
|
|
|
5105
5685
|
// src/runtime/bootstrap.tsx
|
|
5106
5686
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
5107
5687
|
var root = null;
|
|
5688
|
+
var disposeChunkRecoveryHandlers = null;
|
|
5108
5689
|
async function resolveAppConfig(config) {
|
|
5109
5690
|
if (config.router || !config.conventionalRoutes) {
|
|
5110
5691
|
return config;
|
|
@@ -5127,6 +5708,10 @@ async function resolveAppConfig(config) {
|
|
|
5127
5708
|
}
|
|
5128
5709
|
async function bootstrap(config) {
|
|
5129
5710
|
const { rootId = "root", lifecycle } = config;
|
|
5711
|
+
const isMicroApp = isMicroAppEnv();
|
|
5712
|
+
if (!isMicroApp) {
|
|
5713
|
+
clearChunkRecoveryCacheBustParam();
|
|
5714
|
+
}
|
|
5130
5715
|
const resolvedConfig = await resolveAppConfig(config);
|
|
5131
5716
|
if (lifecycle?.onBeforeMount) {
|
|
5132
5717
|
await lifecycle.onBeforeMount();
|
|
@@ -5135,8 +5720,22 @@ async function bootstrap(config) {
|
|
|
5135
5720
|
if (!rootElement) {
|
|
5136
5721
|
throw new Error(`\u627E\u4E0D\u5230\u6839\u5143\u7D20 #${rootId}`);
|
|
5137
5722
|
}
|
|
5138
|
-
|
|
5139
|
-
|
|
5723
|
+
disposeChunkRecoveryHandlers?.();
|
|
5724
|
+
const nextDisposeChunkRecoveryHandlers = installGlobalChunkRecoveryHandlers({
|
|
5725
|
+
config: resolvedConfig.chunkRecovery,
|
|
5726
|
+
isMicroApp,
|
|
5727
|
+
onError: (error) => resolvedConfig.lifecycle?.onError?.(error),
|
|
5728
|
+
onRecoveryEvent: resolvedConfig.lifecycle?.onRecoveryEvent
|
|
5729
|
+
});
|
|
5730
|
+
try {
|
|
5731
|
+
root = createRoot(rootElement);
|
|
5732
|
+
root.render(/* @__PURE__ */ jsx4(RootProvider, { config: resolvedConfig, isMicroApp }));
|
|
5733
|
+
disposeChunkRecoveryHandlers = nextDisposeChunkRecoveryHandlers;
|
|
5734
|
+
} catch (error) {
|
|
5735
|
+
nextDisposeChunkRecoveryHandlers();
|
|
5736
|
+
root = null;
|
|
5737
|
+
throw error;
|
|
5738
|
+
}
|
|
5140
5739
|
if (lifecycle?.onMounted) {
|
|
5141
5740
|
setTimeout(() => {
|
|
5142
5741
|
lifecycle.onMounted?.();
|
|
@@ -5149,6 +5748,8 @@ async function bootstrap(config) {
|
|
|
5149
5748
|
}
|
|
5150
5749
|
}
|
|
5151
5750
|
function unmount() {
|
|
5751
|
+
disposeChunkRecoveryHandlers?.();
|
|
5752
|
+
disposeChunkRecoveryHandlers = null;
|
|
5152
5753
|
if (root) {
|
|
5153
5754
|
root.unmount();
|
|
5154
5755
|
root = null;
|
|
@@ -5156,6 +5757,7 @@ function unmount() {
|
|
|
5156
5757
|
}
|
|
5157
5758
|
function createMicroApp(getConfig) {
|
|
5158
5759
|
let microRoot = null;
|
|
5760
|
+
let disposeMicroChunkRecoveryHandlers = null;
|
|
5159
5761
|
return {
|
|
5160
5762
|
/**
|
|
5161
5763
|
* 微前端 bootstrap 生命周期
|
|
@@ -5179,8 +5781,22 @@ function createMicroApp(getConfig) {
|
|
|
5179
5781
|
if (resolvedConfig.lifecycle?.onBeforeMount) {
|
|
5180
5782
|
await resolvedConfig.lifecycle.onBeforeMount();
|
|
5181
5783
|
}
|
|
5182
|
-
|
|
5183
|
-
|
|
5784
|
+
disposeMicroChunkRecoveryHandlers?.();
|
|
5785
|
+
const nextDisposeMicroChunkRecoveryHandlers = installGlobalChunkRecoveryHandlers({
|
|
5786
|
+
config: resolvedConfig.chunkRecovery,
|
|
5787
|
+
isMicroApp: true,
|
|
5788
|
+
onError: (error) => resolvedConfig.lifecycle?.onError?.(error),
|
|
5789
|
+
onRecoveryEvent: resolvedConfig.lifecycle?.onRecoveryEvent
|
|
5790
|
+
});
|
|
5791
|
+
try {
|
|
5792
|
+
microRoot = createRoot(rootElement);
|
|
5793
|
+
microRoot.render(/* @__PURE__ */ jsx4(RootProvider, { config: resolvedConfig, isMicroApp: true }));
|
|
5794
|
+
disposeMicroChunkRecoveryHandlers = nextDisposeMicroChunkRecoveryHandlers;
|
|
5795
|
+
} catch (error) {
|
|
5796
|
+
nextDisposeMicroChunkRecoveryHandlers();
|
|
5797
|
+
microRoot = null;
|
|
5798
|
+
throw error;
|
|
5799
|
+
}
|
|
5184
5800
|
if (resolvedConfig.lifecycle?.onMounted) {
|
|
5185
5801
|
setTimeout(() => {
|
|
5186
5802
|
resolvedConfig.lifecycle?.onMounted?.();
|
|
@@ -5200,6 +5816,8 @@ function createMicroApp(getConfig) {
|
|
|
5200
5816
|
microRoot.unmount();
|
|
5201
5817
|
microRoot = null;
|
|
5202
5818
|
}
|
|
5819
|
+
disposeMicroChunkRecoveryHandlers?.();
|
|
5820
|
+
disposeMicroChunkRecoveryHandlers = null;
|
|
5203
5821
|
},
|
|
5204
5822
|
/**
|
|
5205
5823
|
* 微前端 update 生命周期(可选)
|
|
@@ -5227,11 +5845,16 @@ function getMicroAppPublicPath() {
|
|
|
5227
5845
|
export {
|
|
5228
5846
|
AppContext,
|
|
5229
5847
|
AppContextProvider,
|
|
5848
|
+
CHUNK_RECOVERY_ACTIVE_SYMBOL,
|
|
5849
|
+
CHUNK_RECOVERY_CACHE_BUST_PARAM,
|
|
5850
|
+
CHUNK_RECOVERY_STORAGE_KEY,
|
|
5230
5851
|
ConventionalRouteGenerator,
|
|
5231
5852
|
ConventionalRoutePlugin,
|
|
5853
|
+
DEFAULT_CHUNK_RECOVERY_COOLDOWN_MS,
|
|
5232
5854
|
ErrorBoundary,
|
|
5233
5855
|
PluginManager,
|
|
5234
5856
|
RootProvider,
|
|
5857
|
+
RouteErrorBoundary,
|
|
5235
5858
|
YwkfGenerator,
|
|
5236
5859
|
YwkfGeneratorPlugin,
|
|
5237
5860
|
analyticsPlugin,
|
|
@@ -5239,6 +5862,8 @@ export {
|
|
|
5239
5862
|
bootstrap,
|
|
5240
5863
|
browserCheckPlugin,
|
|
5241
5864
|
build,
|
|
5865
|
+
claimChunkRecoveryAttempt,
|
|
5866
|
+
clearChunkRecoveryCacheBustParam,
|
|
5242
5867
|
createBaseConfig,
|
|
5243
5868
|
createDevConfig,
|
|
5244
5869
|
createMicroApp,
|
|
@@ -5254,10 +5879,15 @@ export {
|
|
|
5254
5879
|
generateConventionalRoutes,
|
|
5255
5880
|
getDefaultBiomeConfig,
|
|
5256
5881
|
getMicroAppPublicPath,
|
|
5882
|
+
handleChunkLoadError,
|
|
5257
5883
|
i18nPlugin,
|
|
5884
|
+
installGlobalChunkRecoveryHandlers,
|
|
5885
|
+
isChunkLoadError,
|
|
5258
5886
|
isMicroAppEnv,
|
|
5887
|
+
isMicroAppRuntime,
|
|
5259
5888
|
mockPlugin,
|
|
5260
5889
|
reactQueryPlugin,
|
|
5890
|
+
resolveChunkRecoveryPolicy,
|
|
5261
5891
|
tailwindPlugin,
|
|
5262
5892
|
themePlugin,
|
|
5263
5893
|
unmount,
|