1
0
Fork 0
tsgames/build/html.ts

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);
}
}