Files

89 lines
3.6 KiB
JavaScript
Raw Permalink 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.
#!/usr/bin/env node
/**
* start-mock.mjs —— 无 VPN 一键离线演示(npm run dev:mock)。
*
* 做三件事(零第三方依赖,Node 20 自带 fetch):
* 1. 拉起 YschTheme 的本地静态通道 scripts/dev-serve.mjs(9527,/dist/pc 挂 /static/);
* 2. 探活 9527/static/manifest.json(若端口已被上次残留进程占用且可服务,同样放行);
* 3. 以 YH_THEME_PROXY_TARGET=http://localhost:9527 spawn vite --mode mock(8131)。
*
* 效果:浏览器访问 http://localhost:8131 —— 三页治理台账全量可演示(mock 数据),
* 主题 CSS/切换器经本地 9527 供给,全程不触网、不需要 VPN。
* 主题静态资源不拷进 front/public(应用侧不持主题副本是主题仓硬原则)。
* VPN 恢复后照旧 npm run dev 走真后端,两者互不影响。Ctrl+C 退出会一并收掉两个子进程。
*/
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const frontDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const themeDir = path.resolve(frontDir, "..", "..", "YschTheme");
const themeServeScript = path.join(themeDir, "scripts", "dev-serve.mjs");
const viteBin = path.join(frontDir, "node_modules", "vite", "bin", "vite.js");
const THEME_PORT = 9527;
const fail = (msg) => {
console.error(`[start-mock] ${msg}`);
process.exit(1);
};
if (!existsSync(themeServeScript)) {
fail(`找不到主题静态服务脚本 ${themeServeScript}(YschTheme 仓位置异常?)`);
}
if (!existsSync(viteBin)) {
fail(`找不到 ${viteBin}(先在 front 目录 npm install)`);
}
/* 1. 本地静态通道(YschTheme 零依赖实现,serve dist/pc 于 /static/) */
const themeServer = spawn(process.execPath, [themeServeScript], {
cwd: themeDir,
stdio: ["ignore", "pipe", "pipe"],
});
themeServer.stdout.on("data", (d) => process.stdout.write(`[theme] ${d}`));
themeServer.stderr.on("data", (d) => process.stderr.write(`[theme] ${d}`));
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function waitThemeReady(tries = 24) {
for (let i = 0; i < tries; i++) {
try {
const res = await fetch(`http://localhost:${THEME_PORT}/static/manifest.json`);
if (res.ok) return true;
} catch {
/* 尚未就绪/端口被占(占位进程若可服务也会在上面返回 ok) */
}
await sleep(250);
}
return false;
}
/* 2. 探活:主题通道就绪才起前端(演示强依赖主题 CSS) */
if (!(await waitThemeReady())) {
themeServer.kill();
fail(`9527 主题静态通道未就绪 —— 检查 ${themeServeScript} 与 YschTheme/dist/pc 是否存在(必要时先在 YschTheme 跑 npm run gen)`);
}
console.log(`[start-mock] 主题静态通道就绪 → http://localhost:${THEME_PORT}/static/`);
/* 3. vite --mode mock(dev server 8131;/static 代理由 YH_THEME_PROXY_TARGET 指向 9527) */
const vite = spawn(process.execPath, [viteBin, "--mode", "mock"], {
cwd: frontDir,
stdio: "inherit",
env: { ...process.env, YH_THEME_PROXY_TARGET: `http://localhost:${THEME_PORT}` },
});
const shutdown = () => {
vite.kill();
themeServer.kill();
};
vite.on("exit", (code) => {
themeServer.kill();
process.exit(code ?? 0);
});
themeServer.on("exit", () => {
/* 9527 若由残留进程提供则本子进程会因端口占用退出,探活已放行,不必终止演示 */
});
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => {
shutdown();
process.exit(0);
});