57 lines
2.1 KiB
JavaScript
57 lines
2.1 KiB
JavaScript
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
import { gzipSync } from 'node:zlib';
|
|
import { basename, join, resolve } from 'node:path';
|
|
|
|
const root = resolve(process.cwd());
|
|
const dist = resolve(root, 'dist');
|
|
const assets = join(dist, 'assets');
|
|
const budgets = {
|
|
initialJsGzip: 350 * 1024,
|
|
initialCssGzip: 30 * 1024,
|
|
fontsBytes: 2 * 1024 * 1024,
|
|
moduleMediaBytes: 1 * 1024 * 1024,
|
|
};
|
|
|
|
function readAsset(relativePath) {
|
|
return readFileSync(join(dist, relativePath));
|
|
}
|
|
|
|
function gzipBytes(bytes) {
|
|
return gzipSync(bytes, { level: 9 }).byteLength;
|
|
}
|
|
|
|
function formatBytes(bytes) {
|
|
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
}
|
|
|
|
if (!existsSync(join(dist, 'index.html')) || !existsSync(assets)) {
|
|
console.error('性能预算检查需要先运行 pnpm run build:vite。');
|
|
process.exit(1);
|
|
}
|
|
|
|
const html = readFileSync(join(dist, 'index.html'), 'utf8');
|
|
const initialJs = [...html.matchAll(/<script[^>]+src="\.\/([^\"]+\.js)"/g)]
|
|
.map((match) => match[1])
|
|
.reduce((total, relativePath) => total + gzipBytes(readAsset(relativePath)), 0);
|
|
const initialCss = [...html.matchAll(/<link[^>]+href="\.\/([^\"]+\.css)"/g)]
|
|
.map((match) => match[1])
|
|
.reduce((total, relativePath) => total + gzipBytes(readAsset(relativePath)), 0);
|
|
const assetNames = readdirSync(assets);
|
|
const fontBytes = assetNames
|
|
.filter((name) => /\.(woff2?|otf|ttf)$/i.test(name))
|
|
.reduce((total, name) => total + statSync(join(assets, name)).size, 0);
|
|
const moduleMediaBytes = assetNames
|
|
.filter((name) => /^module-.*\.(avif|webp|png|jpe?g)$/i.test(name))
|
|
.reduce((total, name) => total + statSync(join(assets, name)).size, 0);
|
|
|
|
const metrics = { initialJsGzip: initialJs, initialCssGzip: initialCss, fontsBytes: fontBytes, moduleMediaBytes };
|
|
console.log(JSON.stringify({ metrics, budgets }, null, 2));
|
|
|
|
const failures = Object.entries(budgets)
|
|
.filter(([key, budget]) => metrics[key] > budget)
|
|
.map(([key, budget]) => `${key} ${formatBytes(metrics[key])} > ${formatBytes(budget)}`);
|
|
if (failures.length > 0) {
|
|
console.error(`性能预算超标:${failures.join('; ')}`);
|
|
process.exit(1);
|
|
}
|