91 lines
3.0 KiB
JavaScript
91 lines
3.0 KiB
JavaScript
// Assemble a self-contained server into dist/ from the Next standalone output.
|
|
// `next build` with output:"standalone" produces:
|
|
// .next/standalone/ (server.js + traced node_modules + .next/server)
|
|
// .next/static/ (NOT inside standalone — must be copied)
|
|
// We copy everything into dist/ so the published package ships one folder that
|
|
// `node dist/server.js` can run.
|
|
import { cp, mkdir, readdir, rm, writeFile } from "fs/promises";
|
|
import { existsSync } from "fs";
|
|
|
|
const STANDALONE = ".next/standalone";
|
|
const STATIC = ".next/static";
|
|
const PUBLIC = "public";
|
|
const OUT = "dist";
|
|
|
|
if (!existsSync(STANDALONE)) {
|
|
console.error(
|
|
`✗ ${STANDALONE} not found. Did "next build" run with output:"standalone"?`
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
await rm(OUT, { recursive: true, force: true });
|
|
await cp(STANDALONE, OUT, { recursive: true });
|
|
await cp(STATIC, `${OUT}/.next/static`, { recursive: true });
|
|
if (existsSync(PUBLIC)) {
|
|
await cp(PUBLIC, `${OUT}/public`, { recursive: true });
|
|
}
|
|
|
|
// Turbopack represents serverExternalPackages with generated package aliases
|
|
// under .next/node_modules. The standalone tree uses absolute symlinks for
|
|
// those aliases, which npm omits from tarballs. Replace better-sqlite3 aliases
|
|
// with portable shims and let npm install the real native dependency for the
|
|
// target platform from the package root.
|
|
const NEXT_NODE_MODULES = `${OUT}/.next/node_modules`;
|
|
if (existsSync(NEXT_NODE_MODULES)) {
|
|
for (const entry of await readdir(NEXT_NODE_MODULES)) {
|
|
if (!entry.startsWith("better-sqlite3-")) continue;
|
|
const alias = `${NEXT_NODE_MODULES}/${entry}`;
|
|
await rm(alias, { recursive: true, force: true });
|
|
await mkdir(alias, { recursive: true });
|
|
await writeFile(
|
|
`${alias}/package.json`,
|
|
`${JSON.stringify(
|
|
{ name: entry, private: true, main: "index.js" },
|
|
null,
|
|
2
|
|
)}\n`
|
|
);
|
|
await writeFile(
|
|
`${alias}/index.js`,
|
|
'module.exports = require("better-sqlite3");\n'
|
|
);
|
|
}
|
|
}
|
|
await rm(`${OUT}/node_modules/better-sqlite3`, {
|
|
recursive: true,
|
|
force: true,
|
|
});
|
|
|
|
// Next copies the whole project root into the standalone bundle. Prune it down
|
|
// to just the runtime essentials (drops src/, configs, and local notes so
|
|
// they never get published).
|
|
const KEEP = new Set([
|
|
"server.js",
|
|
".next",
|
|
"node_modules",
|
|
"package.json",
|
|
"public",
|
|
]);
|
|
for (const entry of await readdir(OUT)) {
|
|
if (!KEEP.has(entry)) {
|
|
await rm(`${OUT}/${entry}`, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
// Strip source maps (*.map): debug-only artifacts the published runtime never
|
|
// needs. Removing them keeps the package lean and avoids shipping a stack-trace
|
|
// → source mapping. Safe to delete — source maps are never required at runtime.
|
|
let strippedMaps = 0;
|
|
for (const entry of await readdir(OUT, { recursive: true })) {
|
|
if (entry.endsWith(".map")) {
|
|
await rm(`${OUT}/${entry}`, { force: true });
|
|
strippedMaps++;
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
`✓ Assembled standalone server into ${OUT}/ ` +
|
|
`(${strippedMaps} source map(s) stripped; run: node ${OUT}/server.js)`
|
|
);
|