89 lines
3.1 KiB
TypeScript
89 lines
3.1 KiB
TypeScript
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';
|
|
|
|
interface Args {
|
|
production?: boolean;
|
|
portable?: boolean;
|
|
mobile?: boolean
|
|
}
|
|
export async function buildHTML(game: string, { production = false, portable = false, mobile = false }: Args = {}) {
|
|
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, '..', 'src', 'games', game, 'assets', 'favicon.ico'));
|
|
let icon = '';
|
|
if (await iconFile.exists()) {
|
|
icon = `<link rel="icon" href="data:;base64,${Buffer.from(await iconFile.arrayBuffer()).toString('base64')}" />`;
|
|
}
|
|
let script = await bundle.outputs[0].text();
|
|
const inits = new Set<string>();
|
|
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(() =>', '(');
|
|
let scriptPrefix = '';
|
|
if (production) {
|
|
const minifyResult = UglifyJS.minify(script, {
|
|
module: true,
|
|
});
|
|
if (minifyResult.error) {
|
|
console.warn(`Minify error: ${minifyResult.error}`);
|
|
} else {
|
|
script = minifyResult.code;
|
|
}
|
|
} else if (mobile) {
|
|
const eruda = await Bun.file(path.resolve(import.meta.dir, '..', 'node_modules', 'eruda', 'eruda.js')).text();
|
|
scriptPrefix = `<script>${eruda};\neruda.init();</script>`;
|
|
}
|
|
|
|
const resultHTML = html
|
|
.replace('$SCRIPT$', () => `${scriptPrefix}<script type="module">${script}</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);
|
|
}
|
|
} |