@xfe-repo/web-app 1.6.4 → 2.0.0-beta.2
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 +118 -1
- package/client.d.ts +1 -0
- package/deploy/.drone.yml +13 -4
- package/deploy/Dockerfile +15 -6
- package/deploy/helm/templates/deployment.yaml +5 -18
- package/deploy/helm/templates/svc.yaml +1 -1
- package/dist/cli.js +577 -416
- package/dist/cli.mjs +562 -256
- package/dist/config.d.mts +30 -6
- package/dist/config.d.ts +30 -6
- package/dist/config.js +142 -298
- package/dist/config.mjs +124 -2
- package/dist/framework.d.mts +10 -0
- package/dist/framework.d.ts +10 -0
- package/dist/framework.js +220 -0
- package/dist/framework.mjs +182 -0
- package/dist/node-dev.d.mts +2 -0
- package/dist/node-dev.d.ts +2 -0
- package/dist/node-dev.js +358 -0
- package/dist/node-dev.mjs +332 -0
- package/dist/node.d.mts +27 -0
- package/dist/node.d.ts +27 -0
- package/dist/node.js +381 -0
- package/dist/node.mjs +343 -0
- package/dist/react-router-config.d.mts +11 -0
- package/dist/react-router-config.d.ts +11 -0
- package/dist/react-router-config.js +111 -0
- package/dist/react-router-config.mjs +77 -0
- package/dist/root.d.mts +17 -0
- package/dist/root.d.ts +17 -0
- package/dist/root.js +61 -0
- package/dist/root.mjs +34 -0
- package/dist/serve.d.mts +10 -0
- package/dist/serve.d.ts +10 -0
- package/dist/serve.js +71 -0
- package/dist/serve.mjs +36 -0
- package/dist/vite.d.mts +10 -0
- package/dist/vite.d.ts +10 -0
- package/dist/vite.js +182 -0
- package/dist/vite.mjs +146 -0
- package/package.json +27 -72
- package/tsconfig.json +4 -1
- package/config/env.js +0 -104
- package/config/getHttpsConfig.js +0 -66
- package/config/jest/babelTransform.js +0 -29
- package/config/jest/cssTransform.js +0 -14
- package/config/jest/fileTransform.js +0 -40
- package/config/modules.js +0 -133
- package/config/paths.js +0 -65
- package/config/webpack/persistentCache/createEnvironmentHash.js +0 -9
- package/config/webpack/webpack.config.js +0 -737
- package/config/webpack/webpackDevServer.config.js +0 -122
- package/deploy/nginx.conf +0 -62
- package/dist/chunk-75BJNL7E.mjs +0 -239
- package/scripts/build.js +0 -217
- package/scripts/dev.js +0 -162
package/dist/node.mjs
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// src/node.ts
|
|
2
|
+
import { once } from "events";
|
|
3
|
+
import { rm } from "fs/promises";
|
|
4
|
+
import { Server } from "http";
|
|
5
|
+
import path3 from "path";
|
|
6
|
+
import { pathToFileURL } from "url";
|
|
7
|
+
import express from "express";
|
|
8
|
+
|
|
9
|
+
// src/config.ts
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
import yaml from "yaml";
|
|
14
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
15
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
16
|
+
var configDirectory = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
var loadXfeConfig = (root = process.cwd()) => {
|
|
18
|
+
const xfeConfigPath = path.join(root, "xfe.json");
|
|
19
|
+
if (!fs.existsSync(xfeConfigPath)) {
|
|
20
|
+
throw new Error("xfe.json \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u521B\u5EFA\u8BE5\u6587\u4EF6\u3002");
|
|
21
|
+
}
|
|
22
|
+
const xfeConfigContent = fs.readFileSync(xfeConfigPath, "utf8");
|
|
23
|
+
const config = JSON.parse(xfeConfigContent);
|
|
24
|
+
const renderMode = config.webapp?.renderMode;
|
|
25
|
+
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
26
|
+
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
27
|
+
}
|
|
28
|
+
getBuildDirectory(root, config.webapp);
|
|
29
|
+
getServerEntry(root, config.webapp);
|
|
30
|
+
return config;
|
|
31
|
+
};
|
|
32
|
+
var getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
33
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
|
|
34
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
35
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
36
|
+
}
|
|
37
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
38
|
+
const root = path.resolve(projectRoot);
|
|
39
|
+
const output = path.resolve(root, directory);
|
|
40
|
+
const relative = path.relative(root, output);
|
|
41
|
+
const [firstDirectory = ""] = relative.split(path.sep);
|
|
42
|
+
const escapesProject = path.isAbsolute(directory) || Boolean(path.win32.parse(directory).root) || firstDirectory === "..";
|
|
43
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
44
|
+
if (escapesProject || overwritesInput) {
|
|
45
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u9879\u76EE\u5185\u72EC\u7ACB\u7684\u8F93\u51FA\u76EE\u5F55\uFF0C\u4E0D\u80FD\u8986\u76D6\u9879\u76EE\u3001\u6E90\u7801\u6216\u4F9D\u8D56");
|
|
46
|
+
}
|
|
47
|
+
let currentDirectory = root;
|
|
48
|
+
for (const segment of relative.split(path.sep)) {
|
|
49
|
+
currentDirectory = path.join(currentDirectory, segment);
|
|
50
|
+
if (fs.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
51
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return output;
|
|
55
|
+
};
|
|
56
|
+
var getServerEntry = (projectRoot, webapp = {}) => {
|
|
57
|
+
const entry = webapp?.serverEntry;
|
|
58
|
+
if (entry === void 0) return;
|
|
59
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
60
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
61
|
+
}
|
|
62
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
63
|
+
const absolute = path.resolve(projectRoot, normalized);
|
|
64
|
+
const relative = path.relative(path.resolve(projectRoot), absolute);
|
|
65
|
+
const outside = Boolean(path.win32.parse(normalized).root) || relative.split(path.sep)[0] === "..";
|
|
66
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
67
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
68
|
+
}
|
|
69
|
+
return absolute;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/framework.ts
|
|
73
|
+
import fs2 from "fs";
|
|
74
|
+
import { createRequire } from "module";
|
|
75
|
+
import path2 from "path";
|
|
76
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
77
|
+
var frameworkDirectory = typeof __dirname === "string" ? __dirname : path2.dirname(fileURLToPath2(import.meta.url));
|
|
78
|
+
var requireFromFramework = createRequire(path2.join(frameworkDirectory, "framework.js"));
|
|
79
|
+
var extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
80
|
+
var findSource = (directory, name) => extensions.map((extension) => path2.join(directory, `${name}${extension}`)).find(fs2.existsSync);
|
|
81
|
+
var findValueExports = (file) => [...fs2.readFileSync(file, "utf8").matchAll(/^\s*export\s+(?:async\s+)?(?:const|let|var|function|class)\s+([A-Za-z_$][\w$]*)/gm)].map(
|
|
82
|
+
([, name]) => name
|
|
83
|
+
);
|
|
84
|
+
var importPath = (from, target) => {
|
|
85
|
+
const relative = path2.relative(from, target).replace(path2.extname(target), "").replaceAll(path2.sep, "/");
|
|
86
|
+
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
87
|
+
};
|
|
88
|
+
var writeGenerated = (file, content) => {
|
|
89
|
+
if (fs2.existsSync(file) && fs2.readFileSync(file, "utf8") === content) return;
|
|
90
|
+
fs2.writeFileSync(file, content);
|
|
91
|
+
};
|
|
92
|
+
var defaultRootSource = (projectRoot, appDirectory) => {
|
|
93
|
+
const { webapp = {} } = loadXfeConfig(projectRoot);
|
|
94
|
+
const layoutSource = findSource(path2.join(projectRoot, "src"), "layout");
|
|
95
|
+
const layoutExports = layoutSource ? findValueExports(layoutSource) : [];
|
|
96
|
+
const hasErrorView = layoutExports.includes("ErrorView");
|
|
97
|
+
const layoutImport = layoutSource ? `import AppLayout${hasErrorView ? ", { ErrorView }" : ""} from ${JSON.stringify(importPath(appDirectory, layoutSource))}
|
|
98
|
+
` : "";
|
|
99
|
+
return `import { createElement, type ReactNode } from 'react'
|
|
100
|
+
import { Outlet } from 'react-router'
|
|
101
|
+
import { Document, PageError, PageLoading } from '@xfe-repo/web-app/dist/root.mjs'
|
|
102
|
+
${layoutImport}
|
|
103
|
+
export const meta = () => [{ title: ${JSON.stringify(webapp.title || "XFE App")} }]
|
|
104
|
+
export const Layout = ({ children }: { children: ReactNode }) => createElement(Document, { children, lang: ${JSON.stringify(webapp.lang || "zh-CN")}, themeColor: ${JSON.stringify(webapp.themeColor)} })
|
|
105
|
+
export default function Root() { return ${layoutSource ? "createElement(AppLayout, { children: createElement(Outlet) })" : "createElement(Outlet)"} }
|
|
106
|
+
export function ErrorBoundary() { return createElement(PageError, { ${hasErrorView ? "view: ErrorView" : ""} }) }
|
|
107
|
+
export function HydrateFallback() { return createElement(PageLoading) }
|
|
108
|
+
`;
|
|
109
|
+
};
|
|
110
|
+
var getFrameworkRoot = (projectRoot) => path2.join(projectRoot, "node_modules/.cache/xfe-web/react-router");
|
|
111
|
+
var prepareFramework = (projectRoot = process.cwd()) => {
|
|
112
|
+
const sourceDirectory = path2.join(projectRoot, "src");
|
|
113
|
+
const rootSource = findSource(sourceDirectory, "root");
|
|
114
|
+
const appServerSource = findSource(sourceDirectory, "app.server");
|
|
115
|
+
const pagesSource = path2.join(sourceDirectory, "pages");
|
|
116
|
+
if (!fs2.existsSync(pagesSource)) throw new Error("\u672A\u627E\u5230 src/pages");
|
|
117
|
+
const rootDirectory = getFrameworkRoot(projectRoot);
|
|
118
|
+
const appDirectory = path2.join(rootDirectory, "app");
|
|
119
|
+
fs2.mkdirSync(appDirectory, { recursive: true });
|
|
120
|
+
const routerDirectory = path2.dirname(requireFromFramework.resolve("react-router/package.json"));
|
|
121
|
+
const routerLink = path2.join(rootDirectory, "node_modules/react-router");
|
|
122
|
+
fs2.mkdirSync(path2.dirname(routerLink), { recursive: true });
|
|
123
|
+
if (!fs2.lstatSync(routerLink, { throwIfNoEntry: false })?.isSymbolicLink() || fs2.readlinkSync(routerLink) !== routerDirectory) {
|
|
124
|
+
fs2.rmSync(routerLink, { force: true });
|
|
125
|
+
fs2.symlinkSync(routerDirectory, routerLink, "junction");
|
|
126
|
+
}
|
|
127
|
+
const rootTarget = path2.join(appDirectory, "root.tsx");
|
|
128
|
+
const rootImport = rootSource ? importPath(appDirectory, rootSource) : "";
|
|
129
|
+
const rootExports = rootSource ? findValueExports(rootSource).filter((name) => name !== "middleware" || !appServerSource) : [];
|
|
130
|
+
const namedExports = rootExports.length ? `export { ${rootExports.join(", ")} } from ${JSON.stringify(rootImport)}
|
|
131
|
+
` : "";
|
|
132
|
+
const errorBoundaryExport = rootExports.includes("ErrorBoundary") ? "" : "export { DefaultErrorBoundary as ErrorBoundary } from '@xfe-repo/web-router/errors'\n";
|
|
133
|
+
const middlewareExport = appServerSource ? `export { middleware } from ${JSON.stringify(importPath(appDirectory, appServerSource))}
|
|
134
|
+
` : "";
|
|
135
|
+
writeGenerated(
|
|
136
|
+
rootTarget,
|
|
137
|
+
rootSource ? `export * from ${JSON.stringify(rootImport)}
|
|
138
|
+
export { default } from ${JSON.stringify(rootImport)}
|
|
139
|
+
${namedExports}${errorBoundaryExport}${middlewareExport}` : `${defaultRootSource(projectRoot, appDirectory)}${middlewareExport}`
|
|
140
|
+
);
|
|
141
|
+
const pagesLink = path2.join(appDirectory, "pages");
|
|
142
|
+
if (!fs2.existsSync(pagesLink)) fs2.symlinkSync(path2.relative(appDirectory, pagesSource), pagesLink, "dir");
|
|
143
|
+
writeGenerated(
|
|
144
|
+
path2.join(rootDirectory, "react-router.config.js"),
|
|
145
|
+
"export { default } from '@xfe-repo/web-app/dist/react-router-config.mjs'\n"
|
|
146
|
+
);
|
|
147
|
+
writeGenerated(
|
|
148
|
+
path2.join(appDirectory, "routes.js"),
|
|
149
|
+
`import { collectPageRoutes } from '@xfe-repo/web-router/routes'
|
|
150
|
+
export default collectPageRoutes(${JSON.stringify(appDirectory)})
|
|
151
|
+
`
|
|
152
|
+
);
|
|
153
|
+
const defaultsDirectory = path2.join(path2.dirname(requireFromFramework.resolve("@react-router/dev/package.json")), "dist/config/defaults");
|
|
154
|
+
writeGenerated(
|
|
155
|
+
path2.join(appDirectory, "entry.server.tsx"),
|
|
156
|
+
`export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory, path2.join(defaultsDirectory, "entry.server.web.tsx")))}
|
|
157
|
+
`
|
|
158
|
+
);
|
|
159
|
+
const typeScriptConfig = path2.join(rootDirectory, "tsconfig.json");
|
|
160
|
+
writeGenerated(
|
|
161
|
+
typeScriptConfig,
|
|
162
|
+
JSON.stringify(
|
|
163
|
+
{
|
|
164
|
+
extends: path2.join(projectRoot, "tsconfig.json"),
|
|
165
|
+
compilerOptions: { rootDirs: [projectRoot, rootDirectory, path2.join(rootDirectory, ".react-router/types")] },
|
|
166
|
+
include: [
|
|
167
|
+
path2.join(sourceDirectory, "**/*"),
|
|
168
|
+
path2.join(projectRoot, "types/**/*"),
|
|
169
|
+
path2.join(appDirectory, "*.tsx"),
|
|
170
|
+
path2.join(rootDirectory, ".react-router/types/**/*")
|
|
171
|
+
],
|
|
172
|
+
exclude: []
|
|
173
|
+
},
|
|
174
|
+
null,
|
|
175
|
+
2
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
return {
|
|
179
|
+
appDirectory,
|
|
180
|
+
rootDirectory,
|
|
181
|
+
viteConfig: path2.resolve(frameworkDirectory, "vite.mjs"),
|
|
182
|
+
typeScriptConfig
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/node.ts
|
|
187
|
+
var NODE_OUTPUT = "server/node.mjs";
|
|
188
|
+
var HMR_PATH = "/_xfe/hmr";
|
|
189
|
+
var SHUTDOWN_TIMEOUT = 3e4;
|
|
190
|
+
async function buildNode({ projectRoot, webapp }) {
|
|
191
|
+
const { build } = await import("esbuild");
|
|
192
|
+
const entry = getServerEntry(projectRoot, webapp);
|
|
193
|
+
if (!entry) throw new Error("\u7F3A\u5C11 xfe.json.webapp.serverEntry");
|
|
194
|
+
if (webapp.renderMode === "client") await rm(path3.join(getBuildDirectory(projectRoot, webapp), "server"), { recursive: true, force: true });
|
|
195
|
+
await build({
|
|
196
|
+
absWorkingDir: projectRoot,
|
|
197
|
+
entryPoints: [entry],
|
|
198
|
+
outfile: path3.join(getBuildDirectory(projectRoot, webapp), NODE_OUTPUT),
|
|
199
|
+
tsconfig: path3.join(projectRoot, "tsconfig.json"),
|
|
200
|
+
bundle: true,
|
|
201
|
+
packages: "external",
|
|
202
|
+
platform: "node",
|
|
203
|
+
format: "esm",
|
|
204
|
+
target: "node22.22",
|
|
205
|
+
sourcemap: true
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function runNode({ projectRoot, webapp, development }) {
|
|
209
|
+
const entry = development ? getServerEntry(projectRoot, webapp) : path3.join(getBuildDirectory(projectRoot, webapp), NODE_OUTPUT);
|
|
210
|
+
if (!entry) throw new Error("\u7F3A\u5C11 xfe.json.webapp.serverEntry");
|
|
211
|
+
if (development) {
|
|
212
|
+
const { loadEnv } = await import("vite");
|
|
213
|
+
Object.assign(process.env, { ...loadEnv("development", projectRoot, ""), ...process.env });
|
|
214
|
+
} else process.env.NODE_ENV ??= "production";
|
|
215
|
+
const module = await import(pathToFileURL(entry).href);
|
|
216
|
+
if (typeof module.default !== "function") throw new Error("serverEntry \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA Node \u670D\u52A1\u5DE5\u5382\u51FD\u6570");
|
|
217
|
+
const frontend = express().disable("x-powered-by");
|
|
218
|
+
const application = await module.default({ frontend, mode: development ? "development" : "production" });
|
|
219
|
+
const upgrades = /* @__PURE__ */ new Set();
|
|
220
|
+
let vite;
|
|
221
|
+
let closing;
|
|
222
|
+
const close = () => closing ??= disposeApplication(application, { vite, upgrades });
|
|
223
|
+
const onSignal = async () => {
|
|
224
|
+
try {
|
|
225
|
+
await close();
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.error("XFE Node \u5173\u95ED\u5931\u8D25:", error);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
} finally {
|
|
230
|
+
process.off("SIGINT", onSignal);
|
|
231
|
+
process.off("SIGTERM", onSignal);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
try {
|
|
235
|
+
const server = application?.server;
|
|
236
|
+
if (!(server instanceof Server) || server.listening) throw new Error("Node \u5DE5\u5382\u5FC5\u987B\u8FD4\u56DE\u5C1A\u672A listen \u7684 http.Server");
|
|
237
|
+
if (server.listenerCount("upgrade")) throw new Error("\u8BF7\u901A\u8FC7\u5DE5\u5382\u8FD4\u56DE\u7684 upgrade \u5904\u7406\u5347\u7EA7\uFF0C\u4E0D\u8981\u76F4\u63A5\u6CE8\u518C server \u7684 upgrade \u4E8B\u4EF6");
|
|
238
|
+
const hmrPath = path3.posix.join(webapp.basename || "/", HMR_PATH);
|
|
239
|
+
server.on(
|
|
240
|
+
"upgrade",
|
|
241
|
+
/** HMR 与业务互斥分流,升级连接由关闭流程统一回收。 */
|
|
242
|
+
(request, socket, head) => {
|
|
243
|
+
upgrades.add(socket);
|
|
244
|
+
socket.once(
|
|
245
|
+
"close",
|
|
246
|
+
/** 不保留已经断开的升级连接。 */
|
|
247
|
+
() => upgrades.delete(socket)
|
|
248
|
+
);
|
|
249
|
+
if (development && request.url?.split("?")[0] === hmrPath) {
|
|
250
|
+
if (!["vite-hmr", "vite-ping"].includes(String(request.headers["sec-websocket-protocol"]))) socket.destroy();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
if (application.upgrade) application.upgrade(request, socket, head);
|
|
254
|
+
else socket.destroy();
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
if (development) vite = await createDevelopmentServer(server, projectRoot);
|
|
258
|
+
await mountFrontend(frontend, { projectRoot, webapp, vite });
|
|
259
|
+
const listening = once(server, "listening");
|
|
260
|
+
const host = process.env.HOST || webapp.host || "0.0.0.0";
|
|
261
|
+
const port = Number(process.env.PORT ?? webapp.port ?? 3e3);
|
|
262
|
+
server.listen(port, host);
|
|
263
|
+
await listening;
|
|
264
|
+
console.info(`XFE Node: http://${host}:${port}`);
|
|
265
|
+
process.on("SIGINT", onSignal);
|
|
266
|
+
process.on("SIGTERM", onSignal);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
await close();
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async function createDevelopmentServer(server, projectRoot) {
|
|
273
|
+
const { createServer } = await import("vite");
|
|
274
|
+
const framework = prepareFramework(projectRoot);
|
|
275
|
+
const events = [[process, "SIGINT"], [process, "SIGTERM"], [process.stdin, "end"]];
|
|
276
|
+
const snapshots = events.map(
|
|
277
|
+
/** 只记录当前监听,恢复时保留宿主和业务原有的处理器。 */
|
|
278
|
+
([source, event]) => ({ source, event, listeners: new Set(source.listeners(event)) })
|
|
279
|
+
);
|
|
280
|
+
try {
|
|
281
|
+
return await createServer({
|
|
282
|
+
root: framework.rootDirectory,
|
|
283
|
+
configFile: framework.viteConfig,
|
|
284
|
+
server: { middlewareMode: true, ws: { server, path: HMR_PATH } },
|
|
285
|
+
appType: "custom"
|
|
286
|
+
});
|
|
287
|
+
} finally {
|
|
288
|
+
for (const { source, event, listeners } of snapshots) {
|
|
289
|
+
for (const listener of source.listeners(event)) {
|
|
290
|
+
if (!listeners.has(listener)) source.removeListener(event, listener);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async function mountFrontend(frontend, { projectRoot, webapp, vite }) {
|
|
296
|
+
let build;
|
|
297
|
+
if (vite) {
|
|
298
|
+
const { isRunnableDevEnvironment } = await import("vite");
|
|
299
|
+
const environment = vite.environments.ssr;
|
|
300
|
+
if (!isRunnableDevEnvironment(environment)) throw new Error("React Router \u5F00\u53D1\u73AF\u5883\u672A\u5C31\u7EEA");
|
|
301
|
+
frontend.use(vite.middlewares);
|
|
302
|
+
build = async () => environment.runner.import("virtual:react-router/server-build");
|
|
303
|
+
} else {
|
|
304
|
+
const directory = getBuildDirectory(projectRoot, webapp);
|
|
305
|
+
const basename = webapp.basename || "/";
|
|
306
|
+
frontend.use(path3.posix.join(basename, "assets"), express.static(path3.join(directory, "client/assets"), { immutable: true, maxAge: "1y", fallthrough: false }));
|
|
307
|
+
frontend.use(basename, express.static(path3.join(directory, "client")));
|
|
308
|
+
if (webapp.renderMode === "client") {
|
|
309
|
+
frontend.get(
|
|
310
|
+
path3.posix.join(basename, "{*path}"),
|
|
311
|
+
/** SPA 深链接始终返回构建后的首页。 */
|
|
312
|
+
(_request, response) => response.sendFile(path3.join(directory, "client/index.html"))
|
|
313
|
+
);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
build = await import(pathToFileURL(path3.join(directory, "server/index.js")).href);
|
|
317
|
+
}
|
|
318
|
+
const { createRequestHandler } = await import("@react-router/express");
|
|
319
|
+
frontend.use(createRequestHandler({ build, mode: vite ? "development" : "production" }));
|
|
320
|
+
}
|
|
321
|
+
async function disposeApplication(application, { vite, upgrades }) {
|
|
322
|
+
const server = application?.server instanceof Server ? application.server : void 0;
|
|
323
|
+
const forced = setTimeout(
|
|
324
|
+
/** 生产关闭时中断超过等待上限的普通 HTTP 请求。 */
|
|
325
|
+
() => server?.closeAllConnections(),
|
|
326
|
+
SHUTDOWN_TIMEOUT
|
|
327
|
+
);
|
|
328
|
+
forced.unref();
|
|
329
|
+
try {
|
|
330
|
+
const drained = server?.listening ? server[Symbol.asyncDispose]() : void 0;
|
|
331
|
+
for (const socket of upgrades) socket.destroy();
|
|
332
|
+
const results = await Promise.allSettled([drained, vite?.close()]);
|
|
333
|
+
await application?.close?.();
|
|
334
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
335
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
336
|
+
} finally {
|
|
337
|
+
clearTimeout(forced);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export {
|
|
341
|
+
buildNode,
|
|
342
|
+
runNode
|
|
343
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/react-router-config.ts
|
|
31
|
+
var react_router_config_exports = {};
|
|
32
|
+
__export(react_router_config_exports, {
|
|
33
|
+
default: () => react_router_config_default
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(react_router_config_exports);
|
|
36
|
+
|
|
37
|
+
// src/config.ts
|
|
38
|
+
var import_node_fs = __toESM(require("fs"));
|
|
39
|
+
var import_node_path = __toESM(require("path"));
|
|
40
|
+
var import_node_url = require("url");
|
|
41
|
+
var import_yaml = __toESM(require("yaml"));
|
|
42
|
+
var import_meta = {};
|
|
43
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
44
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
45
|
+
var configDirectory = typeof __dirname === "string" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
46
|
+
var loadXfeConfig = (root = process.cwd()) => {
|
|
47
|
+
const xfeConfigPath = import_node_path.default.join(root, "xfe.json");
|
|
48
|
+
if (!import_node_fs.default.existsSync(xfeConfigPath)) {
|
|
49
|
+
throw new Error("xfe.json \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u521B\u5EFA\u8BE5\u6587\u4EF6\u3002");
|
|
50
|
+
}
|
|
51
|
+
const xfeConfigContent = import_node_fs.default.readFileSync(xfeConfigPath, "utf8");
|
|
52
|
+
const config = JSON.parse(xfeConfigContent);
|
|
53
|
+
const renderMode = config.webapp?.renderMode;
|
|
54
|
+
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
55
|
+
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
56
|
+
}
|
|
57
|
+
getBuildDirectory(root, config.webapp);
|
|
58
|
+
getServerEntry(root, config.webapp);
|
|
59
|
+
return config;
|
|
60
|
+
};
|
|
61
|
+
var getBuildDirectory = (projectRoot2, webapp2 = {}) => {
|
|
62
|
+
const configured = webapp2?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp2.buildDirectory;
|
|
63
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
64
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
65
|
+
}
|
|
66
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
67
|
+
const root = import_node_path.default.resolve(projectRoot2);
|
|
68
|
+
const output = import_node_path.default.resolve(root, directory);
|
|
69
|
+
const relative = import_node_path.default.relative(root, output);
|
|
70
|
+
const [firstDirectory = ""] = relative.split(import_node_path.default.sep);
|
|
71
|
+
const escapesProject = import_node_path.default.isAbsolute(directory) || Boolean(import_node_path.default.win32.parse(directory).root) || firstDirectory === "..";
|
|
72
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
73
|
+
if (escapesProject || overwritesInput) {
|
|
74
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u9879\u76EE\u5185\u72EC\u7ACB\u7684\u8F93\u51FA\u76EE\u5F55\uFF0C\u4E0D\u80FD\u8986\u76D6\u9879\u76EE\u3001\u6E90\u7801\u6216\u4F9D\u8D56");
|
|
75
|
+
}
|
|
76
|
+
let currentDirectory = root;
|
|
77
|
+
for (const segment of relative.split(import_node_path.default.sep)) {
|
|
78
|
+
currentDirectory = import_node_path.default.join(currentDirectory, segment);
|
|
79
|
+
if (import_node_fs.default.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
80
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return output;
|
|
84
|
+
};
|
|
85
|
+
var getServerEntry = (projectRoot2, webapp2 = {}) => {
|
|
86
|
+
const entry = webapp2?.serverEntry;
|
|
87
|
+
if (entry === void 0) return;
|
|
88
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
89
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
90
|
+
}
|
|
91
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
92
|
+
const absolute = import_node_path.default.resolve(projectRoot2, normalized);
|
|
93
|
+
const relative = import_node_path.default.relative(import_node_path.default.resolve(projectRoot2), absolute);
|
|
94
|
+
const outside = Boolean(import_node_path.default.win32.parse(normalized).root) || relative.split(import_node_path.default.sep)[0] === "..";
|
|
95
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
96
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
97
|
+
}
|
|
98
|
+
return absolute;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/react-router-config.ts
|
|
102
|
+
var projectRoot = process.env.XFE_WEB_ROOT;
|
|
103
|
+
if (!projectRoot) throw new Error("\u7F3A\u5C11 XFE_WEB_ROOT\uFF0CReact Router \u5FC5\u987B\u901A\u8FC7 xfe-web \u542F\u52A8");
|
|
104
|
+
var { webapp = {} } = loadXfeConfig(projectRoot);
|
|
105
|
+
var react_router_config_default = {
|
|
106
|
+
appDirectory: "app",
|
|
107
|
+
basename: webapp.basename || "/",
|
|
108
|
+
buildDirectory: getBuildDirectory(projectRoot, webapp),
|
|
109
|
+
future: { unstable_optimizeDeps: true },
|
|
110
|
+
ssr: webapp.renderMode !== "client"
|
|
111
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import yaml from "yaml";
|
|
6
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
7
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
8
|
+
var configDirectory = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
var loadXfeConfig = (root = process.cwd()) => {
|
|
10
|
+
const xfeConfigPath = path.join(root, "xfe.json");
|
|
11
|
+
if (!fs.existsSync(xfeConfigPath)) {
|
|
12
|
+
throw new Error("xfe.json \u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u521B\u5EFA\u8BE5\u6587\u4EF6\u3002");
|
|
13
|
+
}
|
|
14
|
+
const xfeConfigContent = fs.readFileSync(xfeConfigPath, "utf8");
|
|
15
|
+
const config = JSON.parse(xfeConfigContent);
|
|
16
|
+
const renderMode = config.webapp?.renderMode;
|
|
17
|
+
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
18
|
+
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
19
|
+
}
|
|
20
|
+
getBuildDirectory(root, config.webapp);
|
|
21
|
+
getServerEntry(root, config.webapp);
|
|
22
|
+
return config;
|
|
23
|
+
};
|
|
24
|
+
var getBuildDirectory = (projectRoot2, webapp2 = {}) => {
|
|
25
|
+
const configured = webapp2?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp2.buildDirectory;
|
|
26
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
27
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
28
|
+
}
|
|
29
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
30
|
+
const root = path.resolve(projectRoot2);
|
|
31
|
+
const output = path.resolve(root, directory);
|
|
32
|
+
const relative = path.relative(root, output);
|
|
33
|
+
const [firstDirectory = ""] = relative.split(path.sep);
|
|
34
|
+
const escapesProject = path.isAbsolute(directory) || Boolean(path.win32.parse(directory).root) || firstDirectory === "..";
|
|
35
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
36
|
+
if (escapesProject || overwritesInput) {
|
|
37
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u9879\u76EE\u5185\u72EC\u7ACB\u7684\u8F93\u51FA\u76EE\u5F55\uFF0C\u4E0D\u80FD\u8986\u76D6\u9879\u76EE\u3001\u6E90\u7801\u6216\u4F9D\u8D56");
|
|
38
|
+
}
|
|
39
|
+
let currentDirectory = root;
|
|
40
|
+
for (const segment of relative.split(path.sep)) {
|
|
41
|
+
currentDirectory = path.join(currentDirectory, segment);
|
|
42
|
+
if (fs.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
43
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return output;
|
|
47
|
+
};
|
|
48
|
+
var getServerEntry = (projectRoot2, webapp2 = {}) => {
|
|
49
|
+
const entry = webapp2?.serverEntry;
|
|
50
|
+
if (entry === void 0) return;
|
|
51
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
52
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
53
|
+
}
|
|
54
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
55
|
+
const absolute = path.resolve(projectRoot2, normalized);
|
|
56
|
+
const relative = path.relative(path.resolve(projectRoot2), absolute);
|
|
57
|
+
const outside = Boolean(path.win32.parse(normalized).root) || relative.split(path.sep)[0] === "..";
|
|
58
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
59
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
60
|
+
}
|
|
61
|
+
return absolute;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/react-router-config.ts
|
|
65
|
+
var projectRoot = process.env.XFE_WEB_ROOT;
|
|
66
|
+
if (!projectRoot) throw new Error("\u7F3A\u5C11 XFE_WEB_ROOT\uFF0CReact Router \u5FC5\u987B\u901A\u8FC7 xfe-web \u542F\u52A8");
|
|
67
|
+
var { webapp = {} } = loadXfeConfig(projectRoot);
|
|
68
|
+
var react_router_config_default = {
|
|
69
|
+
appDirectory: "app",
|
|
70
|
+
basename: webapp.basename || "/",
|
|
71
|
+
buildDirectory: getBuildDirectory(projectRoot, webapp),
|
|
72
|
+
future: { unstable_optimizeDeps: true },
|
|
73
|
+
ssr: webapp.renderMode !== "client"
|
|
74
|
+
};
|
|
75
|
+
export {
|
|
76
|
+
react_router_config_default as default
|
|
77
|
+
};
|
package/dist/root.d.mts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { PropsWithChildren, ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
declare function PageLoading(): react.JSX.Element;
|
|
5
|
+
declare function Document({ children, lang, themeColor }: PropsWithChildren<{
|
|
6
|
+
lang?: string;
|
|
7
|
+
themeColor?: string;
|
|
8
|
+
}>): react.JSX.Element;
|
|
9
|
+
declare function PageError({ view }: {
|
|
10
|
+
view?: ComponentType<{
|
|
11
|
+
error: unknown;
|
|
12
|
+
}>;
|
|
13
|
+
}): react.ReactElement<{
|
|
14
|
+
error: unknown;
|
|
15
|
+
}, string | react.JSXElementConstructor<any>> | react.FunctionComponentElement<{}>;
|
|
16
|
+
|
|
17
|
+
export { Document, PageError, PageLoading };
|
package/dist/root.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { PropsWithChildren, ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
declare function PageLoading(): react.JSX.Element;
|
|
5
|
+
declare function Document({ children, lang, themeColor }: PropsWithChildren<{
|
|
6
|
+
lang?: string;
|
|
7
|
+
themeColor?: string;
|
|
8
|
+
}>): react.JSX.Element;
|
|
9
|
+
declare function PageError({ view }: {
|
|
10
|
+
view?: ComponentType<{
|
|
11
|
+
error: unknown;
|
|
12
|
+
}>;
|
|
13
|
+
}): react.ReactElement<{
|
|
14
|
+
error: unknown;
|
|
15
|
+
}, string | react.JSXElementConstructor<any>> | react.FunctionComponentElement<{}>;
|
|
16
|
+
|
|
17
|
+
export { Document, PageError, PageLoading };
|
package/dist/root.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/root.tsx
|
|
21
|
+
var root_exports = {};
|
|
22
|
+
__export(root_exports, {
|
|
23
|
+
Document: () => Document,
|
|
24
|
+
PageError: () => PageError,
|
|
25
|
+
PageLoading: () => PageLoading
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(root_exports);
|
|
28
|
+
var import_react = require("react");
|
|
29
|
+
var import_react_router = require("react-router");
|
|
30
|
+
var import_errors = require("@xfe-repo/web-router/errors");
|
|
31
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
32
|
+
function PageLoading() {
|
|
33
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", { role: "status", "aria-live": "polite", children: "\u6B63\u5728\u52A0\u8F7D\u9875\u9762\u2026" });
|
|
34
|
+
}
|
|
35
|
+
function Document({ children, lang = "zh-CN", themeColor }) {
|
|
36
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("html", { lang, children: [
|
|
37
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("head", { children: [
|
|
38
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("meta", { charSet: "utf-8" }),
|
|
39
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
40
|
+
themeColor && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("meta", { name: "theme-color", content: themeColor }),
|
|
41
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router.Meta, {}),
|
|
42
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router.Links, {})
|
|
43
|
+
] }),
|
|
44
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("body", { children: [
|
|
45
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("noscript", { children: "\u8BF7\u5141\u8BB8 JavaScript \u8FD0\u884C\u3002" }),
|
|
46
|
+
children,
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router.ScrollRestoration, {}),
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_router.Scripts, {})
|
|
49
|
+
] })
|
|
50
|
+
] });
|
|
51
|
+
}
|
|
52
|
+
function PageError({ view }) {
|
|
53
|
+
const error = (0, import_react_router.useRouteError)();
|
|
54
|
+
return view ? (0, import_react.createElement)(view, { error }) : (0, import_react.createElement)(import_errors.DefaultErrorBoundary);
|
|
55
|
+
}
|
|
56
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
57
|
+
0 && (module.exports = {
|
|
58
|
+
Document,
|
|
59
|
+
PageError,
|
|
60
|
+
PageLoading
|
|
61
|
+
});
|