Files
hertzbeat/web-next/scripts/standalone-server.mjs
T
Logic 2de48d2caa feat: complete HertzBeat 2.0 novice workflows
Refine entity, monitor, alert, settings, observability, and shared operator workflows; add scale guards, route compatibility, release validation, and Product Design coverage.

AI assistance: used for draft implementation and test iteration.\nHuman validation: Node 22 production build; 426 frontend files and 3,398 tests; 59-route matrix; release budget 7.84 MiB / 8.00 MiB; focused backend tests and Browser QA.\nRisk notes: local scale proof covers 2,005 entities; sustained concurrent-ingestion SLA remains deployment-specific.
2026-07-10 14:54:43 +08:00

142 lines
3.9 KiB
JavaScript

import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { cp, rm } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
const DEFAULT_PORT = '4200';
const DEFAULT_HOSTNAME = '0.0.0.0';
export function parseStartArgs(args, env = process.env) {
const parsed = {
port: env.PORT || DEFAULT_PORT,
hostname: env.HOSTNAME || DEFAULT_HOSTNAME
};
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if ((arg === '-p' || arg === '--port') && args[index + 1]) {
parsed.port = args[index + 1];
index += 1;
continue;
}
if (arg.startsWith('--port=')) {
parsed.port = arg.slice('--port='.length);
continue;
}
if ((arg === '-H' || arg === '--hostname' || arg === '--host') && args[index + 1]) {
parsed.hostname = args[index + 1];
index += 1;
continue;
}
if (arg.startsWith('--hostname=')) {
parsed.hostname = arg.slice('--hostname='.length);
continue;
}
if (arg.startsWith('--host=')) {
parsed.hostname = arg.slice('--host='.length);
}
}
return parsed;
}
export function resolveStandalonePaths(rootDir = process.cwd()) {
const distDir = process.env.NEXT_DIST_DIR || '.next';
const standaloneRoot = path.join(rootDir, distDir, 'standalone');
const candidates = [path.join(standaloneRoot, 'web-next'), standaloneRoot];
const appDir = candidates.find((candidate) => existsSync(path.join(candidate, 'server.js')));
if (!appDir) {
throw new Error(`Standalone server.js was not found under ${standaloneRoot}. Run npm run build first.`);
}
return {
rootDir,
distDir,
standaloneRoot,
appDir,
serverFile: path.join(appDir, 'server.js'),
sourceStaticDir: path.join(rootDir, distDir, 'static'),
targetStaticDir: path.join(appDir, distDir, 'static'),
sourcePublicDir: path.join(rootDir, 'public'),
targetPublicDir: path.join(appDir, 'public')
};
}
async function copyIfPresent(source, target) {
if (!existsSync(source)) {
return false;
}
await rm(target, { recursive: true, force: true });
await cp(source, target, { recursive: true });
return true;
}
export async function prepareStandaloneAssets(rootDir = process.cwd()) {
const paths = resolveStandalonePaths(rootDir);
const copiedStatic = await copyIfPresent(paths.sourceStaticDir, paths.targetStaticDir);
const copiedPublic = await copyIfPresent(paths.sourcePublicDir, paths.targetPublicDir);
if (!copiedStatic) {
throw new Error(`Next static assets were not found at ${paths.sourceStaticDir}. Run npm run build first.`);
}
return {
appDir: paths.appDir,
copiedStatic,
copiedPublic,
targetStaticDir: paths.targetStaticDir,
targetPublicDir: paths.targetPublicDir
};
}
export function startStandaloneServer(args = process.argv.slice(2), rootDir = process.cwd(), env = process.env) {
const paths = resolveStandalonePaths(rootDir);
const { port, hostname } = parseStartArgs(args, env);
const child = spawn(process.execPath, [paths.serverFile], {
cwd: paths.appDir,
env: {
...env,
PORT: port,
HOSTNAME: hostname
},
stdio: 'inherit'
});
child.on('exit', (code, signal) => {
if (signal) {
process.kill(process.pid, signal);
return;
}
process.exit(code ?? 0);
});
return child;
}
async function main() {
const [, , command = 'start', ...args] = process.argv;
if (command === 'prepare') {
await prepareStandaloneAssets();
return;
}
if (command === 'start') {
await prepareStandaloneAssets();
startStandaloneServer(args);
return;
}
throw new Error(`Unknown standalone-server command: ${command}`);
}
if (import.meta.url === pathToFileURL(fileURLToPath(import.meta.url)).href && process.argv[1] === fileURLToPath(import.meta.url)) {
main().catch((error) => {
console.error(error.message);
process.exit(1);
});
}