make docker file a little better for prod builds

This commit is contained in:
KingKDot
2026-08-01 22:36:17 -05:00
parent fe38187754
commit 743db8350f
3 changed files with 52 additions and 6 deletions
+3
View File
@@ -113,12 +113,15 @@ RUN if [ -f dist-clients/BackstageCapture.x64.dll ]; then \
# Keep production build phases separate so BuildKit reports the exact slow or # Keep production build phases separate so BuildKit reports the exact slow or
# failing phase and can cache each completed phase independently. # failing phase and can cache each completed phase independently.
RUN bun run build:css RUN bun run build:css
RUN bun run build:web:prod
RUN bun run vendor RUN bun run vendor
RUN MINIFY_CONCURRENCY=4 bun run minify RUN MINIFY_CONCURRENCY=4 bun run minify
RUN bun run build:bundle RUN bun run build:bundle
RUN test "$(wc -l < ./public/index.html)" -lt 20 \ RUN test "$(wc -l < ./public/index.html)" -lt 20 \
&& test "$(wc -l < ./public/assets/main.js)" -lt 50 \ && test "$(wc -l < ./public/assets/main.js)" -lt 50 \
&& test -s ./public/assets/generated/shared-ui-settings.js \
&& test ! -e ./public/assets/generated/shared-ui-settings.js.map \
&& test -s ./public/assets/tailwind.css \ && test -s ./public/assets/tailwind.css \
&& test -d ./public/vendor/fontawesome \ && test -d ./public/vendor/fontawesome \
&& test -s ./dist/index.js \ && test -s ./dist/index.js \
+2 -1
View File
@@ -11,9 +11,10 @@
"dev": "bun run scripts/dev.ts", "dev": "bun run scripts/dev.ts",
"start": "bun run build && bun dist/index.js", "start": "bun run build && bun dist/index.js",
"build": "bun run build:css && bun run build:web && bun run vendor && bun run build:bundle", "build": "bun run build:css && bun run build:web && bun run vendor && bun run build:bundle",
"build:public:prod": "bun run build:css && bun run build:web && bun run vendor && bun run minify", "build:public:prod": "bun run build:css && bun run build:web:prod && bun run vendor && bun run minify",
"build:bundle": "bun build --production src/index.ts --target bun --outfile dist/index.js && bun build --production src/server/plugin-runtime/worker-host.ts --target bun --outfile dist/server/plugin-runtime/worker-host.js", "build:bundle": "bun build --production src/index.ts --target bun --outfile dist/index.js && bun build --production src/server/plugin-runtime/worker-host.ts --target bun --outfile dist/server/plugin-runtime/worker-host.js",
"build:web": "bun build src/web/shared-ui-settings.ts --outdir public/assets/generated --target browser --format esm --sourcemap=external", "build:web": "bun build src/web/shared-ui-settings.ts --outdir public/assets/generated --target browser --format esm --sourcemap=external",
"build:web:prod": "bun -e \"import { rm } from 'node:fs/promises'; await rm('public/assets/generated', { recursive: true, force: true });\" && bun build --production src/web/shared-ui-settings.ts --outdir public/assets/generated --target browser --format esm",
"watch:web": "bun run build:web --watch", "watch:web": "bun run build:web --watch",
"vendor": "bun run scripts/vendor.ts", "vendor": "bun run scripts/vendor.ts",
"build:prod:win": "bun run build:public:prod && bun build --production src/index.ts --compile --target bun-windows-x64 --outfile dist/overlord-server.exe", "build:prod:win": "bun run build:public:prod && bun build --production src/index.ts --compile --target bun-windows-x64 --outfile dist/overlord-server.exe",
+47 -5
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env bun #!/usr/bin/env bun
/** /**
* Minify all public JS, CSS, and HTML assets in-place. * Minify first-party public assets and copied vendor assets that do not
* already ship minified.
* Uses terser (JS), clean-css (CSS), html-minifier-terser (HTML). * Uses terser (JS), clean-css (CSS), html-minifier-terser (HTML).
* *
* Usage: bun run scripts/minify-public.ts [--dir public] * Usage: bun run scripts/minify-public.ts [--dir public]
@@ -55,13 +56,13 @@ async function collectFiles(dir: string, exts: Set<string>): Promise<string[]> {
return results; return results;
} }
async function minifyJS(filePath: string) { async function minifyJS(filePath: string, isModule = true) {
const src = await Bun.file(filePath).text(); const src = await Bun.file(filePath).text();
const result = await terserMinify(src, { const result = await terserMinify(src, {
compress: { passes: 2, drop_console: false, ecma: 2020 }, compress: { passes: 2, drop_console: false, ecma: 2020 },
mangle: { toplevel: false }, mangle: { toplevel: false },
format: { ecma: 2020 }, format: { ecma: 2020 },
module: true, module: isModule,
}); });
if (result.code && result.code.length < src.length) { if (result.code && result.code.length < src.length) {
stats.savedBytes += src.length - result.code.length; stats.savedBytes += src.length - result.code.length;
@@ -108,19 +109,60 @@ async function runPool<T>(
await Promise.all(workers); await Promise.all(workers);
} }
// Collect all files const vendorDir = path.join(publicDir, "vendor");
const vendorRoots = [
"msgpackr",
"codemirror",
"chart.js",
"gridstack",
"hotwired",
"xterm",
"inter",
"jetbrains-mono",
];
async function collectVendorFiles(exts: Set<string>): Promise<string[]> {
const results: string[] = [];
for (const root of vendorRoots) {
const dir = path.join(vendorDir, root);
try {
results.push(...(await collectFiles(dir, exts)));
} catch (error: any) {
if (error?.code !== "ENOENT") throw error;
}
}
return results;
}
function isVendorModule(filePath: string): boolean {
const normalized = filePath.replaceAll("\\", "/");
return normalized.endsWith(".mjs") ||
normalized.includes("/hotwired/") ||
normalized.endsWith("/chart.esm.js");
}
// Collect all files.
const jsFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".js"])); const jsFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".js"]));
const cssFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".css"])); const cssFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".css"]));
const htmlFiles = await collectFiles(publicDir, new Set([".html"])); const htmlFiles = await collectFiles(publicDir, new Set([".html"]));
const vendorJsFiles = await collectVendorFiles(new Set([".js", ".mjs"]));
const vendorCssFiles = await collectVendorFiles(new Set([".css"]));
console.log( console.log(
`Minifying ${jsFiles.length} JS, ${cssFiles.length} CSS, ${htmlFiles.length} HTML files ` + `Minifying ${jsFiles.length + vendorJsFiles.length} JS, ` +
`${cssFiles.length + vendorCssFiles.length} CSS, ${htmlFiles.length} HTML files ` +
`(concurrency=${minifyConcurrency})...`, `(concurrency=${minifyConcurrency})...`,
); );
const jobs = [ const jobs = [
...jsFiles.map((file) => ({ kind: "JS", file, minify: minifyJS })), ...jsFiles.map((file) => ({ kind: "JS", file, minify: minifyJS })),
...vendorJsFiles.map((file) => ({
kind: "JS",
file,
minify: (filePath: string) => minifyJS(filePath, isVendorModule(filePath)),
})),
...cssFiles.map((file) => ({ kind: "CSS", file, minify: minifyCSS })), ...cssFiles.map((file) => ({ kind: "CSS", file, minify: minifyCSS })),
...vendorCssFiles.map((file) => ({ kind: "CSS", file, minify: minifyCSS })),
...htmlFiles.map((file) => ({ kind: "HTML", file, minify: minifyHTML })), ...htmlFiles.map((file) => ({ kind: "HTML", file, minify: minifyHTML })),
]; ];
await runPool(jobs, minifyConcurrency, async ({ kind, file, minify }) => { await runPool(jobs, minifyConcurrency, async ({ kind, file, minify }) => {