79 lines
2.3 KiB
JavaScript
79 lines
2.3 KiB
JavaScript
/**
|
|
* Build script: copy src → dist, minify JS/CSS, inline critical CSS (Beasties).
|
|
* Run with: pnpm build
|
|
*/
|
|
import {
|
|
rmSync,
|
|
mkdirSync,
|
|
readFileSync,
|
|
writeFileSync,
|
|
cpSync,
|
|
readdirSync,
|
|
} from 'fs';
|
|
import { join, dirname, extname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import Beasties from 'beasties';
|
|
import { minify as minifyJs } from 'terser';
|
|
import CleanCSS from 'clean-css';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const root = join(__dirname, '..');
|
|
const srcDir = join(root, 'src');
|
|
const distDir = join(root, 'dist');
|
|
|
|
function getFiles(dir, files = []) {
|
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
for (const e of entries) {
|
|
const full = join(dir, e.name);
|
|
if (e.isDirectory()) getFiles(full, files);
|
|
else files.push(full);
|
|
}
|
|
return files;
|
|
}
|
|
|
|
async function main() {
|
|
// 1. Clean and copy src → dist
|
|
rmSync(distDir, { recursive: true, force: true });
|
|
mkdirSync(distDir, { recursive: true });
|
|
cpSync(srcDir, distDir, { recursive: true });
|
|
|
|
const distFiles = getFiles(distDir);
|
|
|
|
// 2. Minify JS
|
|
const jsFiles = distFiles.filter((f) => extname(f) === '.js');
|
|
for (const f of jsFiles) {
|
|
const code = readFileSync(f, 'utf8');
|
|
const result = await minifyJs(code, { format: { comments: false } });
|
|
if (result.code) writeFileSync(f, result.code);
|
|
}
|
|
|
|
// 3. Minify CSS
|
|
const cleanCss = new CleanCSS({ level: 2 });
|
|
const cssFiles = distFiles.filter((f) => extname(f) === '.css');
|
|
for (const f of cssFiles) {
|
|
const code = readFileSync(f, 'utf8');
|
|
const result = cleanCss.minify(code);
|
|
if (!result.errors.length) writeFileSync(f, result.styles);
|
|
}
|
|
|
|
// 4. Inline critical CSS with Beasties for all HTML files (no browser; works in CI)
|
|
const htmlFiles = distFiles.filter((f) => extname(f) === '.html');
|
|
const beasties = new Beasties({
|
|
path: distDir,
|
|
preload: 'default',
|
|
logLevel: 'warn',
|
|
});
|
|
for (const htmlFile of htmlFiles) {
|
|
const html = readFileSync(htmlFile, 'utf8');
|
|
const inlined = await beasties.process(html);
|
|
writeFileSync(htmlFile, inlined);
|
|
}
|
|
|
|
console.log('Build complete: dist/');
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|