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

license-checker-plugin

v2.0.1

Published

A bundler-agnostic plugin to generate third-party license notices for bundled packages. Supports webpack 5, Rspack, and Vite.

Readme

license-checker-plugin

A bundler-agnostic plugin that generates third-party license notices for packages actually bundled into your final build. Supports webpack 5, Rspack, and Vite.

Features

  • Scans the bundler's module graph for used npm packages
  • Reads license metadata using the built-in license checker (zero external dependencies)
  • Emits TXT, JSON, Markdown, or HTML assets at build time
  • Supports compliance rules with built-in presets (commercial, permissive, enterprise, oss, strict, none)
  • Custom policy with allow, review, deny lists
  • Configurable severity for unknown/missing licenses
  • Respects SPDX License Expressions (MIT OR GPL-2.0, MIT AND Apache-2.0)
  • Filter by package name and/or license type
  • Works with webpack 5, Rspack, and Vite

Installation

npm install license-checker-plugin

For webpack/Rspack projects, ensure webpack is installed (peer dependency). For Vite projects, ensure vite is installed (peer dependency).

Usage

webpack / Rspack

const { LicenseWebpackPlugin } = require('license-checker-plugin');

module.exports = {
  mode: 'production',
  plugins: [
    new LicenseWebpackPlugin({
      filename: 'third-party-licenses.txt',
      format: 'txt',
      includeLicenseText: true,
      policy: { preset: 'commercial' },
    }),
  ],
};

Vite

// vite.config.ts
import { defineConfig } from 'vite';
import { viteLicensePlugin } from 'license-checker-plugin';

export default defineConfig({
  plugins: [
    viteLicensePlugin({
      filename: 'third-party-licenses.json',
      format: 'json',
      includeLicenseText: true,
    }),
  ],
});

Options

| Option | Type | Default | Description | |---|---|---|---|---| | filename | string | licenses.txt | Output asset name | | format | 'txt' \| 'json' \| 'markdown' \| 'html' | txt | Output format | | includeLicenseText | boolean | true | Include license text when supported | | includeRepository | boolean | true | Include repository URLs | | includeHomepage | boolean | true | Include homepage URLs | | includeAuthor | boolean | true | Include author/publisher details | | excludePackages | (string \| Function)[] | [] | Exclude listed packages from output | | policy | Policy \| string | { preset: "commercial" } | License compliance policy | | unknownLicense | 'ignore' \| 'warn' \| 'error' | 'warn' | How to handle UNKNOWN licenses | | missingLicense | 'ignore' \| 'warn' \| 'error' | 'warn' | How to handle packages with no license info | | cache | boolean | true | Reuse the in-memory license database | | workspaceRoot | string | Bundler's root context | Root path for license scanning | | recorder | Recorder | — | External recorder shared across compiler instances (webpack only) | | recordOnly | boolean | false | Record findings without emitting (webpack multi-compiler only) | | waitForRecorderCount | number | — | Wait for N reports before emitting combined asset (webpack only) |

Note: recorder, recordOnly, and waitForRecorderCount are webpack-only options and are not available in the Vite plugin.

How it works

The plugin uses a two-phase architecture:

  1. Database phase: Scans node_modules with the built-in license checker to build a comprehensive cache of all package license information.
  2. Scan phase: Inspects the bundler's module graph to find which packages are actually used in the final bundle.

Only packages that appear in the bundler's output are included in the license asset. DevDependencies that are never imported will not appear.

Filtering dependencies by package name

The plugin starts with the set of dependency entries detected from the bundler's module graph, resolves license metadata for those entries, and then applies excludePackages. Package names are matched with exact, case-sensitive string comparison, or via a predicate function.

Transitive dependency behavior

excludePackages is entry-based. Excluding foo removes the foo entry itself, but it does not automatically remove every dependency that foo depends on.

Example

new LicenseWebpackPlugin({
  excludePackages: ['react-dom'],
});

Output formats

TXT

Human-readable notice file for app distribution.

JSON

Machine-readable output for CI, audits, and internal tooling.

Markdown

Useful for GitHub releases or repository documentation.

HTML

Useful for Electron about pages and in-app license views.

License Compliance

The plugin includes a built-in compliance engine that evaluates each bundled package's license against a configurable Policy. Each package gets one of three statuses:

| Status | Description | |----------|---------------------------------| | PASS | License satisfies the policy | | REVIEW | Requires manual review | | FAIL | License does not comply |

The overall build result follows the worst status: any FAIL stops the build; REVIEW packages produce warnings (but do not fail).

Policy

A Policy can reference a built-in preset, or define custom allow/review/deny lists. Custom lists override the preset when both are given.

