[![npm][npm]][npm-url] [![node][node]][node-url] [![deps][deps]][deps-url] [![tests][tests]][tests-url] [![cover][cover]][cover-url] [![chat][chat]][chat-url] [![size][size]][size-url] # terser-webpack-plugin This plugin uses [terser](https://github.com/terser-js/terser) to minify your JavaScript. ## Getting Started To begin, you'll need to install `terser-webpack-plugin`: ```console $ npm install terser-webpack-plugin --save-dev ``` Then add the plugin to your `webpack` config. For example: **webpack.config.js** ```js const TerserPlugin = require('terser-webpack-plugin'); module.exports = { optimization: { minimize: true, minimizer: [new TerserPlugin()], }, }; ``` And run `webpack` via your preferred method. ## Options ### `test` Type: `String|RegExp|Array` Default: `/\.m?js(\?.*)?$/i` Test to match files against. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ test: /\.js(\?.*)?$/i, }), ], }, }; ``` ### `include` Type: `String|RegExp|Array` Default: `undefined` Files to include. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ include: /\/includes/, }), ], }, }; ``` ### `exclude` Type: `String|RegExp|Array` Default: `undefined` Files to exclude. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ exclude: /\/excludes/, }), ], }, }; ``` ### `chunkFilter` Type: `Function<(chunk) -> boolean>` Default: `() => true` Allowing to filter which chunks should be uglified (by default all chunks are uglified). Return `true` to uglify the chunk, `false` otherwise. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ chunkFilter: (chunk) => { // Exclude uglification for the `vendor` chunk if (chunk.name === 'vendor') { return false; } return true; }, }), ], }, }; ``` ### `cache` > ⚠ Doesn't work with webpack 5! Type: `Boolean|String` Default: `true` Enable file caching. Default path to cache directory: `node_modules/.cache/terser-webpack-plugin`. > ℹ️ If you use your own `minify` function please read the `minify` section for cache invalidation correctly. #### `Boolean` Enable/disable file caching. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ cache: true, }), ], }, }; ``` #### `String` Enable file caching and set path to cache directory. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ cache: 'path/to/cache', }), ], }, }; ``` ### `cacheKeys` > ⚠ Doesn't work with webpack 5! Type: `Function<(defaultCacheKeys, file) -> Object>` Default: `defaultCacheKeys => defaultCacheKeys` Allows you to override default cache keys. Default cache keys: ```js ({ terser: require('terser/package.json').version, // terser version 'terser-webpack-plugin': require('../package.json').version, // plugin version 'terser-webpack-plugin-options': this.options, // plugin options path: compiler.outputPath ? `${compiler.outputPath}/${file}` : file, // asset path hash: crypto .createHash('md4') .update(input) .digest('hex'), // source file hash }); ``` **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ cache: true, cacheKeys: (defaultCacheKeys, file) => { defaultCacheKeys.myCacheKey = 'myCacheKeyValue'; return defaultCacheKeys; }, }), ], }, }; ``` ### `parallel` Type: `Boolean|Number` Default: `true` Use multi-process parallel running to improve the build speed. Default number of concurrent runs: `os.cpus().length - 1`. > ℹ️ Parallelization can speedup your build significantly and is therefore **highly recommended**. > ⚠️ If you use **Circle CI** or any other environment that doesn't provide real available count of CPUs then you need to setup explicitly number of CPUs to avoid `Error: Call retries were exceeded` (see [#143](https://github.com/webpack-contrib/terser-webpack-plugin/issues/143), [#202](https://github.com/webpack-contrib/terser-webpack-plugin/issues/202)). #### `Boolean` Enable/disable multi-process parallel running. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: true, }), ], }, }; ``` #### `Number` Enable multi-process parallel running and set number of concurrent runs. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ parallel: 4, }), ], }, }; ``` ### `sourceMap` Type: `Boolean` Default: `false` (see below for details around `devtool` value and `SourceMapDevToolPlugin` plugin) **Works only with `source-map`, `inline-source-map`, `hidden-source-map` and `nosources-source-map` values for the [`devtool`](https://webpack.js.org/configuration/devtool/) option.** Why? - `eval` wraps modules in `eval("string")` and the minimizer does not handle strings. - `cheap` has not column information and minimizer generate only a single line, which leave only a single mapping. The plugin respect the [`devtool`](https://webpack.js.org/configuration/devtool/) and using the `SourceMapDevToolPlugin` plugin. Using supported `devtool` values enable source map generation. Using `SourceMapDevToolPlugin` with enabled the `columns` option enables source map generation. Use source maps to map error message locations to modules (this slows down the compilation). If you use your own `minify` function please read the `minify` section for handling source maps correctly. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ sourceMap: true, }), ], }, }; ``` ### `minify` Type: `Function` Default: `undefined` Allows you to override default minify function. By default plugin uses [terser](https://github.com/terser-js/terser) package. Useful for using and testing unpublished versions or forks. > ⚠️ **Always use `require` inside `minify` function when `parallel` option enabled**. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ minify: (file, sourceMap) => { const extractedComments = []; // Custom logic for extract comments const { error, map, code, warnings } = require('uglify-module') // Or require('./path/to/uglify-module') .minify(file, { /* Your options for minification */ }); return { error, map, code, warnings, extractedComments }; }, }), ], }, }; ``` ### `terserOptions` Type: `Object` Default: [default](https://github.com/terser-js/terser#minify-options) Terser minify [options](https://github.com/terser-js/terser#minify-options). **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { ecma: undefined, warnings: false, parse: {}, compress: {}, mangle: true, // Note `mangle.properties` is `false` by default. module: false, output: null, toplevel: false, nameCache: null, ie8: false, keep_classnames: undefined, keep_fnames: false, safari10: false, }, }), ], }, }; ``` ### `extractComments` Type: `Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Object` Default: `true` Whether comments shall be extracted to a separate file, (see [details](https://github.com/webpack/webpack/commit/71933e979e51c533b432658d5e37917f9e71595a)). By default extract only comments using `/^\**!|@preserve|@license|@cc_on/i` regexp condition and remove remaining comments. If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`. The `terserOptions.output.comments` option specifies whether the comment will be preserved, i.e. it is possible to preserve some comments (e.g. annotations) while extracting others or even preserving comments that have been extracted. #### `Boolean` Enable/disable extracting comments. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: true, }), ], }, }; ``` #### `String` Extract `all` or `some` (use `/^\**!|@preserve|@license|@cc_on/i` RegExp) comments. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: 'all', }), ], }, }; ``` #### `RegExp` All comments that match the given expression will be extracted to the separate file. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: /@extract/i, }), ], }, }; ``` #### `Function<(node, comment) -> Boolean>` All comments that match the given expression will be extracted to the separate file. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: (astNode, comment) => { if (/@extract/i.test(comment.value)) { return true; } return false; }, }), ], }, }; ``` #### `Object` Allow to customize condition for extract comments, specify extracted file name and banner. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: { condition: /^\**!|@preserve|@license|@cc_on/i, filename: (file, fileData) => { // ⚠ webpack 5: there is only fileData parameter // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`) // You must consider this // The "fileData" argument contains object with "filename", "basename", "query" return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2'); }, banner: (licenseFile) => { return `License information can be found in ${licenseFile}`; }, }, }), ], }, }; ``` ##### `condition` Type: `Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>` Condition what comments you need extract. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: { condition: 'some', filename: (file, fileData) => { // ⚠ webpack 5: there is only fileData parameter // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`) // You must consider this return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2'); }, banner: (licenseFile) => { return `License information can be found in ${licenseFile}`; }, }, }), ], }, }; ``` ##### `filename` Type: `String|Function<(string) -> String>` Default: `[file].LICENSE.txt[query]` Available placeholders: `[file]`, `[query]` and `[filebase]` (`[base]` for webpack 5). The file where the extracted comments will be stored. Default is to append the suffix `.LICENSE.txt` to the original filename. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: { condition: /^\**!|@preserve|@license|@cc_on/i, filename: 'extracted-comments.js', banner: (licenseFile) => { return `License information can be found in ${licenseFile}`; }, }, }), ], }, }; ``` ##### `banner` Type: `Boolean|String|Function<(string) -> String>` Default: `/*! For license information please see ${commentsFile} */` The banner text that points to the extracted file and will be added on top of the original file. Can be `false` (no banner), a `String`, or a `Function<(string) -> String>` that will be called with the filename where extracted comments have been stored. Will be wrapped into comment. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ extractComments: { condition: true, filename: (file, fileData) => { // ⚠ webpack 5: there is only fileData parameter // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`) // You must consider this return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2'); }, banner: (commentsFile) => { return `My custom banner about license information ${commentsFile}`; }, }, }), ], }, }; ``` ### `warningsFilter` Type: `Function<(warning, source, file) -> Boolean>` Default: `() => true` Allow to filter [terser](https://github.com/terser-js/terser) warnings. Return `true` to keep the warning, a falsy value (`false`/`null`/`undefined`) otherwise. > ⚠️ The `source` argument will contain `undefined` if you don't use source maps. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ warningsFilter: (warning, source, file) => { if (/Dropping unreachable code/i.test(warning)) { return true; } if (/source\.js/i.test(source)) { return true; } if (/file\.js/i.test(file)) { return true; } return false; }, }), ], }, }; ``` ## Examples ### Preserve Comments Extract all legal comments (i.e. `/^\**!|@preserve|@license|@cc_on/i`) and preserve `/@license/i` comments. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { output: { comments: /@license/i, }, }, extractComments: true, }), ], }, }; ``` ### Remove Comments If you avoid building with comments, use this config: **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { output: { comments: false, }, }, extractComments: false, }), ], }, }; ``` ### Custom Minify Function Override default minify function - use `uglify-js` for minification. **webpack.config.js** ```js module.exports = { optimization: { minimize: true, minimizer: [ new TerserPlugin({ // Uncomment lines below for cache invalidation correctly // cache: true, // cacheKeys: (defaultCacheKeys) => { // delete defaultCacheKeys.terser; // // return Object.assign( // {}, // defaultCacheKeys, // { 'uglify-js': require('uglify-js/package.json').version }, // ); // }, minify: (file, sourceMap) => { // https://github.com/mishoo/UglifyJS2#minify-options const uglifyJsOptions = { /* your `uglify-js` package options */ }; if (sourceMap) { uglifyJsOptions.sourceMap = { content: sourceMap, }; } return require('uglify-js').minify(file, uglifyJsOptions); }, }), ], }, }; ``` ## Contributing Please take a moment to read our contributing guidelines if you haven't yet done so. [CONTRIBUTING](./.github/CONTRIBUTING.md) ## License [MIT](./LICENSE) [npm]: https://img.shields.io/npm/v/terser-webpack-plugin.svg [npm-url]: https://npmjs.com/package/terser-webpack-plugin [node]: https://img.shields.io/node/v/terser-webpack-plugin.svg [node-url]: https://nodejs.org [deps]: https://david-dm.org/webpack-contrib/terser-webpack-plugin.svg [deps-url]: https://david-dm.org/webpack-contrib/terser-webpack-plugin [tests]: https://dev.azure.com/webpack-contrib/terser-webpack-plugin/_apis/build/status/webpack-contrib.terser-webpack-plugin?branchName=master [tests-url]: https://dev.azure.com/webpack-contrib/terser-webpack-plugin/_build/latest?definitionId=7&branchName=master [cover]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin/branch/master/graph/badge.svg [cover-url]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin [chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg [chat-url]: https://gitter.im/webpack/webpack [size]: https://packagephobia.now.sh/badge?p=terser-webpack-plugin [size-url]: https://packagephobia.now.sh/result?p=terser-webpack-plugin