proper minify (thank you claude for making the code)
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Minify all public JS, CSS, and HTML assets in-place.
|
||||
* Uses terser (JS), clean-css (CSS), html-minifier-terser (HTML).
|
||||
*
|
||||
* Usage: bun run scripts/minify-public.ts [--dir public]
|
||||
*/
|
||||
import { readdir, stat } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { minify as terserMinify } from "terser";
|
||||
import CleanCSS from "clean-css";
|
||||
import { minify as htmlMinify } from "html-minifier-terser";
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
let publicDir = path.resolve("public");
|
||||
const dirIdx = args.indexOf("--dir");
|
||||
if (dirIdx !== -1 && args[dirIdx + 1]) {
|
||||
publicDir = path.resolve(args[dirIdx + 1]);
|
||||
}
|
||||
|
||||
const cleanCss = new CleanCSS({ level: 2 });
|
||||
|
||||
const htmlOpts = {
|
||||
collapseWhitespace: true,
|
||||
removeComments: true,
|
||||
removeRedundantAttributes: true,
|
||||
removeEmptyAttributes: true,
|
||||
minifyCSS: true,
|
||||
minifyJS: true,
|
||||
sortAttributes: true,
|
||||
sortClassName: true,
|
||||
};
|
||||
|
||||
type Stats = { js: number; css: number; html: number; savedBytes: number };
|
||||
const stats: Stats = { js: 0, css: 0, html: 0, savedBytes: 0 };
|
||||
|
||||
async function collectFiles(dir: string, exts: Set<string>): Promise<string[]> {
|
||||
const results: string[] = [];
|
||||
const entries = await readdir(dir, { withFileTypes: true });
|
||||
for (const e of entries) {
|
||||
const full = path.join(dir, e.name);
|
||||
if (e.isDirectory()) {
|
||||
// Skip vendor — already distributed minified
|
||||
if (e.name === "vendor") continue;
|
||||
results.push(...(await collectFiles(full, exts)));
|
||||
} else if (exts.has(path.extname(e.name).toLowerCase())) {
|
||||
results.push(full);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
async function minifyJS(filePath: string) {
|
||||
const src = await Bun.file(filePath).text();
|
||||
const result = await terserMinify(src, {
|
||||
compress: { passes: 2, drop_console: false, ecma: 2020 },
|
||||
mangle: { toplevel: false },
|
||||
format: { ecma: 2020 },
|
||||
module: true,
|
||||
});
|
||||
if (result.code && result.code.length < src.length) {
|
||||
stats.savedBytes += src.length - result.code.length;
|
||||
await Bun.write(filePath, result.code);
|
||||
}
|
||||
stats.js++;
|
||||
}
|
||||
|
||||
async function minifyCSS(filePath: string) {
|
||||
const src = await Bun.file(filePath).text();
|
||||
const result = cleanCss.minify(src);
|
||||
if (result.styles && result.styles.length < src.length) {
|
||||
stats.savedBytes += src.length - result.styles.length;
|
||||
await Bun.write(filePath, result.styles);
|
||||
}
|
||||
stats.css++;
|
||||
}
|
||||
|
||||
async function minifyHTML(filePath: string) {
|
||||
const src = await Bun.file(filePath).text();
|
||||
const result = await htmlMinify(src, htmlOpts);
|
||||
if (result.length < src.length) {
|
||||
stats.savedBytes += src.length - result.length;
|
||||
await Bun.write(filePath, result);
|
||||
}
|
||||
stats.html++;
|
||||
}
|
||||
|
||||
// Collect all files
|
||||
const jsFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".js"]));
|
||||
const cssFiles = await collectFiles(path.join(publicDir, "assets"), new Set([".css"]));
|
||||
const htmlFiles = await collectFiles(publicDir, new Set([".html"]));
|
||||
|
||||
console.log(`Minifying ${jsFiles.length} JS, ${cssFiles.length} CSS, ${htmlFiles.length} HTML files...`);
|
||||
|
||||
// Process in parallel batches
|
||||
await Promise.all([
|
||||
...jsFiles.map((f) => minifyJS(f).catch((e) => console.error(`JS error ${f}: ${e.message}`))),
|
||||
...cssFiles.map((f) => minifyCSS(f).catch((e) => console.error(`CSS error ${f}: ${e.message}`))),
|
||||
...htmlFiles.map((f) => minifyHTML(f).catch((e) => console.error(`HTML error ${f}: ${e.message}`))),
|
||||
]);
|
||||
|
||||
console.log(
|
||||
`Done: ${stats.js} JS, ${stats.css} CSS, ${stats.html} HTML — saved ${(stats.savedBytes / 1024).toFixed(1)} KB`,
|
||||
);
|
||||
Reference in New Issue
Block a user