npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@superinstance/build-guardian

v0.2.0

Published

Build Budget Guardian — tracks build resource usage, enforces budgets, detects bloat trends, and integrates with any JS/TS bundler and CI pipeline

Readme

@superinstance/build-guardian

Build Budget Guardian — tracks build resource usage, enforces budgets, detects bloat trends, and integrates with any JS/TS bundler and CI pipeline.

npm version CI

Why?

Builds grow. Bundles bloat. Nobody notices until it's too late. Build Guardian watches your build output over time and tells you when things are getting out of hand — before your users notice.

Features

  • Multi-bundler support — Webpack (multi-compiler, code-split, lazy routes), Vite/Rollup, esbuild
  • Budget enforcement — Set size, time, and memory limits per entry
  • Bloat detection — Automatic alerts when entries grow beyond threshold
  • Configurable alerting rules — Fail CI on growth, warn on total size, detect consecutive growth
  • Trend analysis — Linear regression on per-entry sizes over time
  • Persistence — Save/load build history to JSON, track per-route size over time
  • 4 export formats — Markdown, Prometheus/Grafana, Slack blocks, GitHub PR comments
  • Conservation scores — Prioritize optimization targets by size × frequency × complexity
  • Zero dependencies — Pure TypeScript, no runtime deps

Install

npm install @superinstance/build-guardian

Quick Start

import { BuildBudget } from '@superinstance/build-guardian';

const budget = new BuildBudget({ bloatThreshold: 0.20 });

// Set budgets
budget.addBudget({ entry: 'dashboard', maxSizeBytes: 100 * 1024 });
budget.addBudget({ entry: 'admin/*', maxSizeBytes: 250 * 1024 });

// Record entries from your build
budget.recordEntry({
  entry: 'dashboard',
  buildTimeMs: 1200,
  sizeBytes: 78 * 1024,
  memoryPeakBytes: 150 * 1024 * 1024,
  modules: [
    { name: './Dashboard.tsx', sizeBytes: 15000 },
    { name: 'd3-full', sizeBytes: 45000 },
    { name: 'moment', sizeBytes: 18000 },
  ],
  timestamp: Date.now(),
});

// Finalize and get report
const report = budget.finalizeBuild();
console.log(report.totalSizeBytes);   // 78 * 1024
console.log(report.alerts.length);    // 0 (first build, no history)
console.log(report.violations.length); // 0 (within budget)

API Reference

BuildBudget

Main class for tracking build metrics.

const budget = new BuildBudget({ bloatThreshold: 0.20 });

Methods

| Method | Description | |--------|-------------| | recordEntry(metrics) | Record metrics for a single entry | | finalizeBuild(label?) | Finalize build, run detection, return BuildReport | | addBudget(budget) | Add an entry budget | | setBudgets(budgets) | Replace all budgets | | addAlertRule(rule) | Add an alert rule | | setAlertRules(rules) | Replace all alert rules | | setFrequencyEstimates(estimates) | Set usage frequency per entry | | compareEntry(entry) | Get human-readable comparison text | | loadHistory(pm) | Load persisted history | | saveHistory(pm) | Save history to persistence | | getHistory() | Get build history | | setHistory(history) | Set history (e.g. from persistence) | | reset() | Clear current metrics for new build cycle |

Entry Metrics

interface EntryMetrics {
  entry: string;           // Entry name (e.g. "dashboard")
  buildTimeMs: number;     // Build time in milliseconds
  sizeBytes: number;       // Output size in bytes
  memoryPeakBytes: number; // Peak memory in bytes
  modules?: ModuleEntry[]; // Per-module breakdown
  timestamp: number;       // Measurement timestamp
  route?: string;          // Route path for code-split entries
  isLazy?: boolean;        // Is this lazy-loaded?
  chunkType?: 'entry' | 'chunk' | 'initial';
  hash?: string;           // Chunk hash
}

Alert Rules

import { presetRules } from '@superinstance/build-guardian';

budget.setAlertRules([
  presetRules.failOnLargeGrowth(),       // Fail if any route grows > 20%
  presetRules.warnTotalBundle500kb(),    // Warn if total > 500KB
  presetRules.failEntrySize250kb(),      // Fail if any entry > 250KB
  presetRules.warnBuildTime60s(),        // Warn if build > 60s
  presetRules.warnConsecutiveGrowth(),   // Warn on 3+ consecutive growth builds
]);

Custom rules:

budget.addAlertRule({
  name: 'admin-size',
  type: 'max-entry-size',
  threshold: 100 * 1024,
  severity: 'fail',
  entryPattern: 'admin/*',  // glob pattern
});

Rule types: max-growth, max-total-size, max-entry-size, max-build-time, consecutive-growth.

Bundler Adapters

Webpack

