CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-size-limit

CLI tool and programmatic API for performance budget monitoring that measures JavaScript bundle size and execution time with plugin support for webpack, esbuild, and various bundlers.

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

Size Limit uses a modular plugin architecture that allows different bundlers, measurement tools, and analysis features to be combined flexibly.

Capabilities

Plugin Interface

The plugin system defines a standard interface for extending Size Limit functionality.

// Plugin interface for plugin developers
interface Plugin {
  // Plugin identification
  name: string;                     // Plugin name (e.g., "@size-limit/webpack")
  
  // Lifecycle hooks
  before?(config: object, check: Check): Promise<void>;
  finally?(config: object, check: Check): Promise<void>;
  
  // Processing steps (0-100 available)
  step0?(config: object, check: Check): Promise<void>;
  step1?(config: object, check: Check): Promise<void>;
  // ... step2 through step99
  step100?(config: object, check: Check): Promise<void>;
  
  // Progress messages for steps
  wait0?: string;                   // Progress message for step0
  wait1?: string;                   // Progress message for step1
  // ... wait2 through wait100
}

// Plugin loading system
class Plugins {
  constructor(list: Plugin[]);
  list: Plugin[];                   // Array of loaded plugins
  isEmpty: boolean;                 // True if no plugins loaded
  has(type: string): boolean;       // Check if plugin type is available
}

Core Plugins

Official plugins that provide essential Size Limit functionality.

// File measurement plugin
// Package: @size-limit/file
// Provides: Basic file size measurement with compression options

// Webpack integration plugin  
// Package: @size-limit/webpack
// Provides: Webpack bundling, tree-shaking, custom config support

// ESBuild integration plugin
// Package: @size-limit/esbuild  
// Provides: ESBuild bundling, fast compilation, modern JS support

// Time measurement plugin
// Package: @size-limit/time
// Provides: Browser execution time measurement, network simulation

// CSS support plugin
// Package: @size-limit/webpack-css
// Provides: CSS processing and measurement with webpack

// Bundle analysis plugins
// Package: @size-limit/webpack-why
// Package: @size-limit/esbuild-why  
// Provides: Detailed bundle analysis, dependency graphs, size breakdowns

Plugin Installation

Plugins are installed as separate npm packages and automatically detected.

Usage Examples:

# Install individual plugins
npm install --save-dev @size-limit/file
npm install --save-dev @size-limit/webpack
npm install --save-dev @size-limit/time

# Install preset bundles
npm install --save-dev @size-limit/preset-app
npm install --save-dev @size-limit/preset-big-lib
npm install --save-dev @size-limit/preset-small-lib

Plugin Detection

Size Limit automatically detects and loads available plugins from project dependencies.

// Plugin detection rules:
// 1. Scans package.json dependencies, devDependencies, optionalDependencies
// 2. Matches packages with names starting with "@size-limit/" or "size-limit-"
// 3. Dynamically imports matching packages
// 4. Flattens plugin arrays (plugins can export multiple plugins)
// 5. Creates Plugins instance with loaded plugin list

async function loadPlugins(pkg: PackageInfo): Promise<Plugins>;

interface PackageInfo {
  packageJson: {
    dependencies?: Record<string, string>;
    devDependencies?: Record<string, string>;
    optionalDependencies?: Record<string, string>;
  };
  path: string;
}

Configuration-Based Plugin Usage

Plugins are activated based on configuration options in each check.

// Plugin activation mapping
const PLUGIN_OPTIONS = {
  brotli: "file",                    // @size-limit/file
  gzip: "file",                      // @size-limit/file
  webpack: "webpack",                // @size-limit/webpack
  config: ["webpack", "esbuild"],    // @size-limit/webpack or @size-limit/esbuild
  entry: "webpack",                  // @size-limit/webpack
  ignore: ["webpack", "esbuild"],    // @size-limit/webpack or @size-limit/esbuild
  import: ["webpack", "esbuild"],    // @size-limit/webpack or @size-limit/esbuild
  modifyWebpackConfig: "webpack",    // @size-limit/webpack
  modifyEsbuildConfig: "esbuild",    // @size-limit/esbuild
  running: "time",                   // @size-limit/time
  time: "time",                      // @size-limit/time
  uiReports: "webpack",              // @size-limit/webpack
  compareWith: "webpack"             // @size-limit/webpack
};

Configuration Examples:

