minimizer-webpack-plugin

A webpack 5 plugin that minifies JS, CSS, HTML, JSON, and images through pluggable, stackable minimizer implementations.

Library
npm
v5.10.0
1,966stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
86/100Excellent
Development Activity92
Maintenance88
Community64
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
81/100Excellent
Architecture85
Code Quality88
Innovation80
Learning Curve70

minimizer-webpack-plugin is the successor to terser-webpack-plugin, shipped as webpack 5’s default JavaScript minimizer while also handling CSS, HTML, JSON, and image assets through pluggable minifier implementations (Terser, uglify-js, @swc/core, esbuild, cssnano, csso, clean-css, lightningcss, html-minifier-terser, @minify-html/node, sharp, svgo, imagemin, @napi-rs/image, and more). Each asset is matched against a test/include/exclude rule and dispatched to whichever configured minimizer implementations declare support for it, letting a single webpack build stack multiple minimizers across different file types.

Under the hood it runs work in a jest-worker pool when a minimizer supports worker threads, persists results through webpack’s own filesystem cache, and can minify source one asset embeds inside another (e.g. inlined CSS in a JS bundle) or rewrite an asset’s bytes and rename it mid-build for image format conversion. All of this is driven purely through webpack’s own hook system, with version-gated feature detection keeping the plugin usable across a wide range of webpack 5.x releases.

What You Get

  • Built-in JS minification via Terser (default), with drop-in swaps to uglify-js, @swc/core, or esbuild
  • First-party CSS minimizers: cssnano, csso, clean-css, lightningcss, and @swc/css
  • HTML minification through html-minifier-terser, @swc/html, or @minify-html/node
  • Image re-encoding and compression via sharp, svgo, imagemin, or @napi-rs/image
  • A worker-pool architecture that parallelizes minification across CPU cores automatically

Common Use Cases

  • Replacing the default webpack JS minimizer with a faster Rust-based one (swc or esbuild) for large monorepo builds
  • Minifying CSS extracted by mini-css-extract-plugin alongside JavaScript in the same optimization pass
  • Compressing and re-encoding image assets (PNG/JPEG/WebP/AVIF) as part of the production build
  • Stacking several MinimizerPlugin instances to apply different minimizers to different file types in one webpack config

Under The Hood

Architecture The plugin exports a single TerserPlugin class (the name is kept internally for cache-tap and back-compat identity) whose constructor normalizes options (test/include/exclude, a minimizer implementation-and-options pair, and an optional generate pair) and whose apply(compiler) wires everything through webpack’s own hook system rather than any internal orchestrator: initialize/validate runs schema validation via schema-utils against options.json, a compilation hook taps chunkHash for cache-busting, the webpack-5.110+ renderEmbeddedSource/embeddedSourceHash hooks let it minify source one asset embeds inside another, an optional NormalModule processResult tap (webpack >= 5.111 only, feature-detected via try/catch) powers the generate path that can rewrite and rename an asset’s bytes mid-build, and the main pass runs in processAssets at PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE. There, optimize() filters assets through matchesName(), computes per-asset matching minimizer indices by probing each implementation’s filter/getTypes/getEmbeddedTypes capability functions, reads/writes webpack’s persistent cache via compilation.getCache, and dispatches the actual work either into a jest-worker pool (worker threads or child processes, chosen per-minimizer via supportsWorkerThreads) or synchronously in-process, merging any extracted-comments license files that multiple assets share a destination name with.

Tech Stack Plain JavaScript with JSDoc type annotations checked by tsc --noEmit (no separate TypeScript build) rather than authored TypeScript. Core runtime dependencies are schema-utils (options validation), jest-worker (the worker pool), @jridgewell/trace-mapping (source-map tracing for error positions), and terser (the default JS minifier); every other minimizer (uglify-js, @swc/core, esbuild, html-minifier-terser, @minify-html/node, cssnano, csso, clean-css, lightningcss, @swc/css, @swc/html, sharp, svgo, imagemin, @napi-rs/image) is an optional peer dependency loaded lazily. The package is built with @babel/cli (babel.config.js) compiling src to dist, with tsc generating standalone .d.ts files into types/ separately. Releases go through Changesets, git hooks through Husky plus lint-staged, and CI runs via GitHub Actions across a dedicated Node.js workflow, a release workflow, and a dependency-review workflow. The plugin targets webpack ^5.1.0 as a peer dependency and does not support webpack 4.

Code Quality Tests run on Jest (testEnvironment: node, a 60-second timeout to accommodate slower CI webpack builds) across dozens of *-option.test.js files, many using snapshot assertions with a custom hash serializer, and whole test files are skipped (rather than individual blocks) when an optional native dependency isn’t installed, gated by env flags for CSS, image, SWC-HTML, and embedded-source suites. Typing is enforced through JSDoc plus a dedicated lint:types tsc pass in CI, alongside separate ESLint, Prettier, and cspell spell-check lint steps run in parallel via npm-run-all. Error handling is explicit rather than swallowed: TerserPlugin.buildError/buildWarning wrap raw minifier errors with file and source-mapped position context, and every minify() call is wrapped in try/catch that pushes to compilation.errors instead of throwing and crashing the build. Naming is consistent and unusually well-commented, with inline notes explaining non-obvious webpack-version-compatibility branches.

What Makes It Unique Rather than a single-purpose JS minifier, this plugin generalizes into one unified multi-format minimizer: a single instance can dispatch JavaScript, JSON, HTML, CSS, and image assets to different pluggable minimizer implementations chosen per-asset through capability-negotiation functions (supportsBinary, filter, getTypes, getEmbeddedTypes) rather than hardcoded per-format branches, and multiple instances can be stacked for finer per-file-type control. It also reaches into genuinely tricky webpack internals most minifier plugins avoid entirely: minifying source embedded inside another asset’s output (inlined CSS/SVG inside a JS bundle) via the newer renderEmbeddedSource hook, an opt-in generate path that can re-encode and rename an asset during module build (needed for image format conversion), and version-gated hook usage so the same plugin keeps working across a wide span of webpack 5.x releases without requiring the newest APIs.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search