@xfe-repo/web-app 2.0.0-beta.1 → 2.0.0-beta.3
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 +60 -2
- package/deploy/.drone.yml +7 -0
- package/deploy/Dockerfile +3 -2
- package/dist/cli.js +486 -187
- package/dist/cli.mjs +475 -175
- package/dist/config.d.mts +11 -1
- package/dist/config.d.ts +11 -1
- package/dist/config.js +68 -10
- package/dist/config.mjs +59 -4
- package/dist/framework.js +88 -44
- package/dist/framework.mjs +47 -3
- package/dist/node-dev.d.mts +2 -0
- package/dist/node-dev.d.ts +2 -0
- package/dist/node-dev.js +356 -0
- package/dist/node-dev.mjs +331 -0
- package/dist/node.d.mts +27 -0
- package/dist/node.d.ts +27 -0
- package/dist/node.js +379 -0
- package/dist/node.mjs +342 -0
- package/dist/react-router-config.js +50 -7
- package/dist/react-router-config.mjs +46 -5
- package/dist/vite.d.mts +1 -0
- package/dist/vite.d.ts +1 -0
- package/dist/vite.js +55 -10
- package/dist/vite.mjs +46 -1
- package/package.json +6 -2
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,13 @@ 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 __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
8
15
|
var __copyProps = (to, from, except, desc) => {
|
|
9
16
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
17
|
for (let key of __getOwnPropNames(from))
|
|
@@ -22,105 +29,165 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
29
|
mod
|
|
23
30
|
));
|
|
24
31
|
|
|
25
|
-
// src/cli.ts
|
|
26
|
-
var import_node_child_process = require("child_process");
|
|
27
|
-
var import_node_fs3 = require("fs");
|
|
28
|
-
var import_path2 = __toESM(require("path"));
|
|
29
|
-
|
|
30
32
|
// src/config.ts
|
|
31
|
-
var
|
|
32
|
-
var
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
33
|
+
var import_node_fs, import_node_path, import_node_url, import_yaml, import_meta, DEFAULT_BUILD_DIRECTORY, BUILD_DIRECTORY_ARGUMENT, protectedDirectories, loadXfeConfig, getBuildDirectory, getServerEntry, configDeploy, getJwtEnv;
|
|
34
|
+
var init_config = __esm({
|
|
35
|
+
"src/config.ts"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
import_node_fs = __toESM(require("fs"));
|
|
38
|
+
import_node_path = __toESM(require("path"));
|
|
39
|
+
import_node_url = require("url");
|
|
40
|
+
import_yaml = __toESM(require("yaml"));
|
|
41
|
+
import_meta = {};
|
|
42
|
+
DEFAULT_BUILD_DIRECTORY = "dist";
|
|
43
|
+
BUILD_DIRECTORY_ARGUMENT = "XFE_BUILD_DIRECTORY";
|
|
44
|
+
protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
45
|
+
loadXfeConfig = (root = process.cwd()) => {
|
|
46
|
+
const xfeConfigPath = import_node_path.default.join(root, "xfe.json");
|
|
47
|
+
if (!import_node_fs.default.existsSync(xfeConfigPath)) {
|
|
48
|
+
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");
|
|
49
|
+
}
|
|
50
|
+
const xfeConfigContent = import_node_fs.default.readFileSync(xfeConfigPath, "utf8");
|
|
51
|
+
const config = JSON.parse(xfeConfigContent);
|
|
52
|
+
const renderMode = config.webapp?.renderMode;
|
|
53
|
+
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
54
|
+
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
55
|
+
}
|
|
56
|
+
getBuildDirectory(root, config.webapp);
|
|
57
|
+
getServerEntry(root, config.webapp);
|
|
58
|
+
return config;
|
|
59
|
+
};
|
|
60
|
+
getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
61
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
|
|
62
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
63
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
64
|
+
}
|
|
65
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
66
|
+
const root = import_node_path.default.resolve(projectRoot);
|
|
67
|
+
const output = import_node_path.default.resolve(root, directory);
|
|
68
|
+
const relative = import_node_path.default.relative(root, output);
|
|
69
|
+
const [firstDirectory = ""] = relative.split(import_node_path.default.sep);
|
|
70
|
+
const escapesProject = import_node_path.default.isAbsolute(directory) || Boolean(import_node_path.default.win32.parse(directory).root) || firstDirectory === "..";
|
|
71
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
72
|
+
if (escapesProject || overwritesInput) {
|
|
73
|
+
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");
|
|
74
|
+
}
|
|
75
|
+
let currentDirectory = root;
|
|
76
|
+
for (const segment of relative.split(import_node_path.default.sep)) {
|
|
77
|
+
currentDirectory = import_node_path.default.join(currentDirectory, segment);
|
|
78
|
+
if (import_node_fs.default.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
79
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return output;
|
|
83
|
+
};
|
|
84
|
+
getServerEntry = (projectRoot, webapp = {}) => {
|
|
85
|
+
const entry = webapp?.serverEntry;
|
|
86
|
+
if (entry === void 0) return;
|
|
87
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
88
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
89
|
+
}
|
|
90
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
91
|
+
const absolute = import_node_path.default.resolve(projectRoot, normalized);
|
|
92
|
+
const relative = import_node_path.default.relative(import_node_path.default.resolve(projectRoot), absolute);
|
|
93
|
+
const outside = Boolean(import_node_path.default.win32.parse(normalized).root) || relative.split(import_node_path.default.sep)[0] === "..";
|
|
94
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
95
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
96
|
+
}
|
|
97
|
+
return absolute;
|
|
98
|
+
};
|
|
99
|
+
configDeploy = () => {
|
|
100
|
+
const xfeConfig = loadXfeConfig();
|
|
101
|
+
if (!xfeConfig?.deploy) return;
|
|
102
|
+
const configDirectory = typeof __dirname === "string" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
103
|
+
const projectRoot = process.cwd();
|
|
104
|
+
const buildDirectory = import_node_path.default.relative(projectRoot, getBuildDirectory(projectRoot, xfeConfig.webapp)).replaceAll(import_node_path.default.sep, "/");
|
|
105
|
+
const droneConfigFilePath = import_node_path.default.resolve(configDirectory, "../deploy/.drone.yml");
|
|
106
|
+
const droneTarget = import_node_path.default.resolve(projectRoot, xfeConfig.deploy.droneConfigPath || "./.drone.yml");
|
|
107
|
+
const defaultArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${DEFAULT_BUILD_DIRECTORY}`);
|
|
108
|
+
const configuredArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${buildDirectory}`);
|
|
109
|
+
const droneConfig = import_node_fs.default.readFileSync(droneConfigFilePath, "utf8").replace(defaultArgument, configuredArgument);
|
|
110
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(droneTarget), { recursive: true });
|
|
111
|
+
import_node_fs.default.writeFileSync(droneTarget, droneConfig);
|
|
112
|
+
const valuesYamlFilePath = import_node_path.default.resolve(configDirectory, "../deploy/helm/values.yaml");
|
|
113
|
+
const valuesYamlFile = import_node_fs.default.readFileSync(valuesYamlFilePath, "utf8");
|
|
114
|
+
const valuesYaml = import_yaml.default.parse(valuesYamlFile);
|
|
115
|
+
if (!valuesYaml.virtualService) valuesYaml.virtualService = {};
|
|
116
|
+
if (!valuesYaml.virtualService.hosts) valuesYaml.virtualService.hosts = { test: [], stage: [], prod: [] };
|
|
117
|
+
const {
|
|
118
|
+
virtualServiceEnabled = true,
|
|
119
|
+
hostsProd = [],
|
|
120
|
+
hostsStage = [],
|
|
121
|
+
hostsTest = [],
|
|
122
|
+
gateways = ["common-gateway-eshetang"]
|
|
123
|
+
} = xfeConfig.deploy;
|
|
124
|
+
const { targetK8s = "saas", targetNamespace = "" } = xfeConfig.deploy;
|
|
125
|
+
valuesYaml.virtualService.enabled = virtualServiceEnabled;
|
|
126
|
+
valuesYaml.virtualService.gateways = gateways;
|
|
127
|
+
valuesYaml.virtualService.hosts.prod = hostsProd;
|
|
128
|
+
valuesYaml.virtualService.hosts.stage = hostsStage;
|
|
129
|
+
valuesYaml.virtualService.hosts.test = hostsTest;
|
|
130
|
+
valuesYaml.targetK8s = targetK8s;
|
|
131
|
+
valuesYaml.namespace = targetNamespace;
|
|
132
|
+
const valuesYamlStr = import_yaml.default.stringify(valuesYaml, { defaultStringType: "QUOTE_SINGLE", defaultKeyType: "PLAIN" });
|
|
133
|
+
import_node_fs.default.writeFileSync(valuesYamlFilePath, valuesYamlStr, "utf8");
|
|
134
|
+
};
|
|
135
|
+
getJwtEnv = async () => {
|
|
136
|
+
const xfeConfig = loadXfeConfig();
|
|
137
|
+
if (!xfeConfig?.jwt) return {};
|
|
138
|
+
const { aud = "" } = xfeConfig.jwt;
|
|
139
|
+
if (!aud) throw new Error("xfe.json \u4E2D\u7684 jwt \u914D\u7F6E\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u786E\u4FDD\u5305\u542B aud \u5B57\u6BB5\u3002");
|
|
140
|
+
const jwkRes = await fetch(`https://app.eshetang.com/jwk?appId=${aud}`);
|
|
141
|
+
if (!jwkRes.ok) {
|
|
142
|
+
throw new Error(`\u8FDC\u7A0B\u83B7\u53D6\u5BC6\u94A5\u5931\u8D25: ${jwkRes.status} ${jwkRes.statusText}`);
|
|
143
|
+
}
|
|
144
|
+
let JwkResponseJson;
|
|
145
|
+
try {
|
|
146
|
+
JwkResponseJson = await jwkRes.json();
|
|
147
|
+
} catch (err) {
|
|
148
|
+
throw new Error(`\u8FDC\u7A0B\u83B7\u53D6\u5BC6\u94A5\u5931\u8D25\uFF0C\u54CD\u5E94\u89E3\u6790\u9519\u8BEF: ${err.message}, response text: ${await jwkRes.text()}`);
|
|
149
|
+
}
|
|
150
|
+
const { keyId, privateKeyPkcs8 } = JwkResponseJson?.data || {};
|
|
151
|
+
if (!keyId || !privateKeyPkcs8) throw new Error(`\u672A\u83B7\u53D6\u5230\u9879\u76EE\u7B7E\u540D\u5BC6\u94A5, \u8BF7\u68C0\u67E5aud\u662F\u5426\u6B63\u786E: ${aud}`);
|
|
152
|
+
return { XFE_JWT_AUD: aud, XFE_JWT_KEY_ID: keyId, XFE_JWT_PRIVATE_KEY: privateKeyPkcs8 };
|
|
153
|
+
};
|
|
83
154
|
}
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
JwkResponseJson = await jwkRes.json();
|
|
87
|
-
} catch (err) {
|
|
88
|
-
throw new Error(`\u8FDC\u7A0B\u83B7\u53D6\u5BC6\u94A5\u5931\u8D25\uFF0C\u54CD\u5E94\u89E3\u6790\u9519\u8BEF: ${err.message}, response text: ${await jwkRes.text()}`);
|
|
89
|
-
}
|
|
90
|
-
const { keyId, privateKeyPkcs8 } = JwkResponseJson?.data || {};
|
|
91
|
-
if (!keyId || !privateKeyPkcs8) throw new Error(`\u672A\u83B7\u53D6\u5230\u9879\u76EE\u7B7E\u540D\u5BC6\u94A5, \u8BF7\u68C0\u67E5aud\u662F\u5426\u6B63\u786E: ${aud}`);
|
|
92
|
-
return { XFE_JWT_AUD: aud, XFE_JWT_KEY_ID: keyId, XFE_JWT_PRIVATE_KEY: privateKeyPkcs8 };
|
|
93
|
-
};
|
|
155
|
+
});
|
|
94
156
|
|
|
95
157
|
// src/framework.ts
|
|
96
|
-
var
|
|
97
|
-
var
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
158
|
+
var import_node_fs2, import_node_module, import_node_path2, import_node_url2, import_meta2, frameworkDirectory, requireFromFramework, extensions, findSource, findValueExports, importPath, writeGenerated, defaultRootSource, getFrameworkRoot, prepareFramework;
|
|
159
|
+
var init_framework = __esm({
|
|
160
|
+
"src/framework.ts"() {
|
|
161
|
+
"use strict";
|
|
162
|
+
import_node_fs2 = __toESM(require("fs"));
|
|
163
|
+
import_node_module = require("module");
|
|
164
|
+
import_node_path2 = __toESM(require("path"));
|
|
165
|
+
import_node_url2 = require("url");
|
|
166
|
+
init_config();
|
|
167
|
+
import_meta2 = {};
|
|
168
|
+
frameworkDirectory = typeof __dirname === "string" ? __dirname : import_node_path2.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
169
|
+
requireFromFramework = (0, import_node_module.createRequire)(import_node_path2.default.join(frameworkDirectory, "framework.js"));
|
|
170
|
+
extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
171
|
+
findSource = (directory, name) => extensions.map((extension) => import_node_path2.default.join(directory, `${name}${extension}`)).find(import_node_fs2.default.existsSync);
|
|
172
|
+
findValueExports = (file) => [...import_node_fs2.default.readFileSync(file, "utf8").matchAll(/^\s*export\s+(?:async\s+)?(?:const|let|var|function|class)\s+([A-Za-z_$][\w$]*)/gm)].map(
|
|
173
|
+
([, name]) => name
|
|
174
|
+
);
|
|
175
|
+
importPath = (from, target) => {
|
|
176
|
+
const relative = import_node_path2.default.relative(from, target).replace(import_node_path2.default.extname(target), "").replaceAll(import_node_path2.default.sep, "/");
|
|
177
|
+
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
178
|
+
};
|
|
179
|
+
writeGenerated = (file, content) => {
|
|
180
|
+
if (import_node_fs2.default.existsSync(file) && import_node_fs2.default.readFileSync(file, "utf8") === content) return;
|
|
181
|
+
import_node_fs2.default.writeFileSync(file, content);
|
|
182
|
+
};
|
|
183
|
+
defaultRootSource = (projectRoot, appDirectory) => {
|
|
184
|
+
const { webapp = {} } = loadXfeConfig(projectRoot);
|
|
185
|
+
const layoutSource = findSource(import_node_path2.default.join(projectRoot, "src"), "layout");
|
|
186
|
+
const layoutExports = layoutSource ? findValueExports(layoutSource) : [];
|
|
187
|
+
const hasErrorView = layoutExports.includes("ErrorView");
|
|
188
|
+
const layoutImport = layoutSource ? `import AppLayout${hasErrorView ? ", { ErrorView }" : ""} from ${JSON.stringify(importPath(appDirectory, layoutSource))}
|
|
122
189
|
` : "";
|
|
123
|
-
|
|
190
|
+
return `import { createElement, type ReactNode } from 'react'
|
|
124
191
|
import { Outlet } from 'react-router'
|
|
125
192
|
import { Document, PageError, PageLoading } from '@xfe-repo/web-app/dist/root.mjs'
|
|
126
193
|
${layoutImport}
|
|
@@ -130,86 +197,270 @@ export default function Root() { return ${layoutSource ? "createElement(AppLayou
|
|
|
130
197
|
export function ErrorBoundary() { return createElement(PageError, { ${hasErrorView ? "view: ErrorView" : ""} }) }
|
|
131
198
|
export function HydrateFallback() { return createElement(PageLoading) }
|
|
132
199
|
`;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
200
|
+
};
|
|
201
|
+
getFrameworkRoot = (projectRoot) => import_node_path2.default.join(projectRoot, "node_modules/.cache/xfe-web/react-router");
|
|
202
|
+
prepareFramework = (projectRoot = process.cwd()) => {
|
|
203
|
+
const sourceDirectory = import_node_path2.default.join(projectRoot, "src");
|
|
204
|
+
const rootSource = findSource(sourceDirectory, "root");
|
|
205
|
+
const appServerSource = findSource(sourceDirectory, "app.server");
|
|
206
|
+
const pagesSource = import_node_path2.default.join(sourceDirectory, "pages");
|
|
207
|
+
if (!import_node_fs2.default.existsSync(pagesSource)) throw new Error("\u672A\u627E\u5230 src/pages");
|
|
208
|
+
const rootDirectory = getFrameworkRoot(projectRoot);
|
|
209
|
+
const appDirectory = import_node_path2.default.join(rootDirectory, "app");
|
|
210
|
+
import_node_fs2.default.mkdirSync(appDirectory, { recursive: true });
|
|
211
|
+
const routerDirectory = import_node_path2.default.dirname(requireFromFramework.resolve("react-router/package.json"));
|
|
212
|
+
const routerLink = import_node_path2.default.join(rootDirectory, "node_modules/react-router");
|
|
213
|
+
import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(routerLink), { recursive: true });
|
|
214
|
+
if (!import_node_fs2.default.lstatSync(routerLink, { throwIfNoEntry: false })?.isSymbolicLink() || import_node_fs2.default.readlinkSync(routerLink) !== routerDirectory) {
|
|
215
|
+
import_node_fs2.default.rmSync(routerLink, { force: true });
|
|
216
|
+
import_node_fs2.default.symlinkSync(routerDirectory, routerLink, "junction");
|
|
217
|
+
}
|
|
218
|
+
const rootTarget = import_node_path2.default.join(appDirectory, "root.tsx");
|
|
219
|
+
const rootImport = rootSource ? importPath(appDirectory, rootSource) : "";
|
|
220
|
+
const rootExports = rootSource ? findValueExports(rootSource).filter((name) => name !== "middleware" || !appServerSource) : [];
|
|
221
|
+
const namedExports = rootExports.length ? `export { ${rootExports.join(", ")} } from ${JSON.stringify(rootImport)}
|
|
155
222
|
` : "";
|
|
156
|
-
|
|
157
|
-
|
|
223
|
+
const errorBoundaryExport = rootExports.includes("ErrorBoundary") ? "" : "export { DefaultErrorBoundary as ErrorBoundary } from '@xfe-repo/web-router/errors'\n";
|
|
224
|
+
const middlewareExport = appServerSource ? `export { middleware } from ${JSON.stringify(importPath(appDirectory, appServerSource))}
|
|
158
225
|
` : "";
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
226
|
+
writeGenerated(
|
|
227
|
+
rootTarget,
|
|
228
|
+
rootSource ? `export * from ${JSON.stringify(rootImport)}
|
|
162
229
|
export { default } from ${JSON.stringify(rootImport)}
|
|
163
230
|
${namedExports}${errorBoundaryExport}${middlewareExport}` : `${defaultRootSource(projectRoot, appDirectory)}${middlewareExport}`
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
231
|
+
);
|
|
232
|
+
const pagesLink = import_node_path2.default.join(appDirectory, "pages");
|
|
233
|
+
if (!import_node_fs2.default.existsSync(pagesLink)) import_node_fs2.default.symlinkSync(import_node_path2.default.relative(appDirectory, pagesSource), pagesLink, "dir");
|
|
234
|
+
writeGenerated(
|
|
235
|
+
import_node_path2.default.join(rootDirectory, "react-router.config.js"),
|
|
236
|
+
"export { default } from '@xfe-repo/web-app/dist/react-router-config.mjs'\n"
|
|
237
|
+
);
|
|
238
|
+
writeGenerated(
|
|
239
|
+
import_node_path2.default.join(appDirectory, "routes.js"),
|
|
240
|
+
`import { collectPageRoutes } from '@xfe-repo/web-router/routes'
|
|
174
241
|
export default collectPageRoutes(${JSON.stringify(appDirectory)})
|
|
175
242
|
`
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
243
|
+
);
|
|
244
|
+
const defaultsDirectory = import_node_path2.default.join(import_node_path2.default.dirname(requireFromFramework.resolve("@react-router/dev/package.json")), "dist/config/defaults");
|
|
245
|
+
writeGenerated(
|
|
246
|
+
import_node_path2.default.join(appDirectory, "entry.server.tsx"),
|
|
247
|
+
`export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory, import_node_path2.default.join(defaultsDirectory, "entry.server.web.tsx")))}
|
|
181
248
|
`
|
|
249
|
+
);
|
|
250
|
+
const typeScriptConfig = import_node_path2.default.join(rootDirectory, "tsconfig.json");
|
|
251
|
+
writeGenerated(
|
|
252
|
+
typeScriptConfig,
|
|
253
|
+
JSON.stringify(
|
|
254
|
+
{
|
|
255
|
+
extends: import_node_path2.default.join(projectRoot, "tsconfig.json"),
|
|
256
|
+
compilerOptions: { rootDirs: [projectRoot, rootDirectory, import_node_path2.default.join(rootDirectory, ".react-router/types")] },
|
|
257
|
+
include: [
|
|
258
|
+
import_node_path2.default.join(sourceDirectory, "**/*"),
|
|
259
|
+
import_node_path2.default.join(projectRoot, "types/**/*"),
|
|
260
|
+
import_node_path2.default.join(appDirectory, "*.tsx"),
|
|
261
|
+
import_node_path2.default.join(rootDirectory, ".react-router/types/**/*")
|
|
262
|
+
],
|
|
263
|
+
exclude: []
|
|
264
|
+
},
|
|
265
|
+
null,
|
|
266
|
+
2
|
|
267
|
+
)
|
|
268
|
+
);
|
|
269
|
+
return {
|
|
270
|
+
appDirectory,
|
|
271
|
+
rootDirectory,
|
|
272
|
+
viteConfig: import_node_path2.default.resolve(frameworkDirectory, "vite.mjs"),
|
|
273
|
+
typeScriptConfig
|
|
274
|
+
};
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// src/node.ts
|
|
280
|
+
var node_exports = {};
|
|
281
|
+
__export(node_exports, {
|
|
282
|
+
buildNode: () => buildNode,
|
|
283
|
+
runNode: () => runNode
|
|
284
|
+
});
|
|
285
|
+
async function buildNode({ projectRoot, webapp }) {
|
|
286
|
+
const { build } = await import("esbuild");
|
|
287
|
+
const entry = getServerEntry(projectRoot, webapp);
|
|
288
|
+
if (!entry) throw new Error("\u7F3A\u5C11 xfe.json.webapp.serverEntry");
|
|
289
|
+
if (webapp.renderMode === "client") await (0, import_promises.rm)(import_node_path4.default.join(getBuildDirectory(projectRoot, webapp), "server"), { recursive: true, force: true });
|
|
290
|
+
await build({
|
|
291
|
+
absWorkingDir: projectRoot,
|
|
292
|
+
entryPoints: [entry],
|
|
293
|
+
outfile: import_node_path4.default.join(getBuildDirectory(projectRoot, webapp), NODE_OUTPUT),
|
|
294
|
+
tsconfig: import_node_path4.default.join(projectRoot, "tsconfig.json"),
|
|
295
|
+
bundle: true,
|
|
296
|
+
packages: "external",
|
|
297
|
+
platform: "node",
|
|
298
|
+
format: "esm",
|
|
299
|
+
target: "node22.22",
|
|
300
|
+
sourcemap: true
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async function runNode({ projectRoot, webapp, development }) {
|
|
304
|
+
const entry = development ? getServerEntry(projectRoot, webapp) : import_node_path4.default.join(getBuildDirectory(projectRoot, webapp), NODE_OUTPUT);
|
|
305
|
+
if (!entry) throw new Error("\u7F3A\u5C11 xfe.json.webapp.serverEntry");
|
|
306
|
+
if (development) {
|
|
307
|
+
const { loadEnv } = await import("vite");
|
|
308
|
+
Object.assign(process.env, { ...loadEnv("development", projectRoot, ""), ...process.env });
|
|
309
|
+
} else process.env.NODE_ENV ??= "production";
|
|
310
|
+
const module2 = await import((0, import_node_url3.pathToFileURL)(entry).href);
|
|
311
|
+
if (typeof module2.default !== "function") throw new Error("serverEntry \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA Node \u670D\u52A1\u5DE5\u5382\u51FD\u6570");
|
|
312
|
+
const frontend = (0, import_express2.default)().disable("x-powered-by");
|
|
313
|
+
const application = await module2.default({ frontend, mode: development ? "development" : "production" });
|
|
314
|
+
const upgrades = /* @__PURE__ */ new Set();
|
|
315
|
+
let vite;
|
|
316
|
+
let closing;
|
|
317
|
+
const close = () => closing ??= disposeApplication(application, { vite, upgrades });
|
|
318
|
+
const onSignal = async () => {
|
|
319
|
+
try {
|
|
320
|
+
await close();
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error("XFE Node \u5173\u95ED\u5931\u8D25:", error);
|
|
323
|
+
process.exit(1);
|
|
324
|
+
} finally {
|
|
325
|
+
process.off("SIGINT", onSignal);
|
|
326
|
+
process.off("SIGTERM", onSignal);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
try {
|
|
330
|
+
const server = application?.server;
|
|
331
|
+
if (!(server instanceof import_node_http.Server) || server.listening) throw new Error("Node \u5DE5\u5382\u5FC5\u987B\u8FD4\u56DE\u5C1A\u672A listen \u7684 http.Server");
|
|
332
|
+
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");
|
|
333
|
+
const hmrPath = import_node_path4.default.posix.join(webapp.basename || "/", HMR_PATH);
|
|
334
|
+
server.on(
|
|
335
|
+
"upgrade",
|
|
336
|
+
/** HMR 与业务互斥分流,升级连接由关闭流程统一回收。 */
|
|
337
|
+
(request, socket, head) => {
|
|
338
|
+
upgrades.add(socket);
|
|
339
|
+
socket.once(
|
|
340
|
+
"close",
|
|
341
|
+
/** 不保留已经断开的升级连接。 */
|
|
342
|
+
() => upgrades.delete(socket)
|
|
343
|
+
);
|
|
344
|
+
if (development && request.url?.split("?")[0] === hmrPath) {
|
|
345
|
+
if (!["vite-hmr", "vite-ping"].includes(String(request.headers["sec-websocket-protocol"]))) socket.destroy();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (application.upgrade) application.upgrade(request, socket, head);
|
|
349
|
+
else socket.destroy();
|
|
350
|
+
}
|
|
351
|
+
);
|
|
352
|
+
if (development) vite = await createDevelopmentServer(server, projectRoot);
|
|
353
|
+
await mountFrontend(frontend, { projectRoot, webapp, vite });
|
|
354
|
+
const listening = (0, import_node_events.once)(server, "listening");
|
|
355
|
+
const host = process.env.HOST || webapp.host || "0.0.0.0";
|
|
356
|
+
const port = Number(process.env.PORT ?? webapp.port ?? 3e3);
|
|
357
|
+
server.listen(port, host);
|
|
358
|
+
await listening;
|
|
359
|
+
console.info(`XFE Node: http://${host}:${port}`);
|
|
360
|
+
process.on("SIGINT", onSignal);
|
|
361
|
+
process.on("SIGTERM", onSignal);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
await close();
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function createDevelopmentServer(server, projectRoot) {
|
|
368
|
+
const { createServer } = await import("vite");
|
|
369
|
+
const framework = prepareFramework(projectRoot);
|
|
370
|
+
const events = [[process, "SIGINT"], [process, "SIGTERM"], [process.stdin, "end"]];
|
|
371
|
+
const snapshots = events.map(
|
|
372
|
+
/** 只记录当前监听,恢复时保留宿主和业务原有的处理器。 */
|
|
373
|
+
([source, event]) => ({ source, event, listeners: new Set(source.listeners(event)) })
|
|
182
374
|
);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
375
|
+
try {
|
|
376
|
+
return await createServer({
|
|
377
|
+
root: framework.rootDirectory,
|
|
378
|
+
configFile: framework.viteConfig,
|
|
379
|
+
server: { middlewareMode: true, ws: { server, path: HMR_PATH } },
|
|
380
|
+
appType: "custom"
|
|
381
|
+
});
|
|
382
|
+
} finally {
|
|
383
|
+
for (const { source, event, listeners } of snapshots) {
|
|
384
|
+
for (const listener of source.listeners(event)) {
|
|
385
|
+
if (!listeners.has(listener)) source.removeListener(event, listener);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
async function mountFrontend(frontend, { projectRoot, webapp, vite }) {
|
|
391
|
+
let build;
|
|
392
|
+
if (vite) {
|
|
393
|
+
const { isRunnableDevEnvironment } = await import("vite");
|
|
394
|
+
const environment = vite.environments.ssr;
|
|
395
|
+
if (!isRunnableDevEnvironment(environment)) throw new Error("React Router \u5F00\u53D1\u73AF\u5883\u672A\u5C31\u7EEA");
|
|
396
|
+
frontend.use(vite.middlewares);
|
|
397
|
+
build = async () => environment.runner.import("virtual:react-router/server-build");
|
|
398
|
+
} else {
|
|
399
|
+
const directory = getBuildDirectory(projectRoot, webapp);
|
|
400
|
+
const basename = webapp.basename || "/";
|
|
401
|
+
frontend.use(import_node_path4.default.posix.join(basename, "assets"), import_express2.default.static(import_node_path4.default.join(directory, "client/assets"), { immutable: true, maxAge: "1y", fallthrough: false }));
|
|
402
|
+
frontend.use(basename, import_express2.default.static(import_node_path4.default.join(directory, "client")));
|
|
403
|
+
if (webapp.renderMode === "client") {
|
|
404
|
+
frontend.get(
|
|
405
|
+
import_node_path4.default.posix.join(basename, "{*path}"),
|
|
406
|
+
/** SPA 深链接始终返回构建后的首页。 */
|
|
407
|
+
(_request, response) => response.sendFile(import_node_path4.default.join(directory, "client/index.html"))
|
|
408
|
+
);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
build = await import((0, import_node_url3.pathToFileURL)(import_node_path4.default.join(directory, "server/index.js")).href);
|
|
412
|
+
}
|
|
413
|
+
const { createRequestHandler } = await import("@react-router/express");
|
|
414
|
+
frontend.use(createRequestHandler({ build, mode: vite ? "development" : "production" }));
|
|
415
|
+
}
|
|
416
|
+
async function disposeApplication(application, { vite, upgrades }) {
|
|
417
|
+
const server = application?.server instanceof import_node_http.Server ? application.server : void 0;
|
|
418
|
+
const forced = setTimeout(
|
|
419
|
+
/** 生产关闭时中断超过等待上限的普通 HTTP 请求。 */
|
|
420
|
+
() => server?.closeAllConnections(),
|
|
421
|
+
SHUTDOWN_TIMEOUT
|
|
201
422
|
);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
423
|
+
forced.unref();
|
|
424
|
+
try {
|
|
425
|
+
const drained = server?.listening ? server[Symbol.asyncDispose]() : void 0;
|
|
426
|
+
for (const socket of upgrades) socket.destroy();
|
|
427
|
+
const results = await Promise.allSettled([drained, vite?.close()]);
|
|
428
|
+
await application?.close?.();
|
|
429
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
430
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
431
|
+
} finally {
|
|
432
|
+
clearTimeout(forced);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
var import_node_events, import_promises, import_node_http, import_node_path4, import_node_url3, import_express2, NODE_OUTPUT, HMR_PATH, SHUTDOWN_TIMEOUT;
|
|
436
|
+
var init_node = __esm({
|
|
437
|
+
"src/node.ts"() {
|
|
438
|
+
"use strict";
|
|
439
|
+
import_node_events = require("events");
|
|
440
|
+
import_promises = require("fs/promises");
|
|
441
|
+
import_node_http = require("http");
|
|
442
|
+
import_node_path4 = __toESM(require("path"));
|
|
443
|
+
import_node_url3 = require("url");
|
|
444
|
+
import_express2 = __toESM(require("express"));
|
|
445
|
+
init_config();
|
|
446
|
+
init_framework();
|
|
447
|
+
NODE_OUTPUT = "server/node.mjs";
|
|
448
|
+
HMR_PATH = "/_xfe/hmr";
|
|
449
|
+
SHUTDOWN_TIMEOUT = 3e4;
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// src/cli.ts
|
|
454
|
+
var import_node_child_process = require("child_process");
|
|
455
|
+
var import_node_events2 = require("events");
|
|
456
|
+
var import_node_fs4 = require("fs");
|
|
457
|
+
var import_path = __toESM(require("path"));
|
|
458
|
+
init_config();
|
|
459
|
+
init_framework();
|
|
209
460
|
|
|
210
461
|
// src/serve.ts
|
|
211
|
-
var
|
|
212
|
-
var
|
|
462
|
+
var import_node_fs3 = require("fs");
|
|
463
|
+
var import_node_path3 = __toESM(require("path"));
|
|
213
464
|
var import_express = __toESM(require("express"));
|
|
214
465
|
var serveClient = ({
|
|
215
466
|
directory,
|
|
@@ -217,8 +468,8 @@ var serveClient = ({
|
|
|
217
468
|
port,
|
|
218
469
|
basename = "/"
|
|
219
470
|
}) => {
|
|
220
|
-
const indexFile =
|
|
221
|
-
if (!(0,
|
|
471
|
+
const indexFile = import_node_path3.default.join(directory, "index.html");
|
|
472
|
+
if (!(0, import_node_fs3.existsSync)(indexFile)) throw new Error(`\u672A\u627E\u5230 SPA \u5165\u53E3 ${indexFile}\uFF0C\u8BF7\u5148\u6267\u884C xfe-web build`);
|
|
222
473
|
const app = (0, import_express.default)().disable("x-powered-by");
|
|
223
474
|
const router = import_express.default.Router();
|
|
224
475
|
app.use((_request, response, next) => {
|
|
@@ -227,7 +478,7 @@ var serveClient = ({
|
|
|
227
478
|
});
|
|
228
479
|
app.use(
|
|
229
480
|
"/assets",
|
|
230
|
-
import_express.default.static(
|
|
481
|
+
import_express.default.static(import_node_path3.default.join(directory, "assets"), { immutable: true, maxAge: "1y" }),
|
|
231
482
|
(_request, response) => response.status(404).end()
|
|
232
483
|
);
|
|
233
484
|
app.use(import_express.default.static(directory));
|
|
@@ -243,33 +494,53 @@ var serveClient = ({
|
|
|
243
494
|
|
|
244
495
|
// src/cli.ts
|
|
245
496
|
var [command, ...args] = process.argv.slice(2);
|
|
246
|
-
var
|
|
247
|
-
var
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
497
|
+
var binaries = { typescript: "lib/tsc.js", tsx: "dist/cli.mjs" };
|
|
498
|
+
var resolveBin = (packageName) => import_path.default.join(import_path.default.dirname(require.resolve(`${packageName}/package.json`)), binaries[packageName] || "bin.cjs");
|
|
499
|
+
async function run(options) {
|
|
500
|
+
const { packageName, args: args2, cwd, env } = options;
|
|
501
|
+
const child = (0, import_node_child_process.spawn)(process.execPath, [resolveBin(packageName), ...args2], { stdio: "inherit", env, cwd });
|
|
502
|
+
let stopping = false;
|
|
503
|
+
const forward = (signal) => {
|
|
504
|
+
if (stopping) return;
|
|
505
|
+
stopping = true;
|
|
506
|
+
child.kill(signal);
|
|
507
|
+
};
|
|
508
|
+
process.on("SIGINT", forward);
|
|
509
|
+
process.on("SIGTERM", forward);
|
|
510
|
+
try {
|
|
511
|
+
const [code] = await (0, import_node_events2.once)(child, "exit");
|
|
512
|
+
if (code !== 0 && !stopping) throw new Error(`${packageName} ${args2[0]} \u5931\u8D25\uFF0C\u9000\u51FA\u7801 ${code ?? 1}`);
|
|
513
|
+
} finally {
|
|
514
|
+
process.off("SIGINT", forward);
|
|
515
|
+
process.off("SIGTERM", forward);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
256
518
|
async function main() {
|
|
257
519
|
const projectRoot = process.cwd();
|
|
258
520
|
if (command === "config") return configDeploy();
|
|
259
521
|
if (command === "start") {
|
|
260
|
-
const { webapp = {} } = loadXfeConfig(projectRoot);
|
|
261
|
-
|
|
522
|
+
const { webapp: webapp2 = {} } = loadXfeConfig(projectRoot);
|
|
523
|
+
const buildDirectory = getBuildDirectory(projectRoot, webapp2);
|
|
524
|
+
if (webapp2.serverEntry) {
|
|
525
|
+
if (args.length) throw new Error("\u81EA\u5B9A\u4E49 Node \u670D\u52A1\u8BF7\u901A\u8FC7 HOST / PORT \u6216 xfe.json \u914D\u7F6E\u542F\u52A8\u5730\u5740");
|
|
526
|
+
Object.assign(process.env, await getJwtEnv());
|
|
527
|
+
const { runNode: runNode2 } = await Promise.resolve().then(() => (init_node(), node_exports));
|
|
528
|
+
return runNode2({ projectRoot, webapp: webapp2 });
|
|
529
|
+
}
|
|
530
|
+
if (webapp2.renderMode === "client") {
|
|
262
531
|
serveClient({
|
|
263
|
-
directory:
|
|
264
|
-
host: process.env.HOST ||
|
|
265
|
-
port: Number(process.env.PORT ??
|
|
266
|
-
basename:
|
|
532
|
+
directory: import_path.default.join(buildDirectory, "client"),
|
|
533
|
+
host: process.env.HOST || webapp2.host || "0.0.0.0",
|
|
534
|
+
port: Number(process.env.PORT ?? webapp2.port ?? 3e3),
|
|
535
|
+
basename: webapp2.basename
|
|
267
536
|
});
|
|
268
537
|
return;
|
|
269
538
|
}
|
|
270
539
|
const rootDirectory = getFrameworkRoot(projectRoot);
|
|
271
|
-
(0,
|
|
272
|
-
return run(
|
|
540
|
+
(0, import_node_fs4.mkdirSync)(rootDirectory, { recursive: true });
|
|
541
|
+
return run({
|
|
542
|
+
packageName: "@react-router/serve",
|
|
543
|
+
args: [import_path.default.join(buildDirectory, "server/index.js"), ...args],
|
|
273
544
|
cwd: rootDirectory,
|
|
274
545
|
env: { ...process.env, ...await getJwtEnv() }
|
|
275
546
|
});
|
|
@@ -281,13 +552,41 @@ async function main() {
|
|
|
281
552
|
const env = { ...process.env, XFE_WEB_ROOT: projectRoot };
|
|
282
553
|
const options = { cwd: framework.rootDirectory, env };
|
|
283
554
|
if (command === "typegen" || command === "typecheck") {
|
|
284
|
-
run("@react-router/dev", ["typegen", ...command === "typegen" ? args : []], options);
|
|
285
|
-
if (command === "typecheck") run("typescript", ["--noEmit", "--project", framework.typeScriptConfig, ...args]);
|
|
555
|
+
await run({ packageName: "@react-router/dev", args: ["typegen", ...command === "typegen" ? args : []], ...options });
|
|
556
|
+
if (command === "typecheck") await run({ packageName: "typescript", args: ["--noEmit", "--project", framework.typeScriptConfig, ...args] });
|
|
286
557
|
return;
|
|
287
558
|
}
|
|
288
559
|
Object.assign(env, await getJwtEnv());
|
|
289
560
|
if (command === "build") delete env.XFE_JWT_PRIVATE_KEY;
|
|
290
|
-
|
|
561
|
+
const { webapp = {} } = loadXfeConfig(projectRoot);
|
|
562
|
+
if (command === "dev" && webapp.serverEntry) {
|
|
563
|
+
if (args.length) throw new Error("\u81EA\u5B9A\u4E49 Node \u670D\u52A1\u8BF7\u901A\u8FC7 HOST / PORT \u6216 xfe.json \u914D\u7F6E\u542F\u52A8\u5730\u5740");
|
|
564
|
+
return run({
|
|
565
|
+
packageName: "tsx",
|
|
566
|
+
args: [
|
|
567
|
+
"watch",
|
|
568
|
+
"--clear-screen=false",
|
|
569
|
+
"--exclude",
|
|
570
|
+
"**/node_modules/**",
|
|
571
|
+
"--exclude",
|
|
572
|
+
import_path.default.resolve(__dirname, "../node_modules/**"),
|
|
573
|
+
"--exclude",
|
|
574
|
+
import_path.default.resolve(__dirname, "../node_modules/.vite-temp/**"),
|
|
575
|
+
"--exclude",
|
|
576
|
+
import_path.default.join(projectRoot, "src/pages/**"),
|
|
577
|
+
"--include",
|
|
578
|
+
webapp.serverEntry,
|
|
579
|
+
import_path.default.join(__dirname, "node-dev.js")
|
|
580
|
+
],
|
|
581
|
+
cwd: projectRoot,
|
|
582
|
+
env
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
await run({ packageName: "@react-router/dev", args: [command, framework.rootDirectory, "--config", framework.viteConfig, ...args], ...options });
|
|
586
|
+
if (webapp.serverEntry) {
|
|
587
|
+
const { buildNode: buildNode2 } = await Promise.resolve().then(() => (init_node(), node_exports));
|
|
588
|
+
await buildNode2({ projectRoot, webapp });
|
|
589
|
+
}
|
|
291
590
|
}
|
|
292
591
|
main().catch((err) => {
|
|
293
592
|
console.error("XFE Web CLI \u6267\u884C\u51FA\u9519:", err);
|