70 lines
2.3 KiB
JavaScript
70 lines
2.3 KiB
JavaScript
import { spawn } from 'node:child_process';
|
|
import { createRequire } from 'node:module';
|
|
import { createInterface } from 'node:readline';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const child = spawn(
|
|
process.execPath,
|
|
[require.resolve('@nestjs/cli/bin/nest.js'), 'start', '--watch'],
|
|
{
|
|
env: { ...process.env, DOODLE_DEV_LAUNCHER: '1' },
|
|
stdio: ['inherit', 'pipe', 'inherit'],
|
|
},
|
|
);
|
|
let opened = false;
|
|
|
|
/** 使用系统默认浏览器,不经 shell 拼接 URL;打开失败不影响开发服务继续运行。 */
|
|
function openBrowser(url) {
|
|
const command =
|
|
process.platform === 'darwin'
|
|
? 'open'
|
|
: process.platform === 'win32'
|
|
? 'explorer.exe'
|
|
: 'xdg-open';
|
|
const browser = spawn(command, [url], { stdio: 'ignore', detached: true });
|
|
const warn = () =>
|
|
process.stderr.write(`无法自动打开浏览器,请手动访问:${url}\n`);
|
|
browser.once('error', warn);
|
|
browser.once('exit', (code) => {
|
|
if (code !== 0 && code !== null) warn();
|
|
});
|
|
browser.unref();
|
|
}
|
|
|
|
// 只在本次启动器收到子服务的成功通知后打开;热更新重启不会反复弹出页面。
|
|
const lines = createInterface({ input: child.stdout });
|
|
lines.on('line', (line) => {
|
|
let event;
|
|
try {
|
|
event = JSON.parse(line);
|
|
} catch {
|
|
/* Nest 编译提示不是 JSON,原样转发。 */
|
|
}
|
|
if (event?.event !== 'doodle-dev-ready') {
|
|
process.stdout.write(`${line}\n`);
|
|
return;
|
|
}
|
|
if (!event.swaggerUrl) {
|
|
process.stdout.write('\nSwagger 已关闭(SWAGGER_ENABLED=false)。\n\n');
|
|
return;
|
|
}
|
|
process.stdout.write(`\nSwagger: ${event.swaggerUrl}\n\n`);
|
|
if (!opened) {
|
|
opened = true;
|
|
openBrowser(event.swaggerUrl);
|
|
}
|
|
});
|
|
|
|
// 退出启动器时将信号传给 Nest,保留其对子服务的正常关闭和端口释放流程。
|
|
for (const signal of ['SIGINT', 'SIGTERM'])
|
|
process.on(signal, () => child.kill(signal));
|
|
child.once('error', () => {
|
|
process.stderr.write('开发服务启动失败,请检查本地 Node.js 与项目依赖。\n');
|
|
process.exitCode = 1;
|
|
});
|
|
child.once('exit', (code, signal) => {
|
|
lines.close();
|
|
process.exitCode =
|
|
code ?? (signal === 'SIGINT' ? 130 : signal === 'SIGTERM' ? 143 : 1);
|
|
});
|