85 lines
2.9 KiB
JavaScript
85 lines
2.9 KiB
JavaScript
// release/esbuild.config.mjs - Bundle the HOT-Step CPP server for portable distribution
|
|
//
|
|
// Usage: node release/esbuild.config.mjs
|
|
//
|
|
// Produces: release/staging/server/server.mjs
|
|
// - All TypeScript/JS source bundled into a single ESM file
|
|
// - better-sqlite3 marked external (native addon, can't be bundled)
|
|
// - ffmpeg-static excluded (replaced by config-based path resolution)
|
|
// - model-registry.json loaded via fs.readFileSync (not bundled inline)
|
|
|
|
import esbuild from 'esbuild';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { builtinModules } from 'module';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const projectRoot = path.resolve(__dirname, '..');
|
|
|
|
// Build complete list of Node.js built-in modules (with and without node: prefix)
|
|
const nodeExternals = [
|
|
...builtinModules,
|
|
...builtinModules.map(m => `node:${m}`),
|
|
];
|
|
|
|
const result = await esbuild.build({
|
|
entryPoints: [path.join(projectRoot, 'server/src/index.ts')],
|
|
bundle: true,
|
|
platform: 'node',
|
|
target: 'node22',
|
|
format: 'esm',
|
|
outfile: path.join(projectRoot, 'release/staging/server/server.mjs'),
|
|
|
|
// External: native addon + all Node.js built-in modules
|
|
// Node builtins must be external because esbuild's ESM CJS-compat shim
|
|
// can't handle dynamic require("node:events") from Express and other CJS deps.
|
|
external: ['better-sqlite3', ...nodeExternals],
|
|
|
|
// Plugin: redirect browser polyfill packages (with trailing slash) to Node.js
|
|
// built-ins. e.g. require('process/') -> require('process')
|
|
plugins: [{
|
|
name: 'node-polyfill-redirect',
|
|
setup(build) {
|
|
// Match requires like 'process/', 'string_decoder/', 'events/', etc.
|
|
build.onResolve({ filter: /^(process|string_decoder|events|buffer|stream|util|path)\/$/ }, (args) => {
|
|
const builtin = args.path.replace(/\/$/, '');
|
|
return { path: builtin, external: true };
|
|
});
|
|
},
|
|
}],
|
|
|
|
// Don't minify - keep readable for debugging production issues
|
|
minify: false,
|
|
sourcemap: false,
|
|
|
|
// Tree-shake unused exports
|
|
treeShaking: true,
|
|
|
|
// CJS interop banner: provide require(), __filename, __dirname for ESM bundle.
|
|
// Express and other CJS dependencies need require() to work inside the ESM wrapper.
|
|
banner: {
|
|
js: [
|
|
'// HOT-Step CPP Server - bundled build',
|
|
'// Generated by release/esbuild.config.mjs',
|
|
'',
|
|
'// CJS interop: provide require() for ESM bundle',
|
|
'import { createRequire as __bundleCreateRequire } from "module";',
|
|
'const require = __bundleCreateRequire(import.meta.url);',
|
|
'',
|
|
].join('\n'),
|
|
},
|
|
|
|
// Log build stats
|
|
logLevel: 'info',
|
|
metafile: true,
|
|
});
|
|
|
|
// Print bundle size summary
|
|
const outputs = result.metafile?.outputs || {};
|
|
for (const [file, info] of Object.entries(outputs)) {
|
|
const sizeKB = (info.bytes / 1024).toFixed(1);
|
|
console.log(` ${file}: ${sizeKB} KB`);
|
|
}
|
|
|
|
console.log('\n\u2705 Server bundle complete');
|