补充客户端打包入口配置

This commit is contained in:
cat-shark
2026-06-20 18:38:49 +08:00
parent 4d7a19dc8a
commit a180295b3b
3 changed files with 174 additions and 1 deletions
+1
View File
@@ -27,6 +27,7 @@
"dev:electron": "concurrently \"set AUTH_SERVER_URL=http://127.0.0.1:3302&& set VITE_DEV_SERVER_URL=http://127.0.0.1:3354&& set EXTERNAL_ELECTRON_DEV=1&& vite --host 127.0.0.1 --port 3354 --strictPort\" \"set AUTH_SERVER_URL=http://127.0.0.1:3302&& set VITE_DEV_SERVER_URL=http://127.0.0.1:3354&& node scripts/dev-electron.cjs\"",
"prepare-package": "node apply-oem.cjs && py -3 scripts/export-runtime-system-templates.py && node scripts/prepare-package.cjs",
"build:win": "npm run prepare-package && npm run build && node scripts/build-resource-artifacts.cjs && electron-builder --win --x64 && node scripts/fix-latest-yml.cjs && node scripts/assemble-release-artifacts.cjs",
"build:client:win": "node scripts/package-client.cjs",
"build:win:only": "electron-builder --win --x64",
"build:mac": "npm run prepare-package && npm run typecheck && vite build && electron-builder --mac",
"postinstall": "electron-builder install-app-deps",
+163
View File
@@ -0,0 +1,163 @@
const path = require("node:path");
const { spawnSync } = require("node:child_process");
const projectRoot = path.resolve(__dirname, "..");
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
const electronBuilder = path.join(
projectRoot,
"node_modules",
".bin",
process.platform === "win32" ? "electron-builder.cmd" : "electron-builder",
);
function usage() {
console.log(`
客户端打包脚本(不包含认证服务/管理后台)
用法:
npm.cmd run build:client:win -- --auth-url=https://auth.example.com
npm.cmd run build:client:win -- --auth-url=http://127.0.0.1:3302 --dry-run
参数:
--auth-url <url> 认证服务地址,可带或不带 /api
--dir 只打包目录,不生成安装包
--dry-run 只打印将执行的命令,不真正打包
--help 显示帮助
`);
}
function readArg(name) {
const prefix = `${name}=`;
const inline = process.argv.find(arg => arg.startsWith(prefix));
if (inline) return inline.slice(prefix.length);
const index = process.argv.indexOf(name);
if (index >= 0) return process.argv[index + 1];
return "";
}
function hasArg(name) {
return process.argv.includes(name);
}
function normalizeAuthUrl(value) {
const raw = String(value || "").trim();
if (!raw) return "";
if (/^https?\/\//i.test(raw)) {
throw new Error(`认证服务地址无效,协议后缺少冒号:${raw}`);
}
let parsed;
try {
parsed = new URL(raw);
} catch {
throw new Error(`认证服务地址无效:${raw}`);
}
if (!["http:", "https:"].includes(parsed.protocol)) {
throw new Error(`认证服务地址只支持 http 或 https:${raw}`);
}
if (["http", "https"].includes(parsed.hostname) && parsed.pathname.startsWith("//")) {
throw new Error(`认证服务地址疑似多写了协议,请检查:${raw}`);
}
if (!parsed.hostname || parsed.hostname.includes("/")) {
throw new Error(`认证服务地址主机名无效:${raw}`);
}
parsed.pathname = parsed.pathname.replace(/\/api\/?$/i, "").replace(/\/+$/, "");
parsed.search = "";
parsed.hash = "";
return parsed.toString().replace(/\/+$/, "");
}
function quoteDisplay(value) {
const text = String(value);
return /\s/.test(text) ? `"${text}"` : text;
}
function quoteCmdArg(value) {
const text = String(value);
if (!/[ \t"&|<>^]/.test(text)) return text;
return `"${text.replace(/"/g, '""')}"`;
}
function isWindowsCmd(command) {
return process.platform === "win32" && /\.(cmd|bat)$/i.test(command);
}
function run(command, args, env, dryRun) {
const display = [command, ...args].map(quoteDisplay).join(" ");
console.log(`[package-client] ${display}`);
if (dryRun) return;
const spawnCommand = isWindowsCmd(command)
? (process.env.ComSpec || "cmd.exe")
: command;
const spawnArgs = isWindowsCmd(command)
? ["/d", "/s", "/c", [quoteCmdArg(command), ...args.map(quoteCmdArg)].join(" ")]
: args;
const result = spawnSync(spawnCommand, spawnArgs, {
cwd: projectRoot,
stdio: "inherit",
env,
shell: false,
});
if (result.error) {
throw result.error;
}
if (result.status !== 0) {
throw new Error(`命令执行失败:${display}`);
}
}
function main() {
if (hasArg("--help") || hasArg("-h")) {
usage();
return;
}
const authUrl = normalizeAuthUrl(
readArg("--auth-url") ||
process.env.PACKAGE_AUTH_SERVER_URL ||
process.env.AUTH_SERVER_URL ||
process.env.VITE_AUTH_SERVER_URL,
);
const dryRun = hasArg("--dry-run");
const dirOnly = hasArg("--dir");
if (!authUrl) {
usage();
throw new Error("打包客户端必须指定认证服务地址:--auth-url=https://auth.example.com");
}
const env = {
...process.env,
AUTH_SERVER_URL: authUrl,
VITE_AUTH_SERVER_URL: authUrl,
PACKAGE_CLIENT_ONLY: "1",
};
console.log(`[package-client] 认证服务地址:${authUrl}`);
console.log("[package-client] 本脚本只打包客户端,不会启动或打包本地认证服务。");
run(npmCommand, ["run", "prepare-package"], env, dryRun);
run(npmCommand, ["run", "build"], env, dryRun);
run(process.execPath, ["scripts/build-resource-artifacts.cjs"], env, dryRun);
run(electronBuilder, ["--win", "--x64", ...(dirOnly ? ["--dir"] : [])], env, dryRun);
if (!dirOnly) {
run(process.execPath, ["scripts/fix-latest-yml.cjs"], env, dryRun);
run(process.execPath, ["scripts/assemble-release-artifacts.cjs"], env, dryRun);
}
}
try {
main();
} catch (error) {
console.error(`[package-client] ${error.message}`);
process.exit(1);
}
+10 -1
View File
@@ -3,6 +3,15 @@ import packageJson from "../package.json";
// import {TimeUtil} from "../electron/lib/util"; // ❌ 这是 Node.js 版本,会被打包到渲染进程
const BASE_URL = "";
const viteEnv = import.meta.env || {};
const processEnv = (typeof process !== "undefined" ? process.env : {}) as Record<string, string | undefined>;
const authServerUrl = viteEnv.VITE_AUTH_SERVER_URL || processEnv.AUTH_SERVER_URL || "http://127.0.0.1:3302";
function normalizeApiBaseUrl(url: string): string {
const trimmed = String(url || "").trim().replace(/\/+$/, "");
if (!trimmed) return "http://127.0.0.1:3302/api";
return /\/api$/i.test(trimmed) ? trimmed : `${trimmed}/api`;
}
export const AppConfig = {
name: "天英超级IP智能体",
@@ -12,7 +21,7 @@ export const AppConfig = {
website: ``,
websiteGithub: "",
websiteGitee: "",
apiBaseUrl: `http://127.0.0.1:3302/api`,
apiBaseUrl: normalizeApiBaseUrl(authServerUrl),
updaterUrl: ``,
downloadUrl: ``,
feedbackUrl: ``,