Support Next.js standalone runtime in websites deploy agent.
Copy static/public into the standalone bundle, point PM2 at server.js, and drop full node_modules after a successful start. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
62f75c3a75
commit
f201a6408c
@@ -10,6 +10,7 @@ fi
|
|||||||
ROOT="/var/www/sites/$SLUG"
|
ROOT="/var/www/sites/$SLUG"
|
||||||
LOG="/var/log/websites/deploy-$SLUG.log"
|
LOG="/var/log/websites/deploy-$SLUG.log"
|
||||||
STATUS="/var/log/websites/deploy-$SLUG.status.json"
|
STATUS="/var/log/websites/deploy-$SLUG.status.json"
|
||||||
|
ECOSYSTEM="/var/www/sites/ecosystem.config.cjs"
|
||||||
exec >>"$LOG" 2>&1
|
exec >>"$LOG" 2>&1
|
||||||
|
|
||||||
write_status() {
|
write_status() {
|
||||||
@@ -78,7 +79,97 @@ fi
|
|||||||
|
|
||||||
npm ci
|
npm ci
|
||||||
npm run build
|
npm run build
|
||||||
pm2 restart "$SLUG" --update-env || pm2 start /var/www/sites/ecosystem.config.cjs --only "$SLUG"
|
|
||||||
|
# Next.js standalone: copy static assets Next does not place in standalone/, then
|
||||||
|
# point PM2 at server.js and drop the full node_modules tree.
|
||||||
|
if [[ -f .next/standalone/server.js ]]; then
|
||||||
|
echo "standalone build detected — preparing runtime bundle"
|
||||||
|
mkdir -p .next/standalone/.next
|
||||||
|
rm -rf .next/standalone/.next/static
|
||||||
|
cp -a .next/static .next/standalone/.next/static
|
||||||
|
if [[ -d public ]]; then
|
||||||
|
rm -rf .next/standalone/public
|
||||||
|
cp -a public .next/standalone/public
|
||||||
|
fi
|
||||||
|
|
||||||
|
SLUG="$SLUG" ROOT="$ROOT" ECOSYSTEM="$ECOSYSTEM" node <<'NODE'
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = process.env.ECOSYSTEM;
|
||||||
|
const slug = process.env.SLUG;
|
||||||
|
const root = process.env.ROOT;
|
||||||
|
let cfg = { apps: [] };
|
||||||
|
try {
|
||||||
|
delete require.cache[require.resolve(path)];
|
||||||
|
cfg = require(path);
|
||||||
|
if (!Array.isArray(cfg.apps)) cfg.apps = [];
|
||||||
|
} catch (_) {
|
||||||
|
cfg = { apps: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = cfg.apps.find((a) => a.name === slug);
|
||||||
|
if (!app) {
|
||||||
|
console.error('ecosystem entry missing for', slug);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const port =
|
||||||
|
(app.env && Number(app.env.PORT)) ||
|
||||||
|
(String(app.args || '').match(/--port\s+(\d+)/) || [])[1] ||
|
||||||
|
3005;
|
||||||
|
|
||||||
|
app.cwd = root + '/.next/standalone';
|
||||||
|
app.script = 'server.js';
|
||||||
|
app.args = '';
|
||||||
|
app.env = {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
PORT: String(port),
|
||||||
|
HOSTNAME: '127.0.0.1',
|
||||||
|
};
|
||||||
|
|
||||||
|
const lines = ['module.exports = {', ' apps: ['];
|
||||||
|
cfg.apps.forEach((entry, idx) => {
|
||||||
|
lines.push(' {');
|
||||||
|
lines.push(` name: ${JSON.stringify(entry.name)},`);
|
||||||
|
lines.push(` cwd: ${JSON.stringify(entry.cwd)},`);
|
||||||
|
lines.push(` script: ${JSON.stringify(entry.script)},`);
|
||||||
|
if (entry.args) {
|
||||||
|
lines.push(` args: ${JSON.stringify(entry.args)},`);
|
||||||
|
}
|
||||||
|
lines.push(' env: {');
|
||||||
|
lines.push(` NODE_ENV: ${JSON.stringify(entry.env.NODE_ENV)},`);
|
||||||
|
lines.push(` PORT: ${JSON.stringify(entry.env.PORT)},`);
|
||||||
|
if (entry.env.HOSTNAME) {
|
||||||
|
lines.push(` HOSTNAME: ${JSON.stringify(entry.env.HOSTNAME)},`);
|
||||||
|
}
|
||||||
|
lines.push(' },');
|
||||||
|
lines.push(` error_file: ${JSON.stringify(entry.error_file)},`);
|
||||||
|
lines.push(` out_file: ${JSON.stringify(entry.out_file)},`);
|
||||||
|
lines.push(' time: true,');
|
||||||
|
lines.push(idx === cfg.apps.length - 1 ? ' }' : ' },');
|
||||||
|
});
|
||||||
|
lines.push(' ],');
|
||||||
|
lines.push('};');
|
||||||
|
lines.push('');
|
||||||
|
fs.writeFileSync(path, lines.join('\n'));
|
||||||
|
console.log('ecosystem updated for standalone:', slug, 'port', port);
|
||||||
|
NODE
|
||||||
|
|
||||||
|
# Full delete+start so PM2 picks up new cwd/script (restart alone keeps old path).
|
||||||
|
pm2 delete "$SLUG" || true
|
||||||
|
pm2 start "$ECOSYSTEM" --only "$SLUG"
|
||||||
|
pm2 save || true
|
||||||
|
|
||||||
|
echo "removing full node_modules (standalone runtime keeps its own minimal copy)"
|
||||||
|
rm -rf node_modules
|
||||||
|
|
||||||
|
echo "==== $(date -u +%Y-%m-%dT%H:%M:%SZ) deploy ok (standalone): $SLUG ===="
|
||||||
|
write_status "success" "Deployed origin/$BRANCH (standalone)"
|
||||||
|
trap - ERR
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "no standalone output — using next start (legacy)"
|
||||||
|
pm2 restart "$SLUG" --update-env || pm2 start "$ECOSYSTEM" --only "$SLUG"
|
||||||
pm2 save || true
|
pm2 save || true
|
||||||
|
|
||||||
echo "==== $(date -u +%Y-%m-%dT%H:%M:%SZ) deploy ok: $SLUG ===="
|
echo "==== $(date -u +%Y-%m-%dT%H:%M:%SZ) deploy ok: $SLUG ===="
|
||||||
|
|||||||
Reference in New Issue
Block a user