| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /**
- * Build local Node service assets for the Electron client package.
- *
- * Steps:
- * 1. build shared
- * 2. compile the Node server
- * 3. bundle shared output
- * 4. install production dependencies for the bundled server
- * 5. copy server dist/.env/uploads
- * 6. copy Playwright browsers
- */
- const { execSync } = require('child_process');
- const path = require('path');
- const fs = require('fs');
- const ROOT = path.resolve(__dirname, '..', '..');
- const CLIENT_DIR = path.resolve(__dirname, '..');
- const SERVER_DIR = path.join(ROOT, 'server');
- const SHARED_DIR = path.join(ROOT, 'shared');
- const BUNDLE_DIR = path.join(CLIENT_DIR, '_bundle');
- const SERVER_BUNDLE = path.join(BUNDLE_DIR, 'server');
- const SHARED_BUNDLE = path.join(BUNDLE_DIR, 'shared');
- const PLAYWRIGHT_DEST = path.join(BUNDLE_DIR, 'playwright');
- const isWin = process.platform === 'win32';
- function run(cmd, cwd) {
- console.log(`\n> [${path.basename(cwd)}] ${cmd}`);
- execSync(cmd, { cwd, stdio: 'inherit', shell: true });
- }
- function step(message) {
- console.log(`\n${'='.repeat(64)}`);
- console.log(` ${message}`);
- console.log('='.repeat(64));
- }
- function cleanDir(dir) {
- if (fs.existsSync(dir)) {
- fs.rmSync(dir, { recursive: true, force: true });
- }
- fs.mkdirSync(dir, { recursive: true });
- }
- function copyDir(src, dest, options = {}) {
- const { filter, dereference = true } = options;
- if (!fs.existsSync(src)) {
- console.log(` skip missing path: ${src}`);
- return;
- }
- fs.mkdirSync(dest, { recursive: true });
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
- const srcPath = path.join(src, entry.name);
- const destPath = path.join(dest, entry.name);
- let stat;
- try {
- stat = dereference ? fs.statSync(srcPath) : fs.lstatSync(srcPath);
- } catch {
- continue;
- }
- if (stat.isDirectory()) {
- if (filter?.skipDir?.(entry.name, srcPath)) continue;
- copyDir(srcPath, destPath, options);
- continue;
- }
- if (stat.isFile()) {
- if (filter?.skipFile?.(entry.name, srcPath)) continue;
- fs.copyFileSync(srcPath, destPath);
- }
- }
- }
- function copyFile(src, dest) {
- if (!fs.existsSync(src)) {
- console.log(` skip missing file: ${src}`);
- return;
- }
- fs.mkdirSync(path.dirname(dest), { recursive: true });
- fs.copyFileSync(src, dest);
- }
- function dirSizeMB(dir) {
- try {
- const out = execSync(
- isWin
- ? `powershell -c "(Get-ChildItem -Recurse '${dir}' -File | Measure-Object -Property Length -Sum).Sum"`
- : `du -sb "${dir}" | cut -f1`,
- { encoding: 'utf-8', shell: true }
- ).trim();
- return Math.round(parseInt(out || '0', 10) / 1024 / 1024);
- } catch {
- return -1;
- }
- }
- function findPlaywrightBrowsersDir() {
- if (process.env.PLAYWRIGHT_BROWSERS_PATH && fs.existsSync(process.env.PLAYWRIGHT_BROWSERS_PATH)) {
- return process.env.PLAYWRIGHT_BROWSERS_PATH;
- }
- if (isWin) {
- const local = process.env.LOCALAPPDATA || '';
- const candidate = path.join(local, 'ms-playwright');
- return fs.existsSync(candidate) ? candidate : null;
- }
- if (process.platform === 'darwin') {
- const candidate = path.join(process.env.HOME || '', 'Library', 'Caches', 'ms-playwright');
- return fs.existsSync(candidate) ? candidate : null;
- }
- const candidate = path.join(process.env.HOME || '', '.cache', 'ms-playwright');
- return fs.existsSync(candidate) ? candidate : null;
- }
- function verify(label, targetPath) {
- const exists = fs.existsSync(targetPath);
- console.log(` ${exists ? 'OK' : '!!'} ${label}: ${targetPath}`);
- if (!exists) {
- throw new Error(`Missing required bundle asset: ${label}`);
- }
- }
- step('1/6 Build shared package');
- if (fs.existsSync(path.join(SHARED_DIR, 'package.json'))) {
- run('npm run build', SHARED_DIR);
- }
- step('2/6 Compile Node server');
- try {
- run('npx tsc', SERVER_DIR);
- } catch (error) {
- const distDir = path.join(SERVER_DIR, 'dist');
- if (!fs.existsSync(distDir) || fs.readdirSync(distDir).length === 0) {
- throw error;
- }
- console.warn('TypeScript reported issues, but dist/ exists. Continue with the compiled output.');
- }
- step('3/6 Bundle shared artifacts');
- cleanDir(SHARED_BUNDLE);
- copyDir(path.join(SHARED_DIR, 'dist'), path.join(SHARED_BUNDLE, 'dist'));
- copyFile(path.join(SHARED_DIR, 'package.json'), path.join(SHARED_BUNDLE, 'package.json'));
- step('4/6 Prepare production server bundle');
- cleanDir(SERVER_BUNDLE);
- copyFile(path.join(SERVER_DIR, 'package.json'), path.join(SERVER_BUNDLE, 'package.json'));
- const bundlePkgPath = path.join(SERVER_BUNDLE, 'package.json');
- const bundlePkg = JSON.parse(fs.readFileSync(bundlePkgPath, 'utf-8'));
- if (bundlePkg.dependencies?.['@media-manager/shared']) {
- bundlePkg.dependencies['@media-manager/shared'] = 'file:../shared';
- fs.writeFileSync(bundlePkgPath, JSON.stringify(bundlePkg, null, 2), 'utf-8');
- }
- run('npm install --omit=dev', SERVER_BUNDLE);
- console.log(` node_modules size: ${dirSizeMB(path.join(SERVER_BUNDLE, 'node_modules'))} MB`);
- copyDir(path.join(SERVER_DIR, 'dist'), path.join(SERVER_BUNDLE, 'dist'));
- copyFile(path.join(SERVER_DIR, '.env'), path.join(SERVER_BUNDLE, '.env'));
- fs.mkdirSync(path.join(SERVER_BUNDLE, 'uploads'), { recursive: true });
- copyFile(path.join(SERVER_DIR, 'uploads', '.gitkeep'), path.join(SERVER_BUNDLE, 'uploads', '.gitkeep'));
- step('5/6 Bundle Playwright browsers');
- const browserCacheDir = findPlaywrightBrowsersDir();
- if (!browserCacheDir) {
- throw new Error('Playwright browser cache not found. Run `npx playwright install chromium` first.');
- }
- cleanDir(PLAYWRIGHT_DEST);
- const browserEntries = fs.readdirSync(browserCacheDir).filter((name) => name.startsWith('chromium') || name.startsWith('ffmpeg'));
- if (browserEntries.length === 0) {
- throw new Error('No Chromium Playwright browser binaries were found.');
- }
- for (const dir of browserEntries) {
- console.log(` copy ${dir}`);
- copyDir(path.join(browserCacheDir, dir), path.join(PLAYWRIGHT_DEST, dir));
- }
- console.log(` playwright size: ${dirSizeMB(PLAYWRIGHT_DEST)} MB`);
- step('6/6 Verify bundle assets');
- verify('server dist/app.js', path.join(SERVER_BUNDLE, 'dist', 'app.js'));
- verify('server node_modules', path.join(SERVER_BUNDLE, 'node_modules'));
- verify('shared dist', path.join(SHARED_BUNDLE, 'dist'));
- verify('playwright', PLAYWRIGHT_DEST);
- step('Bundle ready');
- console.log(` server: ${SERVER_BUNDLE}`);
- console.log(` shared: ${SHARED_BUNDLE}`);
- console.log(` playwright: ${PLAYWRIGHT_DEST}`);
|