{
  "size-limit": [
    {
      "name": "File only",
      "path": "dist/lib.js",
      "webpack": false,
      "running": false
    },
    {
      "name": "Webpack + Time",
      "path": "src/app.js", 
      "webpack": true,
      "running": true,
      "time": {
        "networkSpeed": "3G"
      }
    },
    {
      "name": "ESBuild",
      "path": "src/modern.js",
      "config": "esbuild.config.js",
      "modifyEsbuildConfig": "(config) => ({ ...config, target: 'es2020' })"
    }
  ]
}

Preset Packages

Preset packages provide pre-configured plugin combinations for common use cases.

// @size-limit/preset-app
// Includes: @size-limit/webpack, @size-limit/time, @size-limit/file
// Use case: Large applications with custom bundlers

// @size-limit/preset-big-lib  
// Includes: @size-limit/webpack, @size-limit/file
// Use case: Libraries > 10kB that need bundling

// @size-limit/preset-small-lib
// Includes: @size-limit/file
// Use case: Small libraries < 10kB that don't need bundling

Preset Usage:

# Install preset
npm install --save-dev @size-limit/preset-app

# Configuration automatically uses included plugins
{
  "size-limit": [
    {
      "path": "dist/app.js",
      "limit": "100 kB"
    }
  ]
}

Plugin Execution Flow

Size Limit executes plugins through a structured lifecycle with numbered steps.

// Plugin execution order:
// 1. before() hook for all plugins
// 2. step0() through step100() for all plugins (in sequence)
// 3. finally() hook for all plugins (always executed, even on error)

// Example execution flow:
async function executePlugins(plugins: Plugins, config: object) {
  try {
    // Before phase
    for (let plugin of plugins.list) {
      if (plugin.before) {
        await plugin.before(config, check);
      }
    }
    
    // Step phases  
    for (let stepNumber = 0; stepNumber <= 100; stepNumber++) {
      for (let plugin of plugins.list) {
        const stepMethod = `step${stepNumber}`;
        if (plugin[stepMethod]) {
          await plugin[stepMethod](config, check);
        }
      }
    }
  } finally {
    // Finally phase
    for (let plugin of plugins.list) {
      if (plugin.finally) {
        await plugin.finally(config, check);
      }
    }
  }
}

Creating Custom Plugins

Developers can create custom plugins following the standard interface.

Custom Plugin Example:

// custom-plugin.js
export default {
  name: "custom-size-plugin",
  
  // Initialize plugin
  async before(config, check) {
    console.log(`Starting analysis for ${check.name}`);
  },
  
  // Main processing step
  async step50(config, check) {
    // Custom size calculation logic
    const customSize = await calculateCustomSize(check.files);
    check.customMetric = customSize;
  },
  
  // Cleanup
  async finally(config, check) {
    console.log(`Finished analysis for ${check.name}`);
  },
  
  // Progress messages
  wait50: "Calculating custom metrics..."
};

// Usage with programmatic API
import sizeLimit from "size-limit";
import filePlugin from "@size-limit/file"; 
import customPlugin from "./custom-plugin.js";

const results = await sizeLimit(
  [filePlugin, customPlugin],
  ["dist/bundle.js"]
);

Plugin Development Guidelines

Guidelines for developing Size Limit plugins.

// Plugin development best practices:
// 1. Use descriptive plugin names with @size-limit/ or size-limit- prefix
// 2. Implement appropriate lifecycle hooks (before/finally for setup/cleanup)
// 3. Use numbered steps (step0-step100) for main processing
// 4. Provide wait messages for long-running steps
// 5. Handle errors gracefully and clean up resources in finally
// 6. Modify check objects to add measurements
// 7. Respect existing check properties and plugin interactions
// 8. Document plugin configuration options and requirements

Error Handling in Plugins

Plugin errors are handled gracefully with proper cleanup.

// Error handling flow:
// 1. If any step throws an error, execution stops
// 2. finally() hooks are always called for cleanup
// 3. Progress spinners are marked as failed
// 4. Error is propagated to CLI or API caller

// Error handling example in plugin:
export default {
  name: "example-plugin",
  
  async step10(config, check) {
    try {
      await riskyOperation(check);
    } catch (error) {
      // Log error context
      console.error(`Plugin ${this.name} failed:`, error);
      // Re-throw to stop execution
      throw error;
    }
  },
  
  async finally(config, check) {
    // Always cleanup, even on error
    await cleanup();
  }
};

Install with Tessl CLI

npx tessl i tessl/npm-size-limit

docs

cli-interface.md

configuration.md

error-handling.md

index.md

plugin-system.md

programmatic-api.md

tile.json