@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/config.d.mts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
type WebAppConfig = {
|
|
2
2
|
basename?: string;
|
|
3
|
+
/** 相对于项目根目录的输出路径,默认 dist;旧项目可显式设置 build。 */
|
|
4
|
+
buildDirectory?: string;
|
|
3
5
|
host?: string;
|
|
4
6
|
port?: number;
|
|
5
7
|
/** 渲染方式由 XFE 转换为底层框架配置;省略时兼容已有服务端应用。 */
|
|
6
8
|
renderMode?: 'client' | 'server';
|
|
9
|
+
/** 项目内默认导出 Node 工厂的源码入口;省略时保留原有 SPA / SSR 启动。 */
|
|
10
|
+
serverEntry?: string;
|
|
7
11
|
title?: string;
|
|
8
12
|
lang?: string;
|
|
9
13
|
themeColor?: string;
|
|
@@ -16,8 +20,14 @@ type JwtEnv = {
|
|
|
16
20
|
XFE_JWT_KEY_ID: string;
|
|
17
21
|
XFE_JWT_PRIVATE_KEY: string;
|
|
18
22
|
};
|
|
23
|
+
/** 读取业务配置,并在构建或启动前拒绝无效的渲染方式和输出路径。 */
|
|
19
24
|
declare const loadXfeConfig: (root?: string) => XfeConfig;
|
|
25
|
+
/** 返回构建和启动共用的绝对路径,防止清空项目根目录或框架输入目录。 */
|
|
26
|
+
declare const getBuildDirectory: (projectRoot: string, webapp?: WebAppConfig) => string;
|
|
27
|
+
/** 生产仅校验入口约定而不读取源码,构建阶段由编译器检查文件存在。 */
|
|
28
|
+
declare const getServerEntry: (projectRoot: string, webapp?: WebAppConfig) => string | undefined;
|
|
29
|
+
/** 将输出目录传给 Docker 构建,并沿用现有的集群、域名与 Helm 配置。 */
|
|
20
30
|
declare const configDeploy: () => void;
|
|
21
31
|
declare const getJwtEnv: () => Promise<Partial<JwtEnv>>;
|
|
22
32
|
|
|
23
|
-
export { type JwtEnv, type WebAppConfig, type XfeConfig, configDeploy, getJwtEnv, loadXfeConfig };
|
|
33
|
+
export { type JwtEnv, type WebAppConfig, type XfeConfig, configDeploy, getBuildDirectory, getJwtEnv, getServerEntry, loadXfeConfig };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
type WebAppConfig = {
|
|
2
2
|
basename?: string;
|
|
3
|
+
/** 相对于项目根目录的输出路径,默认 dist;旧项目可显式设置 build。 */
|
|
4
|
+
buildDirectory?: string;
|
|
3
5
|
host?: string;
|
|
4
6
|
port?: number;
|
|
5
7
|
/** 渲染方式由 XFE 转换为底层框架配置;省略时兼容已有服务端应用。 */
|
|
6
8
|
renderMode?: 'client' | 'server';
|
|
9
|
+
/** 项目内默认导出 Node 工厂的源码入口;省略时保留原有 SPA / SSR 启动。 */
|
|
10
|
+
serverEntry?: string;
|
|
7
11
|
title?: string;
|
|
8
12
|
lang?: string;
|
|
9
13
|
themeColor?: string;
|
|
@@ -16,8 +20,14 @@ type JwtEnv = {
|
|
|
16
20
|
XFE_JWT_KEY_ID: string;
|
|
17
21
|
XFE_JWT_PRIVATE_KEY: string;
|
|
18
22
|
};
|
|
23
|
+
/** 读取业务配置,并在构建或启动前拒绝无效的渲染方式和输出路径。 */
|
|
19
24
|
declare const loadXfeConfig: (root?: string) => XfeConfig;
|
|
25
|
+
/** 返回构建和启动共用的绝对路径,防止清空项目根目录或框架输入目录。 */
|
|
26
|
+
declare const getBuildDirectory: (projectRoot: string, webapp?: WebAppConfig) => string;
|
|
27
|
+
/** 生产仅校验入口约定而不读取源码,构建阶段由编译器检查文件存在。 */
|
|
28
|
+
declare const getServerEntry: (projectRoot: string, webapp?: WebAppConfig) => string | undefined;
|
|
29
|
+
/** 将输出目录传给 Docker 构建,并沿用现有的集群、域名与 Helm 配置。 */
|
|
20
30
|
declare const configDeploy: () => void;
|
|
21
31
|
declare const getJwtEnv: () => Promise<Partial<JwtEnv>>;
|
|
22
32
|
|
|
23
|
-
export { type JwtEnv, type WebAppConfig, type XfeConfig, configDeploy, getJwtEnv, loadXfeConfig };
|
|
33
|
+
export { type JwtEnv, type WebAppConfig, type XfeConfig, configDeploy, getBuildDirectory, getJwtEnv, getServerEntry, loadXfeConfig };
|
package/dist/config.js
CHANGED
|
@@ -31,33 +31,89 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var config_exports = {};
|
|
32
32
|
__export(config_exports, {
|
|
33
33
|
configDeploy: () => configDeploy,
|
|
34
|
+
getBuildDirectory: () => getBuildDirectory,
|
|
34
35
|
getJwtEnv: () => getJwtEnv,
|
|
36
|
+
getServerEntry: () => getServerEntry,
|
|
35
37
|
loadXfeConfig: () => loadXfeConfig
|
|
36
38
|
});
|
|
37
39
|
module.exports = __toCommonJS(config_exports);
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
+
var import_node_fs = __toESM(require("fs"));
|
|
41
|
+
var import_node_path = __toESM(require("path"));
|
|
42
|
+
var import_node_url = require("url");
|
|
40
43
|
var import_yaml = __toESM(require("yaml"));
|
|
44
|
+
var import_meta = {};
|
|
45
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
46
|
+
var BUILD_DIRECTORY_ARGUMENT = "XFE_BUILD_DIRECTORY";
|
|
47
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
41
48
|
var loadXfeConfig = (root = process.cwd()) => {
|
|
42
|
-
const xfeConfigPath =
|
|
43
|
-
if (!
|
|
49
|
+
const xfeConfigPath = import_node_path.default.join(root, "xfe.json");
|
|
50
|
+
if (!import_node_fs.default.existsSync(xfeConfigPath)) {
|
|
44
51
|
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");
|
|
45
52
|
}
|
|
46
|
-
const xfeConfigContent =
|
|
53
|
+
const xfeConfigContent = import_node_fs.default.readFileSync(xfeConfigPath, "utf8");
|
|
47
54
|
const config = JSON.parse(xfeConfigContent);
|
|
48
55
|
const renderMode = config.webapp?.renderMode;
|
|
49
56
|
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
50
57
|
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
51
58
|
}
|
|
59
|
+
getBuildDirectory(root, config.webapp);
|
|
60
|
+
getServerEntry(root, config.webapp);
|
|
52
61
|
return config;
|
|
53
62
|
};
|
|
63
|
+
var getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
64
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
|
|
65
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
66
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
67
|
+
}
|
|
68
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
69
|
+
const root = import_node_path.default.resolve(projectRoot);
|
|
70
|
+
const output = import_node_path.default.resolve(root, directory);
|
|
71
|
+
const relative = import_node_path.default.relative(root, output);
|
|
72
|
+
const [firstDirectory = ""] = relative.split(import_node_path.default.sep);
|
|
73
|
+
const escapesProject = import_node_path.default.isAbsolute(directory) || Boolean(import_node_path.default.win32.parse(directory).root) || firstDirectory === "..";
|
|
74
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
75
|
+
if (escapesProject || overwritesInput) {
|
|
76
|
+
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");
|
|
77
|
+
}
|
|
78
|
+
let currentDirectory = root;
|
|
79
|
+
for (const segment of relative.split(import_node_path.default.sep)) {
|
|
80
|
+
currentDirectory = import_node_path.default.join(currentDirectory, segment);
|
|
81
|
+
if (import_node_fs.default.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
82
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return output;
|
|
86
|
+
};
|
|
87
|
+
var getServerEntry = (projectRoot, webapp = {}) => {
|
|
88
|
+
const entry = webapp?.serverEntry;
|
|
89
|
+
if (entry === void 0) return;
|
|
90
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
91
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
92
|
+
}
|
|
93
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
94
|
+
const absolute = import_node_path.default.resolve(projectRoot, normalized);
|
|
95
|
+
const relative = import_node_path.default.relative(import_node_path.default.resolve(projectRoot), absolute);
|
|
96
|
+
const outside = Boolean(import_node_path.default.win32.parse(normalized).root) || relative.split(import_node_path.default.sep)[0] === "..";
|
|
97
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
98
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
99
|
+
}
|
|
100
|
+
return absolute;
|
|
101
|
+
};
|
|
54
102
|
var configDeploy = () => {
|
|
55
103
|
const xfeConfig = loadXfeConfig();
|
|
56
104
|
if (!xfeConfig?.deploy) return;
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const
|
|
105
|
+
const configDirectory = typeof __dirname === "string" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
106
|
+
const projectRoot = process.cwd();
|
|
107
|
+
const buildDirectory = import_node_path.default.relative(projectRoot, getBuildDirectory(projectRoot, xfeConfig.webapp)).replaceAll(import_node_path.default.sep, "/");
|
|
108
|
+
const droneConfigFilePath = import_node_path.default.resolve(configDirectory, "../deploy/.drone.yml");
|
|
109
|
+
const droneTarget = import_node_path.default.resolve(projectRoot, xfeConfig.deploy.droneConfigPath || "./.drone.yml");
|
|
110
|
+
const defaultArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${DEFAULT_BUILD_DIRECTORY}`);
|
|
111
|
+
const configuredArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${buildDirectory}`);
|
|
112
|
+
const droneConfig = import_node_fs.default.readFileSync(droneConfigFilePath, "utf8").replace(defaultArgument, configuredArgument);
|
|
113
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(droneTarget), { recursive: true });
|
|
114
|
+
import_node_fs.default.writeFileSync(droneTarget, droneConfig);
|
|
115
|
+
const valuesYamlFilePath = import_node_path.default.resolve(configDirectory, "../deploy/helm/values.yaml");
|
|
116
|
+
const valuesYamlFile = import_node_fs.default.readFileSync(valuesYamlFilePath, "utf8");
|
|
61
117
|
const valuesYaml = import_yaml.default.parse(valuesYamlFile);
|
|
62
118
|
if (!valuesYaml.virtualService) valuesYaml.virtualService = {};
|
|
63
119
|
if (!valuesYaml.virtualService.hosts) valuesYaml.virtualService.hosts = { test: [], stage: [], prod: [] };
|
|
@@ -77,7 +133,7 @@ var configDeploy = () => {
|
|
|
77
133
|
valuesYaml.targetK8s = targetK8s;
|
|
78
134
|
valuesYaml.namespace = targetNamespace;
|
|
79
135
|
const valuesYamlStr = import_yaml.default.stringify(valuesYaml, { defaultStringType: "QUOTE_SINGLE", defaultKeyType: "PLAIN" });
|
|
80
|
-
|
|
136
|
+
import_node_fs.default.writeFileSync(valuesYamlFilePath, valuesYamlStr, "utf8");
|
|
81
137
|
};
|
|
82
138
|
var getJwtEnv = async () => {
|
|
83
139
|
const xfeConfig = loadXfeConfig();
|
|
@@ -101,6 +157,8 @@ var getJwtEnv = async () => {
|
|
|
101
157
|
// Annotate the CommonJS export names for ESM import in node:
|
|
102
158
|
0 && (module.exports = {
|
|
103
159
|
configDeploy,
|
|
160
|
+
getBuildDirectory,
|
|
104
161
|
getJwtEnv,
|
|
162
|
+
getServerEntry,
|
|
105
163
|
loadXfeConfig
|
|
106
164
|
});
|
package/dist/config.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
|
-
import path from "path";
|
|
3
2
|
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
4
5
|
import yaml from "yaml";
|
|
6
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
7
|
+
var BUILD_DIRECTORY_ARGUMENT = "XFE_BUILD_DIRECTORY";
|
|
8
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
5
9
|
var loadXfeConfig = (root = process.cwd()) => {
|
|
6
10
|
const xfeConfigPath = path.join(root, "xfe.json");
|
|
7
11
|
if (!fs.existsSync(xfeConfigPath)) {
|
|
@@ -13,14 +17,63 @@ var loadXfeConfig = (root = process.cwd()) => {
|
|
|
13
17
|
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
14
18
|
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
15
19
|
}
|
|
20
|
+
getBuildDirectory(root, config.webapp);
|
|
21
|
+
getServerEntry(root, config.webapp);
|
|
16
22
|
return config;
|
|
17
23
|
};
|
|
24
|
+
var getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
25
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.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(projectRoot);
|
|
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 = (projectRoot, webapp = {}) => {
|
|
49
|
+
const entry = webapp?.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(projectRoot, normalized);
|
|
56
|
+
const relative = path.relative(path.resolve(projectRoot), 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
|
+
};
|
|
18
63
|
var configDeploy = () => {
|
|
19
64
|
const xfeConfig = loadXfeConfig();
|
|
20
65
|
if (!xfeConfig?.deploy) return;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const
|
|
66
|
+
const configDirectory = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
|
|
67
|
+
const projectRoot = process.cwd();
|
|
68
|
+
const buildDirectory = path.relative(projectRoot, getBuildDirectory(projectRoot, xfeConfig.webapp)).replaceAll(path.sep, "/");
|
|
69
|
+
const droneConfigFilePath = path.resolve(configDirectory, "../deploy/.drone.yml");
|
|
70
|
+
const droneTarget = path.resolve(projectRoot, xfeConfig.deploy.droneConfigPath || "./.drone.yml");
|
|
71
|
+
const defaultArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${DEFAULT_BUILD_DIRECTORY}`);
|
|
72
|
+
const configuredArgument = JSON.stringify(`${BUILD_DIRECTORY_ARGUMENT}=${buildDirectory}`);
|
|
73
|
+
const droneConfig = fs.readFileSync(droneConfigFilePath, "utf8").replace(defaultArgument, configuredArgument);
|
|
74
|
+
fs.mkdirSync(path.dirname(droneTarget), { recursive: true });
|
|
75
|
+
fs.writeFileSync(droneTarget, droneConfig);
|
|
76
|
+
const valuesYamlFilePath = path.resolve(configDirectory, "../deploy/helm/values.yaml");
|
|
24
77
|
const valuesYamlFile = fs.readFileSync(valuesYamlFilePath, "utf8");
|
|
25
78
|
const valuesYaml = yaml.parse(valuesYamlFile);
|
|
26
79
|
if (!valuesYaml.virtualService) valuesYaml.virtualService = {};
|
|
@@ -64,6 +117,8 @@ var getJwtEnv = async () => {
|
|
|
64
117
|
};
|
|
65
118
|
export {
|
|
66
119
|
configDeploy,
|
|
120
|
+
getBuildDirectory,
|
|
67
121
|
getJwtEnv,
|
|
122
|
+
getServerEntry,
|
|
68
123
|
loadXfeConfig
|
|
69
124
|
};
|
package/dist/framework.js
CHANGED
|
@@ -34,49 +34,93 @@ __export(framework_exports, {
|
|
|
34
34
|
prepareFramework: () => prepareFramework
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(framework_exports);
|
|
37
|
-
var
|
|
37
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
38
38
|
var import_node_module = require("module");
|
|
39
|
-
var
|
|
40
|
-
var
|
|
39
|
+
var import_node_path2 = __toESM(require("path"));
|
|
40
|
+
var import_node_url2 = require("url");
|
|
41
41
|
|
|
42
42
|
// src/config.ts
|
|
43
|
-
var
|
|
44
|
-
var
|
|
43
|
+
var import_node_fs = __toESM(require("fs"));
|
|
44
|
+
var import_node_path = __toESM(require("path"));
|
|
45
|
+
var import_node_url = require("url");
|
|
45
46
|
var import_yaml = __toESM(require("yaml"));
|
|
47
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
48
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
46
49
|
var loadXfeConfig = (root = process.cwd()) => {
|
|
47
|
-
const xfeConfigPath =
|
|
48
|
-
if (!
|
|
50
|
+
const xfeConfigPath = import_node_path.default.join(root, "xfe.json");
|
|
51
|
+
if (!import_node_fs.default.existsSync(xfeConfigPath)) {
|
|
49
52
|
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
53
|
}
|
|
51
|
-
const xfeConfigContent =
|
|
54
|
+
const xfeConfigContent = import_node_fs.default.readFileSync(xfeConfigPath, "utf8");
|
|
52
55
|
const config = JSON.parse(xfeConfigContent);
|
|
53
56
|
const renderMode = config.webapp?.renderMode;
|
|
54
57
|
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
55
58
|
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
56
59
|
}
|
|
60
|
+
getBuildDirectory(root, config.webapp);
|
|
61
|
+
getServerEntry(root, config.webapp);
|
|
57
62
|
return config;
|
|
58
63
|
};
|
|
64
|
+
var getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
65
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
|
|
66
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
67
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
68
|
+
}
|
|
69
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
70
|
+
const root = import_node_path.default.resolve(projectRoot);
|
|
71
|
+
const output = import_node_path.default.resolve(root, directory);
|
|
72
|
+
const relative = import_node_path.default.relative(root, output);
|
|
73
|
+
const [firstDirectory = ""] = relative.split(import_node_path.default.sep);
|
|
74
|
+
const escapesProject = import_node_path.default.isAbsolute(directory) || Boolean(import_node_path.default.win32.parse(directory).root) || firstDirectory === "..";
|
|
75
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
76
|
+
if (escapesProject || overwritesInput) {
|
|
77
|
+
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");
|
|
78
|
+
}
|
|
79
|
+
let currentDirectory = root;
|
|
80
|
+
for (const segment of relative.split(import_node_path.default.sep)) {
|
|
81
|
+
currentDirectory = import_node_path.default.join(currentDirectory, segment);
|
|
82
|
+
if (import_node_fs.default.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
83
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return output;
|
|
87
|
+
};
|
|
88
|
+
var getServerEntry = (projectRoot, webapp = {}) => {
|
|
89
|
+
const entry = webapp?.serverEntry;
|
|
90
|
+
if (entry === void 0) return;
|
|
91
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
92
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
93
|
+
}
|
|
94
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
95
|
+
const absolute = import_node_path.default.resolve(projectRoot, normalized);
|
|
96
|
+
const relative = import_node_path.default.relative(import_node_path.default.resolve(projectRoot), absolute);
|
|
97
|
+
const outside = Boolean(import_node_path.default.win32.parse(normalized).root) || relative.split(import_node_path.default.sep)[0] === "..";
|
|
98
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
99
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
100
|
+
}
|
|
101
|
+
return absolute;
|
|
102
|
+
};
|
|
59
103
|
|
|
60
104
|
// src/framework.ts
|
|
61
105
|
var import_meta = {};
|
|
62
|
-
var frameworkDirectory = typeof __dirname === "string" ? __dirname :
|
|
63
|
-
var requireFromFramework = (0, import_node_module.createRequire)(
|
|
106
|
+
var frameworkDirectory = typeof __dirname === "string" ? __dirname : import_node_path2.default.dirname((0, import_node_url2.fileURLToPath)(import_meta.url));
|
|
107
|
+
var requireFromFramework = (0, import_node_module.createRequire)(import_node_path2.default.join(frameworkDirectory, "framework.js"));
|
|
64
108
|
var extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
65
|
-
var findSource = (directory, name) => extensions.map((extension) =>
|
|
66
|
-
var findValueExports = (file) => [...
|
|
109
|
+
var findSource = (directory, name) => extensions.map((extension) => import_node_path2.default.join(directory, `${name}${extension}`)).find(import_node_fs2.default.existsSync);
|
|
110
|
+
var 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(
|
|
67
111
|
([, name]) => name
|
|
68
112
|
);
|
|
69
113
|
var importPath = (from, target) => {
|
|
70
|
-
const relative =
|
|
114
|
+
const relative = import_node_path2.default.relative(from, target).replace(import_node_path2.default.extname(target), "").replaceAll(import_node_path2.default.sep, "/");
|
|
71
115
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
72
116
|
};
|
|
73
117
|
var writeGenerated = (file, content) => {
|
|
74
|
-
if (
|
|
75
|
-
|
|
118
|
+
if (import_node_fs2.default.existsSync(file) && import_node_fs2.default.readFileSync(file, "utf8") === content) return;
|
|
119
|
+
import_node_fs2.default.writeFileSync(file, content);
|
|
76
120
|
};
|
|
77
121
|
var defaultRootSource = (projectRoot, appDirectory) => {
|
|
78
122
|
const { webapp = {} } = loadXfeConfig(projectRoot);
|
|
79
|
-
const layoutSource = findSource(
|
|
123
|
+
const layoutSource = findSource(import_node_path2.default.join(projectRoot, "src"), "layout");
|
|
80
124
|
const layoutExports = layoutSource ? findValueExports(layoutSource) : [];
|
|
81
125
|
const hasErrorView = layoutExports.includes("ErrorView");
|
|
82
126
|
const layoutImport = layoutSource ? `import AppLayout${hasErrorView ? ", { ErrorView }" : ""} from ${JSON.stringify(importPath(appDirectory, layoutSource))}
|
|
@@ -92,24 +136,24 @@ export function ErrorBoundary() { return createElement(PageError, { ${hasErrorVi
|
|
|
92
136
|
export function HydrateFallback() { return createElement(PageLoading) }
|
|
93
137
|
`;
|
|
94
138
|
};
|
|
95
|
-
var getFrameworkRoot = (projectRoot) =>
|
|
139
|
+
var getFrameworkRoot = (projectRoot) => import_node_path2.default.join(projectRoot, "node_modules/.cache/xfe-web/react-router");
|
|
96
140
|
var prepareFramework = (projectRoot = process.cwd()) => {
|
|
97
|
-
const sourceDirectory =
|
|
141
|
+
const sourceDirectory = import_node_path2.default.join(projectRoot, "src");
|
|
98
142
|
const rootSource = findSource(sourceDirectory, "root");
|
|
99
143
|
const appServerSource = findSource(sourceDirectory, "app.server");
|
|
100
|
-
const pagesSource =
|
|
101
|
-
if (!
|
|
144
|
+
const pagesSource = import_node_path2.default.join(sourceDirectory, "pages");
|
|
145
|
+
if (!import_node_fs2.default.existsSync(pagesSource)) throw new Error("\u672A\u627E\u5230 src/pages");
|
|
102
146
|
const rootDirectory = getFrameworkRoot(projectRoot);
|
|
103
|
-
const appDirectory =
|
|
104
|
-
|
|
105
|
-
const routerDirectory =
|
|
106
|
-
const routerLink =
|
|
107
|
-
|
|
108
|
-
if (!
|
|
109
|
-
|
|
110
|
-
|
|
147
|
+
const appDirectory = import_node_path2.default.join(rootDirectory, "app");
|
|
148
|
+
import_node_fs2.default.mkdirSync(appDirectory, { recursive: true });
|
|
149
|
+
const routerDirectory = import_node_path2.default.dirname(requireFromFramework.resolve("react-router/package.json"));
|
|
150
|
+
const routerLink = import_node_path2.default.join(rootDirectory, "node_modules/react-router");
|
|
151
|
+
import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(routerLink), { recursive: true });
|
|
152
|
+
if (!import_node_fs2.default.lstatSync(routerLink, { throwIfNoEntry: false })?.isSymbolicLink() || import_node_fs2.default.readlinkSync(routerLink) !== routerDirectory) {
|
|
153
|
+
import_node_fs2.default.rmSync(routerLink, { force: true });
|
|
154
|
+
import_node_fs2.default.symlinkSync(routerDirectory, routerLink, "junction");
|
|
111
155
|
}
|
|
112
|
-
const rootTarget =
|
|
156
|
+
const rootTarget = import_node_path2.default.join(appDirectory, "root.tsx");
|
|
113
157
|
const rootImport = rootSource ? importPath(appDirectory, rootSource) : "";
|
|
114
158
|
const rootExports = rootSource ? findValueExports(rootSource).filter((name) => name !== "middleware" || !appServerSource) : [];
|
|
115
159
|
const namedExports = rootExports.length ? `export { ${rootExports.join(", ")} } from ${JSON.stringify(rootImport)}
|
|
@@ -123,36 +167,36 @@ var prepareFramework = (projectRoot = process.cwd()) => {
|
|
|
123
167
|
export { default } from ${JSON.stringify(rootImport)}
|
|
124
168
|
${namedExports}${errorBoundaryExport}${middlewareExport}` : `${defaultRootSource(projectRoot, appDirectory)}${middlewareExport}`
|
|
125
169
|
);
|
|
126
|
-
const pagesLink =
|
|
127
|
-
if (!
|
|
170
|
+
const pagesLink = import_node_path2.default.join(appDirectory, "pages");
|
|
171
|
+
if (!import_node_fs2.default.existsSync(pagesLink)) import_node_fs2.default.symlinkSync(import_node_path2.default.relative(appDirectory, pagesSource), pagesLink, "dir");
|
|
128
172
|
writeGenerated(
|
|
129
|
-
|
|
173
|
+
import_node_path2.default.join(rootDirectory, "react-router.config.js"),
|
|
130
174
|
"export { default } from '@xfe-repo/web-app/dist/react-router-config.mjs'\n"
|
|
131
175
|
);
|
|
132
176
|
writeGenerated(
|
|
133
|
-
|
|
177
|
+
import_node_path2.default.join(appDirectory, "routes.js"),
|
|
134
178
|
`import { collectPageRoutes } from '@xfe-repo/web-router/routes'
|
|
135
179
|
export default collectPageRoutes(${JSON.stringify(appDirectory)})
|
|
136
180
|
`
|
|
137
181
|
);
|
|
138
|
-
const defaultsDirectory =
|
|
182
|
+
const defaultsDirectory = import_node_path2.default.join(import_node_path2.default.dirname(requireFromFramework.resolve("@react-router/dev/package.json")), "dist/config/defaults");
|
|
139
183
|
writeGenerated(
|
|
140
|
-
|
|
141
|
-
`export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory,
|
|
184
|
+
import_node_path2.default.join(appDirectory, "entry.server.tsx"),
|
|
185
|
+
`export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory, import_node_path2.default.join(defaultsDirectory, "entry.server.web.tsx")))}
|
|
142
186
|
`
|
|
143
187
|
);
|
|
144
|
-
const typeScriptConfig =
|
|
188
|
+
const typeScriptConfig = import_node_path2.default.join(rootDirectory, "tsconfig.json");
|
|
145
189
|
writeGenerated(
|
|
146
190
|
typeScriptConfig,
|
|
147
191
|
JSON.stringify(
|
|
148
192
|
{
|
|
149
|
-
extends:
|
|
150
|
-
compilerOptions: { rootDirs: [projectRoot, rootDirectory,
|
|
193
|
+
extends: import_node_path2.default.join(projectRoot, "tsconfig.json"),
|
|
194
|
+
compilerOptions: { rootDirs: [projectRoot, rootDirectory, import_node_path2.default.join(rootDirectory, ".react-router/types")] },
|
|
151
195
|
include: [
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
196
|
+
import_node_path2.default.join(sourceDirectory, "**/*"),
|
|
197
|
+
import_node_path2.default.join(projectRoot, "types/**/*"),
|
|
198
|
+
import_node_path2.default.join(appDirectory, "*.tsx"),
|
|
199
|
+
import_node_path2.default.join(rootDirectory, ".react-router/types/**/*")
|
|
156
200
|
],
|
|
157
201
|
exclude: []
|
|
158
202
|
},
|
|
@@ -163,7 +207,7 @@ export default collectPageRoutes(${JSON.stringify(appDirectory)})
|
|
|
163
207
|
return {
|
|
164
208
|
appDirectory,
|
|
165
209
|
rootDirectory,
|
|
166
|
-
viteConfig:
|
|
210
|
+
viteConfig: import_node_path2.default.resolve(frameworkDirectory, "vite.mjs"),
|
|
167
211
|
typeScriptConfig
|
|
168
212
|
};
|
|
169
213
|
};
|
package/dist/framework.mjs
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
import fs2 from "fs";
|
|
3
3
|
import { createRequire } from "module";
|
|
4
4
|
import path2 from "path";
|
|
5
|
-
import { fileURLToPath } from "url";
|
|
5
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
|
-
import path from "path";
|
|
9
8
|
import fs from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
10
11
|
import yaml from "yaml";
|
|
12
|
+
var DEFAULT_BUILD_DIRECTORY = "dist";
|
|
13
|
+
var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
|
|
11
14
|
var loadXfeConfig = (root = process.cwd()) => {
|
|
12
15
|
const xfeConfigPath = path.join(root, "xfe.json");
|
|
13
16
|
if (!fs.existsSync(xfeConfigPath)) {
|
|
@@ -19,11 +22,52 @@ var loadXfeConfig = (root = process.cwd()) => {
|
|
|
19
22
|
if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
|
|
20
23
|
throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
|
|
21
24
|
}
|
|
25
|
+
getBuildDirectory(root, config.webapp);
|
|
26
|
+
getServerEntry(root, config.webapp);
|
|
22
27
|
return config;
|
|
23
28
|
};
|
|
29
|
+
var getBuildDirectory = (projectRoot, webapp = {}) => {
|
|
30
|
+
const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
|
|
31
|
+
if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
|
|
32
|
+
throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
|
|
33
|
+
}
|
|
34
|
+
const directory = configured.trim().replaceAll("\\", "/");
|
|
35
|
+
const root = path.resolve(projectRoot);
|
|
36
|
+
const output = path.resolve(root, directory);
|
|
37
|
+
const relative = path.relative(root, output);
|
|
38
|
+
const [firstDirectory = ""] = relative.split(path.sep);
|
|
39
|
+
const escapesProject = path.isAbsolute(directory) || Boolean(path.win32.parse(directory).root) || firstDirectory === "..";
|
|
40
|
+
const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
|
|
41
|
+
if (escapesProject || overwritesInput) {
|
|
42
|
+
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");
|
|
43
|
+
}
|
|
44
|
+
let currentDirectory = root;
|
|
45
|
+
for (const segment of relative.split(path.sep)) {
|
|
46
|
+
currentDirectory = path.join(currentDirectory, segment);
|
|
47
|
+
if (fs.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
|
|
48
|
+
throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return output;
|
|
52
|
+
};
|
|
53
|
+
var getServerEntry = (projectRoot, webapp = {}) => {
|
|
54
|
+
const entry = webapp?.serverEntry;
|
|
55
|
+
if (entry === void 0) return;
|
|
56
|
+
if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
|
|
57
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
58
|
+
}
|
|
59
|
+
const normalized = entry.trim().replaceAll("\\", "/");
|
|
60
|
+
const absolute = path.resolve(projectRoot, normalized);
|
|
61
|
+
const relative = path.relative(path.resolve(projectRoot), absolute);
|
|
62
|
+
const outside = Boolean(path.win32.parse(normalized).root) || relative.split(path.sep)[0] === "..";
|
|
63
|
+
if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
|
|
64
|
+
throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
|
|
65
|
+
}
|
|
66
|
+
return absolute;
|
|
67
|
+
};
|
|
24
68
|
|
|
25
69
|
// src/framework.ts
|
|
26
|
-
var frameworkDirectory = typeof __dirname === "string" ? __dirname : path2.dirname(
|
|
70
|
+
var frameworkDirectory = typeof __dirname === "string" ? __dirname : path2.dirname(fileURLToPath2(import.meta.url));
|
|
27
71
|
var requireFromFramework = createRequire(path2.join(frameworkDirectory, "framework.js"));
|
|
28
72
|
var extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
29
73
|
var findSource = (directory, name) => extensions.map((extension) => path2.join(directory, `${name}${extension}`)).find(fs2.existsSync);
|