import { analyzeWebpackStats } from '@superinstance/build-guardian';

// Works with stats.toJson() or raw stats JSON
const analyses = analyzeWebpackStats(stats.toJson());

// Multi-compiler support
const analyses = analyzeWebpackStats([clientStats, serverStats]);

Supports: multi-compiler, code-split chunks, lazy-loaded routes, parent/child chunks, chunksByEntryPoint.

Vite / Rollup

import { analyzeViteOutput } from '@superinstance/build-guardian';

const result = await viteBuild();
const analyses = analyzeViteOutput(result);

esbuild

import { analyzeEsbuildMetafile } from '@superinstance/build-guardian';

const analyses = analyzeEsbuildMetafile(metafile);

Export Formats

import { toMarkdown, toPrometheus, toSlack, toGitHubComment } from '@superinstance/build-guardian';

const report = budget.finalizeBuild();

// Markdown report
console.log(toMarkdown(report));

// Prometheus metrics for Grafana
fs.writeFileSync('/metrics/build-guardian.txt', toPrometheus(report));

// Slack Block Kit for CI notifications
const blocks = toSlack(report);
await slackClient.chat.postMessage({ channel: '#builds', blocks });

// GitHub PR comment
const comment = toGitHubComment(report);
await octokit.issues.createComment({ owner, repo, issue_number: pr, body: comment });

Persistence

import { PersistenceManager } from '@superinstance/build-guardian';

const pm = new PersistenceManager({
  filePath: './build-history.json',
  maxHistoryEntries: 100,
});

// Load history before recording
await budget.loadHistory(pm);

// ... record entries and finalize ...

// Save after finalizing
await budget.saveHistory(pm);

// Get per-route size history over time
const routeHistory = await pm.getRouteSizeHistory();

Trend Analysis

import { analyzeTrends } from '@superinstance/build-guardian';

// Automatically computed during finalizeBuild()
const report = budget.finalizeBuild();

for (const trend of report.trends) {
  console.log(`${trend.entry}: ${trend.direction}`);
  console.log(`  Slope: ${trend.slope} bytes/build`);
  console.log(`  ${trend.summary}`);
}

Conservation Scores

Prioritize optimization targets by composite score (size × frequency × complexity):

budget.setFrequencyEstimates(new Map([
  ['home', 50000],       // Very popular
  ['admin', 100],        // Rarely used
]));

const report = budget.finalizeBuild();
// report.scores sorted by score descending

Integration Examples

Webpack Plugin

// webpack.config.ts
import { BuildGuardianWebpackPlugin } from '@superinstance/build-guardian/examples/webpack-plugin';

export default {
  plugins: [
    new BuildGuardianWebpackPlugin({
      budgets: [{ entry: 'main', maxSizeBytes: 250 * 1024 }],
      persist: true,
      failOnError: true,
    }),
  ],
};

Vite Plugin

// vite.config.ts
import { buildGuardianVitePlugin } from '@superinstance/build-guardian/examples/vite-plugin';

export default defineConfig({
  plugins: [buildGuardianVitePlugin({ persist: true })],
});

GitHub Actions

See .github/workflows/ci.yml for the full CI workflow. The key integration:

import { BuildBudget, toGitHubComment, presetRules } from '@superinstance/build-guardian';

// ... after build ...
const report = budget.finalizeBuild();
const comment = toGitHubComment(report);
await octokit.issues.createComment({ ... });

CLI

npx ts-node examples/cli-usage.ts --stats ./build-stats.json --format prometheus --fail-on-violation

Architecture

src/
├── types.ts              # Shared types and utilities
├── budget.ts             # BuildBudget class (core)
├── analyzer.ts           # Webpack & esbuild analyzers
├── reporter.ts           # Markdown report generation
├── alerting.ts           # Configurable alert rules
├── trends.ts             # Trend analysis (linear regression)
├── persistence.ts        # JSON file persistence
├── adapters/
│   └── vite-rollup.ts    # Vite & Rollup adapters
├── export/
│   ├── prometheus.ts     # Prometheus text format
│   ├── slack.ts          # Slack Block Kit
│   ├── markdown.ts       # Refined markdown
│   └── github-comment.ts # GitHub PR comments
└── __tests__/
    └── guardian.test.ts  # 55 tests

Plugins Guide

Build Guardian is designed to be extensible. The BuildBudget class is the core; adapters feed it data, and export formats read its reports.

To create a new adapter:

  1. Create a function that takes your bundler's output
  2. Return ChunkAnalysis[] (see analyzer.ts)
  3. Convert each ChunkAnalysis to EntryMetrics and call budget.recordEntry()

To create a new export format:

  1. Create a function that takes a BuildReport
  2. Return your desired format (string, object, etc.)
  3. See existing exports in src/export/ for patterns

License

MIT © SuperInstance