115 lines
4.2 KiB
JavaScript
115 lines
4.2 KiB
JavaScript
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const cp = require('node:child_process');
|
|
|
|
const backendDir = path.resolve(__dirname, '..');
|
|
const repoDir = path.resolve(backendDir, '..', '..');
|
|
const frontendDir = path.join(repoDir, 'packages', 'frontend');
|
|
const stageDir = path.join(backendDir, 'build', 'pkg-stage');
|
|
const outputDir = path.join(backendDir, 'build', 'pkg-output');
|
|
|
|
function run(command, cwd, env) {
|
|
cp.execFileSync(
|
|
process.platform === 'win32' ? 'cmd.exe' : 'bash',
|
|
process.platform === 'win32' ? ['/c', command] : ['-lc', command],
|
|
{ cwd, stdio: 'inherit', env: { ...process.env, ...env } }
|
|
);
|
|
}
|
|
|
|
function assertStage(dir) {
|
|
const required = [
|
|
path.join(dir, 'public', 'index.html'),
|
|
path.join(dir, 'dist', 'index.js'),
|
|
];
|
|
for (const file of required) {
|
|
if (!fs.existsSync(file)) {
|
|
throw new Error(`缺少 staging 文件: ${file}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Clean
|
|
fs.rmSync(stageDir, { recursive: true, force: true });
|
|
fs.rmSync(outputDir, { recursive: true, force: true });
|
|
fs.mkdirSync(stageDir, { recursive: true });
|
|
|
|
// Build frontend (override API base URL to use same-origin for installer)
|
|
console.log('[1/6] Building frontend...');
|
|
run('pnpm build', frontendDir, { VITE_API_BASE_URL: '', VITE_COOL_EPS_ENABLE: 'true' });
|
|
|
|
// Build backend
|
|
console.log('[2/6] Building backend...');
|
|
run('npm run build', backendDir);
|
|
|
|
// Stage files
|
|
console.log('[3/6] Staging files...');
|
|
fs.cpSync(path.join(backendDir, 'bootstrap.js'), path.join(stageDir, 'bootstrap.js'));
|
|
fs.cpSync(path.join(backendDir, 'dist'), path.join(stageDir, 'dist'), { recursive: true });
|
|
fs.cpSync(path.join(backendDir, 'public'), path.join(stageDir, 'public'), { recursive: true });
|
|
// Overlay frontend dist onto public (frontend index.html replaces backend welcome page)
|
|
fs.cpSync(path.join(frontendDir, 'dist'), path.join(stageDir, 'public'), { recursive: true, force: true });
|
|
if (fs.existsSync(path.join(backendDir, 'typings'))) {
|
|
fs.cpSync(path.join(backendDir, 'typings'), path.join(stageDir, 'typings'), { recursive: true });
|
|
}
|
|
if (fs.existsSync(path.join(backendDir, 'src', 'locales'))) {
|
|
fs.mkdirSync(path.join(stageDir, 'src'), { recursive: true });
|
|
fs.cpSync(path.join(backendDir, 'src', 'locales'), path.join(stageDir, 'src', 'locales'), { recursive: true });
|
|
}
|
|
|
|
// Generate staging package.json
|
|
console.log('[4/6] Generating staging package.json...');
|
|
const backendPkg = require(path.join(backendDir, 'package.json'));
|
|
const stagePkg = {
|
|
name: backendPkg.name,
|
|
version: backendPkg.version,
|
|
private: true,
|
|
overrides: backendPkg.overrides || {},
|
|
dependencies: backendPkg.dependencies,
|
|
bin: './bootstrap.js',
|
|
pkg: {
|
|
scripts: ['dist/**/*.js', 'node_modules/**/*.mjs'],
|
|
assets: [
|
|
'public/**/*',
|
|
'typings/**/*',
|
|
'src/locales/**/*',
|
|
'node_modules/@img/sharp-win32-x64/**/*',
|
|
'node_modules/@img/colour/**/*',
|
|
'node_modules/better-sqlite3/build/Release/*.node',
|
|
'node_modules/@msgpackr-extract/msgpackr-extract-win32-x64/*.node',
|
|
'node_modules/@napi-rs/canvas-win32-x64-msvc/*.node',
|
|
],
|
|
targets: ['node20-win-x64'],
|
|
outputPath: outputDir,
|
|
},
|
|
};
|
|
fs.writeFileSync(path.join(stageDir, 'package.json'), JSON.stringify(stagePkg, null, 2));
|
|
|
|
// Install deps
|
|
console.log('[5/6] Installing production dependencies...');
|
|
run('npm install --production --install-strategy=hoisted --legacy-peer-deps', stageDir);
|
|
|
|
// Patch generator-function
|
|
const gfPkg = path.join(stageDir, 'node_modules', 'generator-function', 'package.json');
|
|
if (fs.existsSync(gfPkg)) {
|
|
const gf = JSON.parse(fs.readFileSync(gfPkg, 'utf8'));
|
|
if (gf.exports && gf.exports['.']) {
|
|
gf.exports['.'] = './index.js';
|
|
fs.writeFileSync(gfPkg, JSON.stringify(gf, null, 2));
|
|
console.log(' Patched generator-function exports');
|
|
}
|
|
}
|
|
|
|
// Run pkg
|
|
console.log('[6/6] Running pkg...');
|
|
assertStage(stageDir);
|
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
run('npx @yao-pkg/pkg@6.14.1 .', stageDir);
|
|
|
|
// Validate
|
|
console.log('\n=== Build complete ===');
|
|
const exePath = path.join(outputDir, 'backend.exe');
|
|
if (fs.existsSync(exePath)) {
|
|
const stat = fs.statSync(exePath);
|
|
console.log(`Output: ${exePath} (${(stat.size / 1024 / 1024).toFixed(1)} MB)`);
|
|
}
|