98 lines
3.4 KiB
JavaScript
98 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
|||
|
|
// Bundle size budget (Gitea #96). The CI "Report bundle sizes" step printed
|
||
|
|
// numbers with nothing to compare them against, so a bundle could balloon
|
||
|
|
// silently. This script compares dist/assets gzip sizes against a small
|
||
|
|
// checked-in budget (scripts/bundle-budget.json) and prints the same report.
|
||
|
|
//
|
||
|
|
// Mode is passed via argv: `pull_request` fails the build over budget,
|
||
|
|
// anything else (e.g. `push`) only warns — a push has already merged, so
|
||
|
|
// blocking it can't prevent the regression, only delay the deploy of an
|
||
|
|
// otherwise-good commit; the pull_request gate is where this should be caught.
|
||
|
|
import { appendFileSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
||
|
|
import { gzipSync } from 'node:zlib';
|
||
|
|
import path from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
|
||
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||
|
|
const mode = process.argv[2] || 'push';
|
||
|
|
const distAssetsDir = path.join(__dirname, '..', 'dist', 'assets');
|
||
|
|
const budgetPath = path.join(__dirname, 'bundle-budget.json');
|
||
|
|
|
||
|
|
function formatKb(bytes) {
|
||
|
|
return `${(bytes / 1024).toFixed(1)} kB`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function main() {
|
||
|
|
const budget = JSON.parse(readFileSync(budgetPath, 'utf-8'));
|
||
|
|
|
||
|
|
const jsFiles = readdirSync(distAssetsDir)
|
||
|
|
.filter((f) => f.endsWith('.js') && !f.endsWith('.map'))
|
||
|
|
.sort();
|
||
|
|
|
||
|
|
if (jsFiles.length === 0) {
|
||
|
|
console.error(
|
||
|
|
`[check-bundle-size] No .js files found in ${distAssetsDir} — did the build run?`,
|
||
|
|
);
|
||
|
|
process.exitCode = 1;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const rows = jsFiles.map((name) => {
|
||
|
|
const filePath = path.join(distAssetsDir, name);
|
||
|
|
const size = statSync(filePath).size;
|
||
|
|
const gzipSize = gzipSync(readFileSync(filePath)).length;
|
||
|
|
return { name, size, gzipSize };
|
||
|
|
});
|
||
|
|
|
||
|
|
const totalGzipBytes = rows.reduce((sum, r) => sum + r.gzipSize, 0);
|
||
|
|
const largest = rows.reduce((max, r) => (r.gzipSize > max.gzipSize ? r : max), rows[0]);
|
||
|
|
|
||
|
|
const summaryLines = [
|
||
|
|
'### Bundle sizes',
|
||
|
|
'',
|
||
|
|
'| File | Size | Gzip |',
|
||
|
|
'|------|------|------|',
|
||
|
|
...rows.map((r) => `| ${r.name} | ${formatKb(r.size)} | ${formatKb(r.gzipSize)} |`),
|
||
|
|
'',
|
||
|
|
`**Total gzip:** ${formatKb(totalGzipBytes)} (budget ${formatKb(budget.totalGzipBytes)})`,
|
||
|
|
`**Largest chunk gzip:** ${largest.name} — ${formatKb(largest.gzipSize)} (budget ${formatKb(
|
||
|
|
budget.largestChunkGzipBytes,
|
||
|
|
)})`,
|
||
|
|
];
|
||
|
|
|
||
|
|
const summaryText = summaryLines.join('\n');
|
||
|
|
console.log(summaryText);
|
||
|
|
if (process.env.GITHUB_STEP_SUMMARY) {
|
||
|
|
// Gitea Actions/act_runner honors the same GITHUB_STEP_SUMMARY convention.
|
||
|
|
appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${summaryText}\n`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const overBudget = [];
|
||
|
|
if (totalGzipBytes > budget.totalGzipBytes) {
|
||
|
|
overBudget.push(
|
||
|
|
`total gzip ${formatKb(totalGzipBytes)} exceeds budget ${formatKb(budget.totalGzipBytes)}`,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if (largest.gzipSize > budget.largestChunkGzipBytes) {
|
||
|
|
overBudget.push(
|
||
|
|
`largest chunk (${largest.name}) gzip ${formatKb(largest.gzipSize)} exceeds budget ${formatKb(
|
||
|
|
budget.largestChunkGzipBytes,
|
||
|
|
)}`,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (overBudget.length > 0) {
|
||
|
|
const message = `[check-bundle-size] Over budget: ${overBudget.join('; ')}`;
|
||
|
|
if (mode === 'pull_request') {
|
||
|
|
console.error(message);
|
||
|
|
process.exitCode = 1;
|
||
|
|
} else {
|
||
|
|
console.warn(`${message} (warning only on "${mode}")`);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
console.log('[check-bundle-size] Within budget.');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
main();
|