@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.
Files changed (56) hide show
  1. package/README.md +118 -1
  2. package/client.d.ts +1 -0
  3. package/deploy/.drone.yml +13 -4
  4. package/deploy/Dockerfile +15 -6
  5. package/deploy/helm/templates/deployment.yaml +5 -18
  6. package/deploy/helm/templates/svc.yaml +1 -1
  7. package/dist/cli.js +577 -416
  8. package/dist/cli.mjs +562 -256
  9. package/dist/config.d.mts +30 -6
  10. package/dist/config.d.ts +30 -6
  11. package/dist/config.js +142 -298
  12. package/dist/config.mjs +124 -2
  13. package/dist/framework.d.mts +10 -0
  14. package/dist/framework.d.ts +10 -0
  15. package/dist/framework.js +220 -0
  16. package/dist/framework.mjs +182 -0
  17. package/dist/node-dev.d.mts +2 -0
  18. package/dist/node-dev.d.ts +2 -0
  19. package/dist/node-dev.js +358 -0
  20. package/dist/node-dev.mjs +332 -0
  21. package/dist/node.d.mts +27 -0
  22. package/dist/node.d.ts +27 -0
  23. package/dist/node.js +381 -0
  24. package/dist/node.mjs +343 -0
  25. package/dist/react-router-config.d.mts +11 -0
  26. package/dist/react-router-config.d.ts +11 -0
  27. package/dist/react-router-config.js +111 -0
  28. package/dist/react-router-config.mjs +77 -0
  29. package/dist/root.d.mts +17 -0
  30. package/dist/root.d.ts +17 -0
  31. package/dist/root.js +61 -0
  32. package/dist/root.mjs +34 -0
  33. package/dist/serve.d.mts +10 -0
  34. package/dist/serve.d.ts +10 -0
  35. package/dist/serve.js +71 -0
  36. package/dist/serve.mjs +36 -0
  37. package/dist/vite.d.mts +10 -0
  38. package/dist/vite.d.ts +10 -0
  39. package/dist/vite.js +182 -0
  40. package/dist/vite.mjs +146 -0
  41. package/package.json +27 -72
  42. package/tsconfig.json +4 -1
  43. package/config/env.js +0 -104
  44. package/config/getHttpsConfig.js +0 -66
  45. package/config/jest/babelTransform.js +0 -29
  46. package/config/jest/cssTransform.js +0 -14
  47. package/config/jest/fileTransform.js +0 -40
  48. package/config/modules.js +0 -133
  49. package/config/paths.js +0 -65
  50. package/config/webpack/persistentCache/createEnvironmentHash.js +0 -9
  51. package/config/webpack/webpack.config.js +0 -737
  52. package/config/webpack/webpackDevServer.config.js +0 -122
  53. package/deploy/nginx.conf +0 -62
  54. package/dist/chunk-75BJNL7E.mjs +0 -239
  55. package/scripts/build.js +0 -217
  56. package/scripts/dev.js +0 -162
