152 lines
4.1 KiB
JavaScript
152 lines
4.1 KiB
JavaScript
import {spawn} from 'node:child_process';
|
|
import {existsSync, readFileSync} from 'node:fs';
|
|
import path from 'node:path';
|
|
import {fileURLToPath} from 'node:url';
|
|
|
|
const repoRoot = fileURLToPath(new URL('../', import.meta.url));
|
|
const envExamplePath = fileURLToPath(new URL('../.env.example', import.meta.url));
|
|
const envLocalPath = fileURLToPath(new URL('../.env.local', import.meta.url));
|
|
const caddyConfigPath = fileURLToPath(new URL('../tools/Caddyfile.dev', import.meta.url));
|
|
const distRoot = fileURLToPath(new URL('../dist/', import.meta.url));
|
|
const bundledCaddyExe = fileURLToPath(new URL('../tools/caddy.exe', import.meta.url));
|
|
|
|
function parseEnvContents(contents) {
|
|
return contents
|
|
.split(/\r?\n/u)
|
|
.reduce((envMap, rawLine) => {
|
|
const line = rawLine.trim();
|
|
if (!line || line.startsWith('#')) {
|
|
return envMap;
|
|
}
|
|
|
|
const separatorIndex = line.indexOf('=');
|
|
if (separatorIndex < 0) {
|
|
return envMap;
|
|
}
|
|
|
|
const key = line.slice(0, separatorIndex).trim();
|
|
let value = line.slice(separatorIndex + 1).trim();
|
|
|
|
if (
|
|
(value.startsWith('"') && value.endsWith('"')) ||
|
|
(value.startsWith("'") && value.endsWith("'"))
|
|
) {
|
|
value = value.slice(1, -1);
|
|
}
|
|
|
|
envMap[key] = value;
|
|
return envMap;
|
|
}, {});
|
|
}
|
|
|
|
function readEnvFile(filePath) {
|
|
if (!existsSync(filePath)) {
|
|
return {};
|
|
}
|
|
|
|
return parseEnvContents(readFileSync(filePath, 'utf8'));
|
|
}
|
|
|
|
function normalizePathForCaddy(filePath) {
|
|
return path.resolve(filePath).replace(/\\/gu, '/');
|
|
}
|
|
|
|
function resolveApiUpstream(env) {
|
|
return (
|
|
env.CADDY_API_UPSTREAM
|
|
|| env.NODE_SERVER_TARGET
|
|
|| 'http://127.0.0.1:8081'
|
|
);
|
|
}
|
|
|
|
function resolveCaddyBinary() {
|
|
if (process.platform === 'win32' && existsSync(bundledCaddyExe)) {
|
|
return bundledCaddyExe;
|
|
}
|
|
|
|
return process.platform === 'win32' ? 'caddy.exe' : 'caddy';
|
|
}
|
|
|
|
const mergedEnv = {
|
|
...readEnvFile(envExamplePath),
|
|
...readEnvFile(envLocalPath),
|
|
...process.env,
|
|
};
|
|
|
|
if (!existsSync(path.join(distRoot, 'index.html'))) {
|
|
console.error('[serve:caddy] dist/index.html 不存在,请先运行 npm run build:raw');
|
|
process.exit(1);
|
|
}
|
|
|
|
mergedEnv.CADDY_SITE_ROOT = mergedEnv.CADDY_SITE_ROOT || normalizePathForCaddy(distRoot);
|
|
mergedEnv.CADDY_PUBLIC_ROOT = mergedEnv.CADDY_PUBLIC_ROOT || normalizePathForCaddy(path.join(repoRoot, 'public'));
|
|
mergedEnv.CADDY_API_UPSTREAM = resolveApiUpstream(mergedEnv);
|
|
|
|
const caddyBinary = resolveCaddyBinary();
|
|
|
|
console.log('[serve:caddy] listen=:8080');
|
|
console.log(`[serve:caddy] CADDY_SITE_ROOT=${mergedEnv.CADDY_SITE_ROOT}`);
|
|
console.log(`[serve:caddy] CADDY_PUBLIC_ROOT=${mergedEnv.CADDY_PUBLIC_ROOT}`);
|
|
console.log(`[serve:caddy] CADDY_API_UPSTREAM=${mergedEnv.CADDY_API_UPSTREAM}`);
|
|
console.log(`[serve:caddy] config=${caddyConfigPath}`);
|
|
|
|
const caddyProcess = spawn(
|
|
caddyBinary,
|
|
['run', '--config', caddyConfigPath, '--adapter', 'caddyfile'],
|
|
{
|
|
cwd: repoRoot,
|
|
env: mergedEnv,
|
|
stdio: 'inherit',
|
|
shell: process.platform === 'win32' && !existsSync(bundledCaddyExe),
|
|
},
|
|
);
|
|
|
|
let shuttingDown = false;
|
|
|
|
function requestShutdown(code = 0) {
|
|
if (shuttingDown) {
|
|
return;
|
|
}
|
|
|
|
shuttingDown = true;
|
|
|
|
if (caddyProcess.exitCode === null) {
|
|
caddyProcess.kill('SIGTERM');
|
|
setTimeout(() => {
|
|
if (caddyProcess.exitCode === null) {
|
|
caddyProcess.kill('SIGKILL');
|
|
}
|
|
}, 2000).unref();
|
|
}
|
|
|
|
if (caddyProcess.exitCode !== null) {
|
|
process.exit(code);
|
|
}
|
|
}
|
|
|
|
caddyProcess.on('error', (error) => {
|
|
console.error('[serve:caddy] 启动 Caddy 失败', error);
|
|
process.exit(1);
|
|
});
|
|
|
|
caddyProcess.on('exit', (code, signal) => {
|
|
if (!shuttingDown) {
|
|
const resolvedExitCode = code ?? 1;
|
|
const signalSuffix = signal ? ` (${signal})` : '';
|
|
console.error(
|
|
`[serve:caddy] Caddy exited with code ${resolvedExitCode}${signalSuffix}`,
|
|
);
|
|
process.exit(resolvedExitCode);
|
|
}
|
|
});
|
|
|
|
process.on('SIGINT', () => {
|
|
console.log('[serve:caddy] received SIGINT, shutting down...');
|
|
requestShutdown(0);
|
|
});
|
|
|
|
process.on('SIGTERM', () => {
|
|
console.log('[serve:caddy] received SIGTERM, shutting down...');
|
|
requestShutdown(0);
|
|
});
|