interface Policy {
  preset?: Preset;
  allow?: string[];   // licenses that always PASS
  review?: string[];  // licenses flagged for manual review
  deny?: string[];    // licenses that FAIL
}

Built-in presets

| Preset | Description | |--------------|--------------------------------------------------| | commercial | Default. Permissive + weak copyleft allowed; strong copyleft denied | | permissive | Only permissive licenses allowed; everything else requires review | | enterprise | Only permissive licenses allowed; all copyleft denied (strong + weak) | | oss | All licenses allowed (no restrictions) | | strict | Whitelist mode. Only allow-listed licenses pass; everything else fails | | none | No compliance checks (all packages pass) |

Preset license categories

| Category | Licenses | |-----------------|-------------------------------------------------------------------------------------------------| | Permissive | MIT, MIT-0, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, CC0-1.0, Unlicense, 0BSD, BSL-1.0, Zlib, Artistic-2.0, Python-2.0, WTFPL, CC-BY-4.0, BlueOak-1.0.0, Unicode-DFS-2015, NCSA | | Weak copyleft | LGPL-2.1*, LGPL-3.0*, MPL-2.0, EPL-1.0, EPL-2.0, CDDL-1.0, EUPL-1.2, PostgreSQL | | Strong copyleft | GPL-2.0*, GPL-3.0*, AGPL-1.0, AGPL-3.0*, SSPL-1.0, OSL-3.0, RPL-1.5 |

* Licenses marked with * also include their -only and -or-later SPDX variants (e.g. GPL-3.0-only, AGPL-3.0-or-later).

Examples

// Use a preset
new LicenseWebpackPlugin({
  policy: { preset: 'commercial' },
});

// Custom allow/deny lists
new LicenseWebpackPlugin({
  policy: {
    allow: ['MIT', 'Apache-2.0'],
    deny: ['GPL-3.0', 'AGPL-3.0'],
  },
});

// Override preset with custom lists
new LicenseWebpackPlugin({
  policy: {
    preset: 'commercial',
    allow: ['MIT', 'Apache-2.0'],  // overrides the preset's allow list
  },
});

// Whitelist mode (strict)
new LicenseWebpackPlugin({
  policy: { preset: 'strict', allow: ['MIT', 'Apache-2.0'] },
});

SPDX Expressions

The engine fully respects SPDX License Expressions:

  • MIT OR GPL-2.0 — passes if any alternative is allowed
  • MIT AND GPL-2.0 — passes only if all licenses are allowed
  • MIT WITH LLVM-exception — exception is handled per SPDX spec

Unknown / missing licenses

| Option | Values | Default | Description | |---|---|---|---| | unknownLicense | 'ignore' / 'warn' / 'error' | 'warn' | How to treat UNKNOWN licenses | | missingLicense | 'ignore' / 'warn' / 'error' | 'warn' | How to treat packages without license info |

new LicenseWebpackPlugin({
  unknownLicense: 'error',   // fail on unknown licenses
  missingLicense: 'ignore',  // silently skip packages with no license field
});

Multi-compiler usage (webpack only)

When using webpack's multi-compiler mode (an array of configurations) each compiler runs independently. The recorder option lets all instances share a single DefaultRecorder so that one primary instance can merge all their findings and emit a single combined license file.

const { LicenseWebpackPlugin, DefaultRecorder } = require('license-checker-plugin');

const sharedRecorder = new DefaultRecorder();

module.exports = [
  {
    name: 'renderer',
    entry: './src/renderer/index.js',
    plugins: [
      new LicenseWebpackPlugin({
        recorder: sharedRecorder,
        recordOnly: true,
      }),
    ],
  },
  {
    name: 'main',
    entry: './src/main/index.js',
    plugins: [
      new LicenseWebpackPlugin({
        filename: 'third-party-licenses.txt',
        recorder: sharedRecorder,
        waitForRecorderCount: 2,
      }),
    ],
  },
];

Recorder interface

export interface Recorder {
  record(report: LicenseBuildReport): void;
  getReports(): LicenseBuildReport[];
  waitForReports(expectedCount?: number, timeoutMs?: number): Promise<LicenseBuildReport[]>;
}

DefaultRecorder is the built-in implementation. It stores reports in memory and resolves waitForReports as soon as the expected count is reached.

API

LicenseWebpackPlugin

webpack/Rspack plugin (class, use with new).

viteLicensePlugin(options)

Vite plugin (function, returns a plugin object).

import { viteLicensePlugin } from 'license-checker-plugin';

LicensePluginCore

Framework-agnostic core that can be used to build adapters for other bundlers.

import { LicensePluginCore } from 'license-checker-plugin';

DefaultRecorder

Built-in recorder implementation for multi-compiler scenarios.

Development

npm install
npm run build
npm test

License

MIT