package/dist/config.mjs CHANGED
@@ -1,2 +1,124 @@
1
- import { configDeploy, getJwtEnv, loadXfeConfig } from "./chunk-75BJNL7E.mjs";
2
- export { configDeploy, getJwtEnv, loadXfeConfig };
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 BUILD_DIRECTORY_ARGUMENT = "XFE_BUILD_DIRECTORY";
8
+ var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
9
+ var configDirectory = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
10
+ var loadXfeConfig = (root = process.cwd()) => {
11
+ const xfeConfigPath = path.join(root, "xfe.json");
12
+ if (!fs.existsSync(xfeConfigPath)) {
13
+ 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");
14
+ }
15
+ const xfeConfigContent = fs.readFileSync(xfeConfigPath, "utf8");
16
+ const config = JSON.parse(xfeConfigContent);
17
+ const renderMode = config.webapp?.renderMode;
18
+ if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
19
+ throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
20
+ }
21
+ getBuildDirectory(root, config.webapp);
22
+ getServerEntry(root, config.webapp);
23
+ return config;
24
+ };
25
+ var getBuildDirectory = (projectRoot, webapp = {}) => {
26
+ const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
27
+ if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
28
+ throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
29
+ }
30
+ const directory = configured.trim().replaceAll("\\", "/");
31
+ const root = path.resolve(projectRoot);
32
+ const output = path.resolve(root, directory);
33
+ const relative = path.relative(root, output);
34
+ const [firstDirectory = ""] = relative.split(path.sep);
35
+ const escapesProject = path.isAbsolute(directory) || Boolean(path.win32.parse(directory).root) || firstDirectory === "..";
36
+ const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
37
+ if (escapesProject || overwritesInput) {
38
+ 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");
39
+ }
40
+ let currentDirectory = root;
41
+ for (const segment of relative.split(path.sep)) {
42
+ currentDirectory = path.join(currentDirectory, segment);
43
+ if (fs.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
44
+ throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
45
+ }
46
+ }
47
+ return output;
48
+ };
49
+ var getServerEntry = (projectRoot, webapp = {}) => {
50
+ const entry = webapp?.serverEntry;
51
+ if (entry === void 0) return;
52
+ if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
53
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
54
+ }
55
+ const normalized = entry.trim().replaceAll("\\", "/");
56
+ const absolute = path.resolve(projectRoot, normalized);
57
+ const relative = path.relative(path.resolve(projectRoot), absolute);
58
+ const outside = Boolean(path.win32.parse(normalized).root) || relative.split(path.sep)[0] === "..";
59
+ if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
60
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
61
+ }
62
+ return absolute;
63
+ };
64
+ var configDeploy = () => {
65
+ const xfeConfig = loadXfeConfig();
66
+ if (!xfeConfig?.deploy) return;
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");
77
+ const valuesYamlFile = fs.readFileSync(valuesYamlFilePath, "utf8");
78
+ const valuesYaml = yaml.parse(valuesYamlFile);
79
+ if (!valuesYaml.virtualService) valuesYaml.virtualService = {};
80
+ if (!valuesYaml.virtualService.hosts) valuesYaml.virtualService.hosts = { test: [], stage: [], prod: [] };
81
+ const {
82
+ virtualServiceEnabled = true,
83
+ hostsProd = [],
84
+ hostsStage = [],
85
+ hostsTest = [],
86
+ gateways = ["common-gateway-eshetang"]
87
+ } = xfeConfig.deploy;
88
+ const { targetK8s = "saas", targetNamespace = "" } = xfeConfig.deploy;
89
+ valuesYaml.virtualService.enabled = virtualServiceEnabled;
90
+ valuesYaml.virtualService.gateways = gateways;
91
+ valuesYaml.virtualService.hosts.prod = hostsProd;
92
+ valuesYaml.virtualService.hosts.stage = hostsStage;
93
+ valuesYaml.virtualService.hosts.test = hostsTest;
94
+ valuesYaml.targetK8s = targetK8s;
95
+ valuesYaml.namespace = targetNamespace;
96
+ const valuesYamlStr = yaml.stringify(valuesYaml, { defaultStringType: "QUOTE_SINGLE", defaultKeyType: "PLAIN" });
97
+ fs.writeFileSync(valuesYamlFilePath, valuesYamlStr, "utf8");
98
+ };
99
+ var getJwtEnv = async () => {
100
+ const xfeConfig = loadXfeConfig();
101
+ if (!xfeConfig?.jwt) return {};
102
+ const { aud = "" } = xfeConfig.jwt;
103
+ 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");
104
+ const jwkRes = await fetch(`https://app.eshetang.com/jwk?appId=${aud}`);
105
+ if (!jwkRes.ok) {
106
+ throw new Error(`\u8FDC\u7A0B\u83B7\u53D6\u5BC6\u94A5\u5931\u8D25: ${jwkRes.status} ${jwkRes.statusText}`);
107
+ }
108
+ let JwkResponseJson;
109
+ try {
110
+ JwkResponseJson = await jwkRes.json();
111
+ } catch (err) {
112
+ 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()}`);
113
+ }
114
+ const { keyId, privateKeyPkcs8 } = JwkResponseJson?.data || {};
115
+ if (!keyId || !privateKeyPkcs8) throw new Error(`\u672A\u83B7\u53D6\u5230\u9879\u76EE\u7B7E\u540D\u5BC6\u94A5, \u8BF7\u68C0\u67E5aud\u662F\u5426\u6B63\u786E: ${aud}`);
116
+ return { XFE_JWT_AUD: aud, XFE_JWT_KEY_ID: keyId, XFE_JWT_PRIVATE_KEY: privateKeyPkcs8 };
117
+ };
118
+ export {
119
+ configDeploy,
120
+ getBuildDirectory,
121
+ getJwtEnv,
122
+ getServerEntry,
123
+ loadXfeConfig
124
+ };
@@ -0,0 +1,10 @@
1
+ type FrameworkPaths = {
2
+ appDirectory: string;
3
+ rootDirectory: string;
4
+ viteConfig: string;
5
+ typeScriptConfig: string;
6
+ };
7
+ declare const getFrameworkRoot: (projectRoot: string) => string;
8
+ declare const prepareFramework: (projectRoot?: string) => FrameworkPaths;
9
+
10
+ export { type FrameworkPaths, getFrameworkRoot, prepareFramework };
@@ -0,0 +1,10 @@
1
+ type FrameworkPaths = {
2
+ appDirectory: string;
3
+ rootDirectory: string;
4
+ viteConfig: string;
5
+ typeScriptConfig: string;
6
+ };
7
+ declare const getFrameworkRoot: (projectRoot: string) => string;
8
+ declare const prepareFramework: (projectRoot?: string) => FrameworkPaths;
9
+
10
+ export { type FrameworkPaths, getFrameworkRoot, prepareFramework };
@@ -0,0 +1,220 @@
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/framework.ts
31
+ var framework_exports = {};
32
+ __export(framework_exports, {
33
+ getFrameworkRoot: () => getFrameworkRoot,
34
+ prepareFramework: () => prepareFramework
35
+ });
36
+ module.exports = __toCommonJS(framework_exports);
37
+ var import_node_fs2 = __toESM(require("fs"));
38
+ var import_node_module = require("module");
39
+ var import_node_path2 = __toESM(require("path"));
40
+ var import_node_url2 = require("url");
41
+
42
+ // src/config.ts
43
+ var import_node_fs = __toESM(require("fs"));
44
+ var import_node_path = __toESM(require("path"));
45
+ var import_node_url = require("url");
46
+ var import_yaml = __toESM(require("yaml"));
47
+ var import_meta = {};
48
+ var DEFAULT_BUILD_DIRECTORY = "dist";
49
+ var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
50
+ var configDirectory = typeof __dirname === "string" ? __dirname : import_node_path.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
51
+ var loadXfeConfig = (root = process.cwd()) => {
52
+ const xfeConfigPath = import_node_path.default.join(root, "xfe.json");
53
+ if (!import_node_fs.default.existsSync(xfeConfigPath)) {
54
+ 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");
55
+ }
56
+ const xfeConfigContent = import_node_fs.default.readFileSync(xfeConfigPath, "utf8");
57
+ const config = JSON.parse(xfeConfigContent);
58
+ const renderMode = config.webapp?.renderMode;
59
+ if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
60
+ throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
61
+ }
62
+ getBuildDirectory(root, config.webapp);
63
+ getServerEntry(root, config.webapp);
64
+ return config;
65
+ };
66
+ var getBuildDirectory = (projectRoot, webapp = {}) => {
67
+ const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
68
+ if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
69
+ throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
70
+ }
71
+ const directory = configured.trim().replaceAll("\\", "/");
72
+ const root = import_node_path.default.resolve(projectRoot);
73
+ const output = import_node_path.default.resolve(root, directory);
74
+ const relative = import_node_path.default.relative(root, output);
75
+ const [firstDirectory = ""] = relative.split(import_node_path.default.sep);
76
+ const escapesProject = import_node_path.default.isAbsolute(directory) || Boolean(import_node_path.default.win32.parse(directory).root) || firstDirectory === "..";
77
+ const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
78
+ if (escapesProject || overwritesInput) {
79
+ 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");
80
+ }
81
+ let currentDirectory = root;
82
+ for (const segment of relative.split(import_node_path.default.sep)) {
83
+ currentDirectory = import_node_path.default.join(currentDirectory, segment);
84
+ if (import_node_fs.default.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
85
+ throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
86
+ }
87
+ }
88
+ return output;
89
+ };
90
+ var getServerEntry = (projectRoot, webapp = {}) => {
91
+ const entry = webapp?.serverEntry;
92
+ if (entry === void 0) return;
93
+ if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
94
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
95
+ }
96
+ const normalized = entry.trim().replaceAll("\\", "/");
97
+ const absolute = import_node_path.default.resolve(projectRoot, normalized);
98
+ const relative = import_node_path.default.relative(import_node_path.default.resolve(projectRoot), absolute);
99
+ const outside = Boolean(import_node_path.default.win32.parse(normalized).root) || relative.split(import_node_path.default.sep)[0] === "..";
100
+ if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
101
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
102
+ }
103
+ return absolute;
104
+ };
105
+
106
+ // src/framework.ts
107
+ var import_meta2 = {};
108
+ var frameworkDirectory = typeof __dirname === "string" ? __dirname : import_node_path2.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
109
+ var requireFromFramework = (0, import_node_module.createRequire)(import_node_path2.default.join(frameworkDirectory, "framework.js"));
110
+ var extensions = [".tsx", ".ts", ".jsx", ".js"];
111
+ var findSource = (directory, name) => extensions.map((extension) => import_node_path2.default.join(directory, `${name}${extension}`)).find(import_node_fs2.default.existsSync);
112
+ 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(
113
+ ([, name]) => name
114
+ );
115
+ var importPath = (from, target) => {
116
+ const relative = import_node_path2.default.relative(from, target).replace(import_node_path2.default.extname(target), "").replaceAll(import_node_path2.default.sep, "/");
117
+ return relative.startsWith(".") ? relative : `./${relative}`;
118
+ };
119
+ var writeGenerated = (file, content) => {
120
+ if (import_node_fs2.default.existsSync(file) && import_node_fs2.default.readFileSync(file, "utf8") === content) return;
121
+ import_node_fs2.default.writeFileSync(file, content);
122
+ };
123
+ var defaultRootSource = (projectRoot, appDirectory) => {
124
+ const { webapp = {} } = loadXfeConfig(projectRoot);
125
+ const layoutSource = findSource(import_node_path2.default.join(projectRoot, "src"), "layout");
126
+ const layoutExports = layoutSource ? findValueExports(layoutSource) : [];
127
+ const hasErrorView = layoutExports.includes("ErrorView");
128
+ const layoutImport = layoutSource ? `import AppLayout${hasErrorView ? ", { ErrorView }" : ""} from ${JSON.stringify(importPath(appDirectory, layoutSource))}
129
+ ` : "";
130
+ return `import { createElement, type ReactNode } from 'react'
131
+ import { Outlet } from 'react-router'
132
+ import { Document, PageError, PageLoading } from '@xfe-repo/web-app/dist/root.mjs'
133
+ ${layoutImport}
134
+ export const meta = () => [{ title: ${JSON.stringify(webapp.title || "XFE App")} }]
135
+ export const Layout = ({ children }: { children: ReactNode }) => createElement(Document, { children, lang: ${JSON.stringify(webapp.lang || "zh-CN")}, themeColor: ${JSON.stringify(webapp.themeColor)} })
136
+ export default function Root() { return ${layoutSource ? "createElement(AppLayout, { children: createElement(Outlet) })" : "createElement(Outlet)"} }
137
+ export function ErrorBoundary() { return createElement(PageError, { ${hasErrorView ? "view: ErrorView" : ""} }) }
138
+ export function HydrateFallback() { return createElement(PageLoading) }
139
+ `;
140
+ };
141
+ var getFrameworkRoot = (projectRoot) => import_node_path2.default.join(projectRoot, "node_modules/.cache/xfe-web/react-router");
142
+ var prepareFramework = (projectRoot = process.cwd()) => {
143
+ const sourceDirectory = import_node_path2.default.join(projectRoot, "src");
144
+ const rootSource = findSource(sourceDirectory, "root");
145
+ const appServerSource = findSource(sourceDirectory, "app.server");
146
+ const pagesSource = import_node_path2.default.join(sourceDirectory, "pages");
147
+ if (!import_node_fs2.default.existsSync(pagesSource)) throw new Error("\u672A\u627E\u5230 src/pages");
148
+ const rootDirectory = getFrameworkRoot(projectRoot);
149
+ const appDirectory = import_node_path2.default.join(rootDirectory, "app");
150
+ import_node_fs2.default.mkdirSync(appDirectory, { recursive: true });
151
+ const routerDirectory = import_node_path2.default.dirname(requireFromFramework.resolve("react-router/package.json"));
152
+ const routerLink = import_node_path2.default.join(rootDirectory, "node_modules/react-router");
153
+ import_node_fs2.default.mkdirSync(import_node_path2.default.dirname(routerLink), { recursive: true });
154
+ if (!import_node_fs2.default.lstatSync(routerLink, { throwIfNoEntry: false })?.isSymbolicLink() || import_node_fs2.default.readlinkSync(routerLink) !== routerDirectory) {
155
+ import_node_fs2.default.rmSync(routerLink, { force: true });
156
+ import_node_fs2.default.symlinkSync(routerDirectory, routerLink, "junction");
157
+ }
158
+ const rootTarget = import_node_path2.default.join(appDirectory, "root.tsx");
159
+ const rootImport = rootSource ? importPath(appDirectory, rootSource) : "";
160
+ const rootExports = rootSource ? findValueExports(rootSource).filter((name) => name !== "middleware" || !appServerSource) : [];
161
+ const namedExports = rootExports.length ? `export { ${rootExports.join(", ")} } from ${JSON.stringify(rootImport)}
162
+ ` : "";
163
+ const errorBoundaryExport = rootExports.includes("ErrorBoundary") ? "" : "export { DefaultErrorBoundary as ErrorBoundary } from '@xfe-repo/web-router/errors'\n";
164
+ const middlewareExport = appServerSource ? `export { middleware } from ${JSON.stringify(importPath(appDirectory, appServerSource))}
165
+ ` : "";
166
+ writeGenerated(
167
+ rootTarget,
168
+ rootSource ? `export * from ${JSON.stringify(rootImport)}
169
+ export { default } from ${JSON.stringify(rootImport)}
170
+ ${namedExports}${errorBoundaryExport}${middlewareExport}` : `${defaultRootSource(projectRoot, appDirectory)}${middlewareExport}`
171
+ );
172
+ const pagesLink = import_node_path2.default.join(appDirectory, "pages");
173
+ if (!import_node_fs2.default.existsSync(pagesLink)) import_node_fs2.default.symlinkSync(import_node_path2.default.relative(appDirectory, pagesSource), pagesLink, "dir");
174
+ writeGenerated(
175
+ import_node_path2.default.join(rootDirectory, "react-router.config.js"),
176
+ "export { default } from '@xfe-repo/web-app/dist/react-router-config.mjs'\n"
177
+ );
178
+ writeGenerated(
179
+ import_node_path2.default.join(appDirectory, "routes.js"),
180
+ `import { collectPageRoutes } from '@xfe-repo/web-router/routes'
181
+ export default collectPageRoutes(${JSON.stringify(appDirectory)})
182
+ `
183
+ );
184
+ const defaultsDirectory = import_node_path2.default.join(import_node_path2.default.dirname(requireFromFramework.resolve("@react-router/dev/package.json")), "dist/config/defaults");
185
+ writeGenerated(
186
+ import_node_path2.default.join(appDirectory, "entry.server.tsx"),
187
+ `export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory, import_node_path2.default.join(defaultsDirectory, "entry.server.web.tsx")))}
188
+ `
189
+ );
190
+ const typeScriptConfig = import_node_path2.default.join(rootDirectory, "tsconfig.json");
191
+ writeGenerated(
192
+ typeScriptConfig,
193
+ JSON.stringify(
194
+ {
195
+ extends: import_node_path2.default.join(projectRoot, "tsconfig.json"),
196
+ compilerOptions: { rootDirs: [projectRoot, rootDirectory, import_node_path2.default.join(rootDirectory, ".react-router/types")] },
197
+ include: [
198
+ import_node_path2.default.join(sourceDirectory, "**/*"),
199
+ import_node_path2.default.join(projectRoot, "types/**/*"),
200
+ import_node_path2.default.join(appDirectory, "*.tsx"),
201
+ import_node_path2.default.join(rootDirectory, ".react-router/types/**/*")
202
+ ],
203
+ exclude: []
204
+ },
205
+ null,
206
+ 2
207
+ )
208
+ );
209
+ return {
210
+ appDirectory,
211
+ rootDirectory,
212
+ viteConfig: import_node_path2.default.resolve(frameworkDirectory, "vite.mjs"),
213
+ typeScriptConfig
214
+ };
215
+ };
216
+ // Annotate the CommonJS export names for ESM import in node:
217
+ 0 && (module.exports = {
218
+ getFrameworkRoot,
219
+ prepareFramework
220
+ });
@@ -0,0 +1,182 @@
1
+ // src/framework.ts
2
+ import fs2 from "fs";
3
+ import { createRequire } from "module";
4
+ import path2 from "path";
5
+ import { fileURLToPath as fileURLToPath2 } from "url";
6
+
7
+ // src/config.ts
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { fileURLToPath } from "url";
11
+ import yaml from "yaml";
12
+ var DEFAULT_BUILD_DIRECTORY = "dist";
13
+ var protectedDirectories = /* @__PURE__ */ new Set(["src", "types", "public", "node_modules", ".git"]);
14
+ var configDirectory = typeof __dirname === "string" ? __dirname : path.dirname(fileURLToPath(import.meta.url));
15
+ var loadXfeConfig = (root = process.cwd()) => {
16
+ const xfeConfigPath = path.join(root, "xfe.json");
17
+ if (!fs.existsSync(xfeConfigPath)) {
18
+ 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");
19
+ }
20
+ const xfeConfigContent = fs.readFileSync(xfeConfigPath, "utf8");
21
+ const config = JSON.parse(xfeConfigContent);
22
+ const renderMode = config.webapp?.renderMode;
23
+ if (renderMode !== void 0 && renderMode !== "client" && renderMode !== "server") {
24
+ throw new Error("xfe.json.webapp.renderMode \u53EA\u80FD\u4E3A client \u6216 server");
25
+ }
26
+ getBuildDirectory(root, config.webapp);
27
+ getServerEntry(root, config.webapp);
28
+ return config;
29
+ };
30
+ var getBuildDirectory = (projectRoot, webapp = {}) => {
31
+ const configured = webapp?.buildDirectory === void 0 ? DEFAULT_BUILD_DIRECTORY : webapp.buildDirectory;
32
+ if (typeof configured !== "string" || !configured.trim() || /[\0\r\n]/.test(configured)) {
33
+ throw new Error("xfe.json.webapp.buildDirectory \u5FC5\u987B\u662F\u975E\u7A7A\u7684\u5355\u884C\u5B57\u7B26\u4E32");
34
+ }
35
+ const directory = configured.trim().replaceAll("\\", "/");
36
+ const root = path.resolve(projectRoot);
37
+ const output = path.resolve(root, directory);
38
+ const relative = path.relative(root, output);
39
+ const [firstDirectory = ""] = relative.split(path.sep);
40
+ const escapesProject = path.isAbsolute(directory) || Boolean(path.win32.parse(directory).root) || firstDirectory === "..";
41
+ const overwritesInput = !relative || protectedDirectories.has(firstDirectory.toLowerCase());
42
+ if (escapesProject || overwritesInput) {
43
+ 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");
44
+ }
45
+ let currentDirectory = root;
46
+ for (const segment of relative.split(path.sep)) {
47
+ currentDirectory = path.join(currentDirectory, segment);
48
+ if (fs.lstatSync(currentDirectory, { throwIfNoEntry: false })?.isSymbolicLink()) {
49
+ throw new Error("xfe.json.webapp.buildDirectory \u4E0D\u80FD\u7ECF\u8FC7\u7B26\u53F7\u94FE\u63A5\uFF0C\u4EE5\u514D\u6E05\u7406\u5176\u4ED6\u76EE\u5F55");
50
+ }
51
+ }
52
+ return output;
53
+ };
54
+ var getServerEntry = (projectRoot, webapp = {}) => {
55
+ const entry = webapp?.serverEntry;
56
+ if (entry === void 0) return;
57
+ if (typeof entry !== "string" || !entry.trim() || /[\0\r\n]/.test(entry)) {
58
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
59
+ }
60
+ const normalized = entry.trim().replaceAll("\\", "/");
61
+ const absolute = path.resolve(projectRoot, normalized);
62
+ const relative = path.relative(path.resolve(projectRoot), absolute);
63
+ const outside = Boolean(path.win32.parse(normalized).root) || relative.split(path.sep)[0] === "..";
64
+ if (outside || !/\.(?:[jt]sx?|m[jt]s)$/.test(relative)) {
65
+ throw new Error("xfe.json.webapp.serverEntry \u5FC5\u987B\u662F\u9879\u76EE\u5185\u7684 TypeScript / JavaScript \u76F8\u5BF9\u8DEF\u5F84");
66
+ }
67
+ return absolute;
68
+ };
69
+
70
+ // src/framework.ts
71
+ var frameworkDirectory = typeof __dirname === "string" ? __dirname : path2.dirname(fileURLToPath2(import.meta.url));
72
+ var requireFromFramework = createRequire(path2.join(frameworkDirectory, "framework.js"));
73
+ var extensions = [".tsx", ".ts", ".jsx", ".js"];
74
+ var findSource = (directory, name) => extensions.map((extension) => path2.join(directory, `${name}${extension}`)).find(fs2.existsSync);
75
+ 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(
76
+ ([, name]) => name
77
+ );
78
+ var importPath = (from, target) => {
79
+ const relative = path2.relative(from, target).replace(path2.extname(target), "").replaceAll(path2.sep, "/");
80
+ return relative.startsWith(".") ? relative : `./${relative}`;
81
+ };
82
+ var writeGenerated = (file, content) => {
83
+ if (fs2.existsSync(file) && fs2.readFileSync(file, "utf8") === content) return;
84
+ fs2.writeFileSync(file, content);
85
+ };
86
+ var defaultRootSource = (projectRoot, appDirectory) => {
87
+ const { webapp = {} } = loadXfeConfig(projectRoot);
88
+ const layoutSource = findSource(path2.join(projectRoot, "src"), "layout");
89
+ const layoutExports = layoutSource ? findValueExports(layoutSource) : [];
90
+ const hasErrorView = layoutExports.includes("ErrorView");
91
+ const layoutImport = layoutSource ? `import AppLayout${hasErrorView ? ", { ErrorView }" : ""} from ${JSON.stringify(importPath(appDirectory, layoutSource))}
92
+ ` : "";
93
+ return `import { createElement, type ReactNode } from 'react'
94
+ import { Outlet } from 'react-router'
95
+ import { Document, PageError, PageLoading } from '@xfe-repo/web-app/dist/root.mjs'
96
+ ${layoutImport}
97
+ export const meta = () => [{ title: ${JSON.stringify(webapp.title || "XFE App")} }]
98
+ export const Layout = ({ children }: { children: ReactNode }) => createElement(Document, { children, lang: ${JSON.stringify(webapp.lang || "zh-CN")}, themeColor: ${JSON.stringify(webapp.themeColor)} })
99
+ export default function Root() { return ${layoutSource ? "createElement(AppLayout, { children: createElement(Outlet) })" : "createElement(Outlet)"} }
100
+ export function ErrorBoundary() { return createElement(PageError, { ${hasErrorView ? "view: ErrorView" : ""} }) }
101
+ export function HydrateFallback() { return createElement(PageLoading) }
102
+ `;
103
+ };
104
+ var getFrameworkRoot = (projectRoot) => path2.join(projectRoot, "node_modules/.cache/xfe-web/react-router");
105
+ var prepareFramework = (projectRoot = process.cwd()) => {
106
+ const sourceDirectory = path2.join(projectRoot, "src");
107
+ const rootSource = findSource(sourceDirectory, "root");
108
+ const appServerSource = findSource(sourceDirectory, "app.server");
109
+ const pagesSource = path2.join(sourceDirectory, "pages");
110
+ if (!fs2.existsSync(pagesSource)) throw new Error("\u672A\u627E\u5230 src/pages");
111
+ const rootDirectory = getFrameworkRoot(projectRoot);
112
+ const appDirectory = path2.join(rootDirectory, "app");
113
+ fs2.mkdirSync(appDirectory, { recursive: true });
114
+ const routerDirectory = path2.dirname(requireFromFramework.resolve("react-router/package.json"));
115
+ const routerLink = path2.join(rootDirectory, "node_modules/react-router");
116
+ fs2.mkdirSync(path2.dirname(routerLink), { recursive: true });
117
+ if (!fs2.lstatSync(routerLink, { throwIfNoEntry: false })?.isSymbolicLink() || fs2.readlinkSync(routerLink) !== routerDirectory) {
118
+ fs2.rmSync(routerLink, { force: true });
119
+ fs2.symlinkSync(routerDirectory, routerLink, "junction");
120
+ }
121
+ const rootTarget = path2.join(appDirectory, "root.tsx");
122
+ const rootImport = rootSource ? importPath(appDirectory, rootSource) : "";
123
+ const rootExports = rootSource ? findValueExports(rootSource).filter((name) => name !== "middleware" || !appServerSource) : [];
124
+ const namedExports = rootExports.length ? `export { ${rootExports.join(", ")} } from ${JSON.stringify(rootImport)}
125
+ ` : "";
126
+ const errorBoundaryExport = rootExports.includes("ErrorBoundary") ? "" : "export { DefaultErrorBoundary as ErrorBoundary } from '@xfe-repo/web-router/errors'\n";
127
+ const middlewareExport = appServerSource ? `export { middleware } from ${JSON.stringify(importPath(appDirectory, appServerSource))}
128
+ ` : "";
129
+ writeGenerated(
130
+ rootTarget,
131
+ rootSource ? `export * from ${JSON.stringify(rootImport)}
132
+ export { default } from ${JSON.stringify(rootImport)}
133
+ ${namedExports}${errorBoundaryExport}${middlewareExport}` : `${defaultRootSource(projectRoot, appDirectory)}${middlewareExport}`
134
+ );
135
+ const pagesLink = path2.join(appDirectory, "pages");
136
+ if (!fs2.existsSync(pagesLink)) fs2.symlinkSync(path2.relative(appDirectory, pagesSource), pagesLink, "dir");
137
+ writeGenerated(
138
+ path2.join(rootDirectory, "react-router.config.js"),
139
+ "export { default } from '@xfe-repo/web-app/dist/react-router-config.mjs'\n"
140
+ );
141
+ writeGenerated(
142
+ path2.join(appDirectory, "routes.js"),
143
+ `import { collectPageRoutes } from '@xfe-repo/web-router/routes'
144
+ export default collectPageRoutes(${JSON.stringify(appDirectory)})
145
+ `
146
+ );
147
+ const defaultsDirectory = path2.join(path2.dirname(requireFromFramework.resolve("@react-router/dev/package.json")), "dist/config/defaults");
148
+ writeGenerated(
149
+ path2.join(appDirectory, "entry.server.tsx"),
150
+ `export { default, streamTimeout } from ${JSON.stringify(importPath(appDirectory, path2.join(defaultsDirectory, "entry.server.web.tsx")))}
151
+ `
152
+ );
153
+ const typeScriptConfig = path2.join(rootDirectory, "tsconfig.json");
154
+ writeGenerated(
155
+ typeScriptConfig,
156
+ JSON.stringify(
157
+ {
158
+ extends: path2.join(projectRoot, "tsconfig.json"),
159
+ compilerOptions: { rootDirs: [projectRoot, rootDirectory, path2.join(rootDirectory, ".react-router/types")] },
160
+ include: [
161
+ path2.join(sourceDirectory, "**/*"),
162
+ path2.join(projectRoot, "types/**/*"),
163
+ path2.join(appDirectory, "*.tsx"),
164
+ path2.join(rootDirectory, ".react-router/types/**/*")
165
+ ],
166
+ exclude: []
167
+ },
168
+ null,
169
+ 2
170
+ )
171
+ );
172
+ return {
173
+ appDirectory,
174
+ rootDirectory,
175
+ viteConfig: path2.resolve(frameworkDirectory, "vite.mjs"),
176
+ typeScriptConfig
177
+ };
178
+ };
179
+ export {
180
+ getFrameworkRoot,
181
+ prepareFramework
182
+ };
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,2 @@
1
+
2
+ export { }