67 lines
2 KiB
JavaScript
67 lines
2 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
/**
|
||
|
|
* Bundle size gate — TASK-DEBT-015
|
||
|
|
* Fails the build if initial JS bundle exceeds 200KB gzipped.
|
||
|
|
* Measures: index-*.js + vendor-react-*.js (critical path for first paint).
|
||
|
|
*/
|
||
|
|
import { readdirSync, readFileSync } from 'fs';
|
||
|
|
import { createGzip } from 'zlib';
|
||
|
|
import { dirname, join } from 'path';
|
||
|
|
import { fileURLToPath } from 'url';
|
||
|
|
|
||
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
|
|
const DIST = join(__dirname, '../dist_verification/assets');
|
||
|
|
const MAX_COMBINED_KB = 200;
|
||
|
|
|
||
|
|
function gzipSize(bytes) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
const chunks = [];
|
||
|
|
const gzip = createGzip();
|
||
|
|
gzip.on('data', (chunk) => chunks.push(chunk));
|
||
|
|
gzip.on('end', () => resolve(Buffer.concat(chunks).length));
|
||
|
|
gzip.on('error', reject);
|
||
|
|
gzip.end(bytes);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main() {
|
||
|
|
let dir;
|
||
|
|
try {
|
||
|
|
dir = readdirSync(DIST);
|
||
|
|
} catch (e) {
|
||
|
|
console.error('Run "npm run build" first. dist_verification/assets not found.');
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
|
||
|
|
const indexFile = dir.find((f) => f.startsWith('index-') && f.endsWith('.js'));
|
||
|
|
const vendorReactFile = dir.find((f) => f.startsWith('vendor-react-') && f.endsWith('.js'));
|
||
|
|
|
||
|
|
let totalGzip = 0;
|
||
|
|
const results = [];
|
||
|
|
|
||
|
|
for (const file of [indexFile, vendorReactFile]) {
|
||
|
|
if (!file) continue;
|
||
|
|
const path = join(DIST, file);
|
||
|
|
const bytes = readFileSync(path);
|
||
|
|
const sizeGzip = await gzipSize(bytes);
|
||
|
|
totalGzip += sizeGzip;
|
||
|
|
results.push({ file, kb: (sizeGzip / 1024).toFixed(1) });
|
||
|
|
}
|
||
|
|
|
||
|
|
const totalKb = totalGzip / 1024;
|
||
|
|
console.log('Bundle size (gzipped):');
|
||
|
|
results.forEach((r) => console.log(` ${r.file}: ${r.kb} kB`));
|
||
|
|
console.log(` Total (index + vendor-react): ${totalKb.toFixed(1)} kB`);
|
||
|
|
|
||
|
|
if (totalKb > MAX_COMBINED_KB) {
|
||
|
|
console.error(`\nFAIL: Initial bundle exceeds ${MAX_COMBINED_KB} kB (target: ORIGIN_PERFORMANCE_TARGETS §3.2)`);
|
||
|
|
process.exit(1);
|
||
|
|
}
|
||
|
|
console.log(`\nPASS: Bundle under ${MAX_COMBINED_KB} kB limit.`);
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((e) => {
|
||
|
|
console.error(e);
|
||
|
|
process.exit(1);
|
||
|
|
});
|