import path from 'path'; import { minify } from 'html-minifier'; import UglifyJS from 'uglify-js'; import wasmPlugin from './wasmPlugin'; import imagePlugin from './imagePlugin'; import fontPlugin from './fontPlugin'; import lightningcss from 'bun-lightningcss'; import { getGames } from './isGame'; import audioPlugin from './audioPlugin'; export async function buildHTML(game: string, production = false, portable = false) { const html = await Bun.file(path.resolve(import.meta.dir, 'assets', 'index.html')).text(); const bundle = await Bun.build({ outdir: '/tmp', entrypoints: [path.resolve(import.meta.dir, '..', 'src', 'index.ts')], sourcemap: production ? 'none' : 'inline', define: { global: 'window', GAME: `"${game}"`, GAMES: JSON.stringify(await getGames()), }, plugins: [ imagePlugin, audioPlugin, fontPlugin, wasmPlugin({ production, portable }), lightningcss(), ] }); if (bundle.success) { if (bundle.outputs.length > 1) { console.log(bundle.outputs); return; } const iconFile = Bun.file(path.resolve(import.meta.dir, '..', 'games', game, 'assets', 'favicon.ico')); let icon = ''; if (await iconFile.exists()) { icon = ``; } let script = await bundle.outputs[0].text(); const inits = new Set(); script = script.replace(/var (init_[^ ]+) = __esm\(\(\)/g, (_, $1) => { inits.add($1); return `var ${$1} = __esm(async ()`; }); for (const init of inits) { script = script.replaceAll(`${init}()`, `await ${init}()`); } script = script.replaceAll('await Promise.resolve().then(() =>', '('); if (production) { const minifyResult = UglifyJS.minify(script, { module: true, }); if (minifyResult.error) { console.warn(`Minify error: ${minifyResult.error}`); } else { script = minifyResult.code; } } const resultHTML = html .replace('$SCRIPT$', ``) .replace('$TITLE$', game[0].toUpperCase() + game.slice(1).toLowerCase()) .replace('$ICON$', icon); return minify(resultHTML, { collapseWhitespace: production, decodeEntities: true, minifyCSS: production, minifyJS: production, }); } else { console.error('Failed: ', !bundle.success, bundle); } }