Files
mnote/scripts/prepare-desktop-next.js
T

122 lines
4.1 KiB
JavaScript
Raw Normal View History

2026-01-15 20:54:21 +08:00
#!/usr/bin/env node
/**
* 生成桌面端内置的 Next standalone 产物到 `desktop-electron/desktop-next`。
*
* 目标:
* - 打包时不依赖用户机器上的 pnpm / node 环境即可运行(Electron 自身携带 Node)。
* - 运行期文件读写落到安装目录的 data/(由 Electron 注入 MNOTE_DATA_DIR)。
*
* 注意:需要 wolai-frontend 的 next.config.ts 开启 output: "standalone"。
*/
const { spawnSync } = require("child_process");
const fs = require("fs");
const path = require("path");
const rootDir = path.resolve(__dirname, "..");
const frontendDir = path.join(rootDir, "wolai-frontend");
const outDir = path.join(rootDir, "desktop-electron", "desktop-next");
function parseDotenv(filePath) {
if (!fs.existsSync(filePath)) return {};
const raw = fs.readFileSync(filePath, { encoding: "utf8" });
const out = {};
for (const line of raw.split(/\r?\n/)) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const idx = trimmed.indexOf("=");
if (idx === -1) continue;
const key = trimmed.slice(0, idx).trim();
const value = trimmed.slice(idx + 1).trim();
if (!key) continue;
out[key] = value;
}
return out;
}
function ensureDir(dir) {
fs.mkdirSync(dir, { recursive: true });
}
function rmDir(dir) {
fs.rmSync(dir, { recursive: true, force: true });
}
function run(command, cwd, env) {
const r = spawnSync(command, {
cwd,
env: { ...process.env, ...env },
stdio: "inherit",
shell: true,
});
if (r.status !== 0) {
process.exit(r.status ?? 1);
}
}
function assertExists(filePath, hint) {
if (!fs.existsSync(filePath)) {
console.error(`\n[prepare-desktop-next] 缺少:${filePath}`);
if (hint) console.error(`[prepare-desktop-next] 提示:${hint}`);
process.exit(1);
}
}
function copyDir(from, to) {
// 关键:Next standalone 在 pnpm 环境下可能包含大量 symlink/junction。
// electron-builder 在复制 extraResources 时对链接目录处理不稳定,
// 因此这里强制“解引用复制”,把真实文件复制出来,确保运行期能 require('next')。
fs.cpSync(from, to, { recursive: true, force: true, dereference: true });
}
function main() {
console.log("[prepare-desktop-next] 开始构建 wolai-frontendstandalone)…");
2026-02-01 08:47:40 +08:00
// 约定:全局仅使用仓库根目录的 .env.all 作为配置来源(生产优先)。
// 桌面端如需覆盖,可通过系统环境变量注入(例如在启动命令前临时设置)。
const envAllPath = path.join(rootDir, ".env.all");
assertExists(envAllPath, "请先在仓库根目录创建 .env.all(全局唯一 env 文件)。");
2026-01-15 20:54:21 +08:00
const desktopEnv = {
2026-02-01 08:47:40 +08:00
...parseDotenv(envAllPath),
2026-01-15 20:54:21 +08:00
};
console.log("[prepare-desktop-next] 桌面端 env 摘要:", {
NEXT_PUBLIC_BACKEND_URL: desktopEnv.NEXT_PUBLIC_BACKEND_URL,
NEXT_PUBLIC_ONLYOFFICE_BASE_URL: desktopEnv.NEXT_PUBLIC_ONLYOFFICE_BASE_URL,
});
run("pnpm -C wolai-frontend build", rootDir, {
NODE_ENV: "production",
NEXT_TELEMETRY_DISABLED: "1",
...desktopEnv,
});
const standaloneDir = path.join(frontendDir, ".next", "standalone");
const staticDir = path.join(frontendDir, ".next", "static");
const publicDir = path.join(frontendDir, "public");
assertExists(
path.join(standaloneDir, "server.js"),
'请在 wolai-frontend/next.config.ts 增加 `output: "standalone"` 后重试。',
);
assertExists(staticDir, "Next build 未生成 .next/static(可能构建失败或目录异常)。");
assertExists(publicDir, "wolai-frontend/public 不存在。");
console.log(`[prepare-desktop-next] 清理旧产物:${outDir}`);
rmDir(outDir);
ensureDir(outDir);
console.log("[prepare-desktop-next] 复制 standalone …");
copyDir(standaloneDir, outDir);
console.log("[prepare-desktop-next] 补齐 .next/static …");
ensureDir(path.join(outDir, ".next"));
copyDir(staticDir, path.join(outDir, ".next", "static"));
console.log("[prepare-desktop-next] 补齐 public …");
copyDir(publicDir, path.join(outDir, "public"));
console.log("[prepare-desktop-next] 完成。");
}
main();