Files
soul-yongping/next-project/scripts/start-standalone.js
2026-02-09 14:43:35 +08:00

134 lines
4.0 KiB
JavaScript
Raw 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
/**
* Standalone 模式启动脚本
* 自动复制 .next/static 和 public 到 standalone 目录后启动服务器
*/
const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');
const rootDir = path.join(__dirname, '..');
const standaloneDir = path.join(rootDir, '.next', 'standalone');
const staticSrc = path.join(rootDir, '.next', 'static');
const staticDst = path.join(standaloneDir, '.next', 'static');
const publicSrc = path.join(rootDir, 'public');
const publicDst = path.join(standaloneDir, 'public');
/**
* 递归复制目录
*/
function copyDir(src, dst) {
if (!fs.existsSync(src)) {
console.warn(`⚠️ 跳过复制:${src} 不存在`);
return;
}
// 删除旧目录
if (fs.existsSync(dst)) {
fs.rmSync(dst, { recursive: true, force: true });
}
// 创建目标目录
fs.mkdirSync(dst, { recursive: true });
// 复制文件
const entries = fs.readdirSync(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const dstPath = path.join(dst, entry.name);
if (entry.isDirectory()) {
copyDir(srcPath, dstPath);
} else {
fs.copyFileSync(srcPath, dstPath);
}
}
}
console.log('🚀 准备启动 Standalone 服务器...');
console.log(' (请勿在 .next/standalone 下直接 node server.js否则会 404须在项目根用 pnpm start\n');
// 检查 standalone 目录
if (!fs.existsSync(standaloneDir)) {
console.error('❌ 错误:未找到 .next/standalone 目录');
console.error(' 请先运行: pnpm build');
process.exit(1);
}
// 复制静态资源(缺一不可,否则部署到线上也会 404
console.log('📦 复制静态资源...');
if (!fs.existsSync(staticSrc)) {
console.error('❌ 错误:.next/static 不存在,请先执行 pnpm build');
process.exit(1);
}
console.log(' .next/static → .next/standalone/.next/static');
copyDir(staticSrc, staticDst);
const chunksDir = path.join(staticDst, 'chunks');
if (!fs.existsSync(chunksDir)) {
console.error('❌ 错误:复制后 .next/standalone/.next/static/chunks 不存在,本地会 404部署线上也会报错');
process.exit(1);
}
console.log(' public → .next/standalone/public');
copyDir(publicSrc, publicDst);
// 同步构建索引(与 devlop 打包一致),避免本地/宝塔 server 用错导致页面空白 404
const nextRoot = path.join(rootDir, '.next');
const nextStandalone = path.join(standaloneDir, '.next');
const indexFiles = [
'BUILD_ID',
'build-manifest.json',
'app-path-routes-manifest.json',
'routes-manifest.json',
'prerender-manifest.json',
'required-server-files.json',
'fallback-build-manifest.json',
];
for (const name of indexFiles) {
const src = path.join(nextRoot, name);
const dst = path.join(nextStandalone, name);
if (fs.existsSync(src)) {
try {
fs.copyFileSync(src, dst);
} catch (e) {
console.warn(' [警告] 复制索引失败 %s: %s', name, e.message);
}
}
}
console.log('✅ 静态资源与构建索引已同步\n');
// 启动服务器(必须在 standalone 目录下运行,否则 _next/static 会 404
const serverPath = path.join(standaloneDir, 'server.js');
const DEFAULT_PORT = 30006;
const port = process.env.PORT || String(DEFAULT_PORT);
console.log(`🌐 启动服务器: http://localhost:${port}`);
console.log(' (静态资源已复制到 .next/standalone请勿直接 cd 到 standalone 用 node server.js)\n');
const server = spawn('node', ['server.js'], {
cwd: standaloneDir, // 关键:工作目录必须是 standalone否则找不到 .next/static
stdio: 'inherit',
env: { ...process.env, PORT: port }
});
server.on('error', (err) => {
console.error('❌ 启动失败:', err);
process.exit(1);
});
server.on('exit', (code) => {
if (code !== 0) {
console.error(`\n❌ 服务器异常退出,退出码: ${code}`);
}
process.exit(code);
});
// 处理 Ctrl+C
process.on('SIGINT', () => {
console.log('\n\n👋 停止服务器...');
server.kill('SIGINT');
});