diff --git a/packages/chronicle/src/cli/commands/start.ts b/packages/chronicle/src/cli/commands/start.ts index 4bb86b3..574a232 100644 --- a/packages/chronicle/src/cli/commands/start.ts +++ b/packages/chronicle/src/cli/commands/start.ts @@ -1,41 +1,58 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { spawn } from 'node:child_process'; import chalk from 'chalk'; import { Command } from 'commander'; import { loadCLIConfig } from '@/cli/utils/config'; -import { PACKAGE_ROOT } from '@/cli/utils/resolve'; -import { linkContent } from '@/cli/utils/scaffold'; + +function resolveServerEntry(projectRoot: string, preset?: string): string { + if (preset === 'vercel' || preset === 'vercel-static') { + return path.resolve(projectRoot, '.vercel/output/server/index.mjs'); + } + return path.resolve(projectRoot, '.output/server/index.mjs'); +} export const startCommand = new Command('start') .description('Start production server') .option('-p, --port ', 'Port number', '3000') .option('--config ', 'Path to chronicle.yaml') - .option('--host ', 'Host address', 'localhost') + .option('--host ', 'Host address', '0.0.0.0') + .option('--preset ', 'Deploy preset (must match build preset)') .action(async options => { - const { config, projectRoot, configPath } = await loadCLIConfig(options.config); - const port = parseInt(options.port, 10); - await linkContent(projectRoot, config); + const { config, projectRoot } = await loadCLIConfig(options.config); + const preset = options.preset ?? config.preset; + const serverEntry = resolveServerEntry(projectRoot, preset); - console.log(chalk.cyan('Starting production server...')); + const exists = await fs.access(serverEntry).then(() => true, () => false); + if (!exists) { + console.error(chalk.red(`No build found at ${serverEntry}`)); + console.error(chalk.red('Run `chronicle build` first.')); + process.exit(1); + } - const { preview } = await import('vite'); - const { createViteConfig } = await import('@/server/vite-config'); + console.log(chalk.cyan('Starting production server...')); - const viteConfig = await createViteConfig({ packageRoot: PACKAGE_ROOT, projectRoot, configPath }); - const server = await preview({ - ...viteConfig, - preview: { port, host: options.host } + const child = spawn(process.execPath, [serverEntry], { + stdio: 'inherit', + env: { + ...process.env, + PORT: options.port, + HOST: options.host, + }, }); - server.printUrls(); - let shuttingDown = false; - const shutdown = async () => { + const shutdown = () => { if (shuttingDown) return; shuttingDown = true; try { - await server.close(); - } catch { /* ignore close errors */ } - process.exit(0); + child.kill('SIGTERM'); + } catch { /* ignore if already exited */ } }; process.once('SIGINT', shutdown); process.once('SIGTERM', shutdown); + + child.on('exit', (code) => { + process.exit(code ?? 0); + }); });