vite-plugin-bundlesize
Version:
Monitor bundle sizes and analyze bundle contents
102 lines • 5.69 kB
JavaScript
import picomatch from "picomatch";
import { DIM, FG_GREEN_79, FG_MAGENTA_200, FG_RED_197, FG_YELLOW_220, RESET, padLeft, padRight, parseSize, } from "./lib.js";
export const DEFAULT_LIMIT = 150_000; // 150 kB
const COLS = Math.min(process.stdout.columns || 80, 120);
const nf = new Intl.NumberFormat("en-us", { maximumFractionDigits: 1 });
export default function analyze({ bundlemeta, config, version, }) {
// 1. print header
console.log(`${FG_MAGENTA_200}⚡ vite-plugin-bundlesize${RESET}
${DIM}v${version}${RESET}`);
console.log(""); // newline
const passed = [];
const chunks = [];
const sizes = [];
const limits = [];
for (const entry of Object.values(bundlemeta.chunks)) {
if (!entry.isEntry) {
continue;
}
const globMatch = config.limits.find((l) => l.name && picomatch(l.name)(entry.id));
if (!globMatch) {
console.log(`${FG_YELLOW_220}! Entry "${entry.id}" not matched by any patterns in bundlesize.limits. Using default size of 150 kB.`);
}
const limit = globMatch || { name: "**/*", limit: DEFAULT_LIMIT };
const maxSize = typeof limit.limit === "string" ? parseSize(limit.limit) : limit.limit;
const entrySize = {
uncompressed: entry.size,
gzip: entry.sizeGzip,
brotli: entry.sizeBrotli,
}[limit.mode || "uncompressed"];
passed.push(!Number.isFinite(maxSize) || maxSize <= 0 || entrySize <= maxSize);
chunks.push(entry);
sizes.push(nf.format(entrySize / 1000));
limits.push(`${nf.format((typeof limit.limit === "string" ? parseSize(limit.limit) : limit.limit) / 1000)} kB${limit.mode === "gzip" ? " (gz)" : limit.mode === "brotli" ? " (br)" : ""}`);
}
if (passed.every((status) => status === true)) {
console.log(`${FG_GREEN_79}All chunks within size limit!${RESET}`);
}
else {
console.log(`${FG_RED_197}The following chunks exceeded the size limit:${RESET}`);
}
for (let i = 0; i < chunks.length; i++) {
console.log(`${passed[i] ? `${FG_GREEN_79}✔${RESET}` : `${FG_RED_197}✘${RESET}`} ${padRight(chunks[i].id, Math.max(...chunks.map((c) => c.id.length)))} ${passed[i] ? FG_GREEN_79 : FG_RED_197}${padLeft(sizes[i], Math.max(...sizes.map((s) => s.length)))} / ${padLeft(limits[i], Math.max(...limits.map((l) => l.length)))}${RESET}`);
}
// 2. print details
console.log(""); // newline
for (let i = 0; i < chunks.length; i++) {
const nodeModulesTotal = Object.values(chunks[i].contents).reduce((size, c) => size + (c.packageName ? c.size : 0), 0);
const ls = passed[i]
? `${FG_GREEN_79}│ ${RESET}`
: `${FG_RED_197}│ ${RESET}`;
console.log(`${passed[i] ? `${FG_GREEN_79}✔${RESET}` : `${FG_RED_197}✘${RESET}`} ${chunks[i].id}`);
console.log(`${ls}${passed[i] ? FG_GREEN_79 : FG_RED_197}${sizes[i]} / ${limits[i]}${RESET}`);
const a = nf.format(nodeModulesTotal / 1000);
const b = nf.format((chunks[i].size - nodeModulesTotal) / 1000);
console.log(`${ls}${DIM}- node_modules ${padLeft(a, Math.max(a.length, b.length))} kB (uncompressed)${RESET}`);
console.log(`${ls}${DIM}- local ${padLeft(b, Math.max(a.length, b.length))} kB (uncompressed)${RESET}`);
console.log(ls); // newline
// biggest modules (show only if check failed)
if (!passed[i] || config.stats === "all") {
const nodeModulesSizes = {};
for (const c of Object.values(chunks[i].contents)) {
if (c.packageName) {
if (!(c.packageName in nodeModulesSizes)) {
nodeModulesSizes[c.packageName] = 0;
}
nodeModulesSizes[c.packageName] += c.size;
}
}
const sortedNodeModules = Object.entries(nodeModulesSizes);
sortedNodeModules.sort((a, b) => b[1] - a[1]);
console.log(`${passed[i] ? FG_GREEN_79 : FG_RED_197}├─${RESET} Biggest modules`);
console.log(ls); // newline
let remainingModuleSize = nodeModulesTotal;
for (const [packageName, size] of config.stats === "all"
? sortedNodeModules
: sortedNodeModules.slice(0, 25)) {
const maxLength = COLS - 3; // 3 characters = prefix
const displaySize = `${nf.format(size / 1000)} kB`;
const perc = size / chunks[i].size;
const displayPerc = `(${nf.format(100 * perc)}%)`;
console.log(`${ls}${packageName}${padLeft(`${displaySize} ${DIM}${displayPerc}${RESET}`, maxLength - packageName.length)}${RESET}`);
const bar = Math.round(maxLength * perc);
console.log(`${ls}${FG_RED_197}${"=".repeat(bar)}${RESET}${"-".repeat(maxLength - bar)}${RESET}`);
remainingModuleSize -= size;
}
if (config.stats === "summary" && sortedNodeModules.length > 25) {
const remaining = sortedNodeModules.length - 25;
console.log(`${ls}${DIM}… and ${remaining} other${remaining !== 1 ? "s" : ""} (${nf.format(remainingModuleSize / 1000)} kB)${RESET}`);
}
}
// connecting line to next chunk
if (i < chunks.length - 1) {
console.log(ls); // newline
console.log(ls); // newline
}
}
// 3. exit process with error code if some failed (if enabled)
if (!config.allowFail && passed.some((status) => status === false)) {
process.exit(1);
}
}
//# sourceMappingURL=index.js.map