Files
WYF-koubo/scripts/start-local.cjs
T
2026-06-19 18:45:55 +08:00

133 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require("node:fs");
const path = require("node:path");
const net = require("node:net");
const { spawn, spawnSync } = require("node:child_process");
const projectRoot = path.resolve(__dirname, "..");
const serverUrl = process.env.VITE_DEV_SERVER_URL || "http://127.0.0.1:3354";
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
const requiredNodeMajor = 20;
const checkOnly = process.argv.includes("--check");
function log(message = "") {
process.stdout.write(`${message}\n`);
}
function fail(message) {
process.stderr.write(`\n[start-local] ${message}\n`);
process.exit(1);
}
function parseServerUrl(url) {
try {
return new URL(url);
} catch {
fail(`VITE_DEV_SERVER_URL 无效:${url}`);
}
}
function checkCommand(command, args, label) {
const result = spawnSync(command, args, {
cwd: projectRoot,
encoding: "utf8",
stdio: "pipe",
shell: process.platform === "win32",
});
if (result.error || result.status !== 0) {
fail(`未检测到 ${label},请先安装后再运行。`);
}
return (result.stdout || result.stderr || "").trim();
}
function checkNodeVersion() {
const major = Number(process.versions.node.split(".")[0]);
if (!Number.isFinite(major) || major < requiredNodeMajor) {
fail(`当前 Node.js 为 ${process.version},建议使用 .nvmrc 指定的 Node.js ${requiredNodeMajor}`);
}
}
function checkDependencies() {
const viteBin = path.join(projectRoot, "node_modules", ".bin", process.platform === "win32" ? "vite.cmd" : "vite");
const electronPackage = path.join(projectRoot, "node_modules", "electron", "package.json");
if (!fs.existsSync(viteBin) || !fs.existsSync(electronPackage)) {
fail("依赖尚未安装,请先执行:npm install");
}
}
function assertPortAvailable(host, port) {
return new Promise((resolve, reject) => {
const server = net.createServer();
server.once("error", error => {
if (error.code === "EADDRINUSE") {
reject(new Error(`端口 ${port} 已被占用,请先关闭已有 Vite/Electron 开发进程。`));
return;
}
reject(error);
});
server.once("listening", () => {
server.close(resolve);
});
server.listen(port, host);
});
}
async function main() {
process.chdir(projectRoot);
const parsedUrl = parseServerUrl(serverUrl);
const host = parsedUrl.hostname || "127.0.0.1";
const port = Number(parsedUrl.port || 3344);
log("========================================");
log(" 本地快速启动:Vite + Electron");
log("========================================");
log(`项目目录:${projectRoot}`);
log(`开发地址:${serverUrl}`);
log("");
checkNodeVersion();
const npmVersion = checkCommand(npmCommand, ["--version"], "npm");
checkDependencies();
await assertPortAvailable(host, port);
log(`Node.js${process.version}`);
log(`npm${npmVersion}`);
log("");
if (checkOnly) {
log("自检通过:可以执行 npm run start:local 或双击 start-local.bat 启动。");
return;
}
log("正在启动应用,关闭此窗口即可停止开发服务。");
log("");
const child = spawn(npmCommand, ["run", "dev:electron"], {
cwd: projectRoot,
stdio: "inherit",
env: {
...process.env,
VITE_DEV_SERVER_URL: serverUrl,
},
shell: process.platform === "win32",
});
child.on("exit", code => {
process.exit(code ?? 0);
});
child.on("error", error => {
fail(`启动失败:${error.message}`);
});
}
main().catch(error => {
fail(error.message);
});