0db85f5dae91368e2c0edaf982ffc6cbfce10f79b827b23c16bba52024236be84fb09b3ad9c9d1ccd1cfd90994c9f540055b3c137b9f7d1afa709bbc1c7b30 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772
  1. <div align="center">
  2. <a href="https://github.com/webpack/webpack">
  3. <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
  4. </a>
  5. </div>
  6. [![npm][npm]][npm-url]
  7. [![node][node]][node-url]
  8. [![deps][deps]][deps-url]
  9. [![tests][tests]][tests-url]
  10. [![cover][cover]][cover-url]
  11. [![chat][chat]][chat-url]
  12. [![size][size]][size-url]
  13. # terser-webpack-plugin
  14. This plugin uses [terser](https://github.com/terser-js/terser) to minify your JavaScript.
  15. ## Getting Started
  16. To begin, you'll need to install `terser-webpack-plugin`:
  17. ```console
  18. $ npm install terser-webpack-plugin --save-dev
  19. ```
  20. Then add the plugin to your `webpack` config. For example:
  21. **webpack.config.js**
  22. ```js
  23. const TerserPlugin = require('terser-webpack-plugin');
  24. module.exports = {
  25. optimization: {
  26. minimize: true,
  27. minimizer: [new TerserPlugin()],
  28. },
  29. };
  30. ```
  31. And run `webpack` via your preferred method.
  32. ## Options
  33. ### `test`
  34. Type: `String|RegExp|Array<String|RegExp>`
  35. Default: `/\.m?js(\?.*)?$/i`
  36. Test to match files against.
  37. **webpack.config.js**
  38. ```js
  39. module.exports = {
  40. optimization: {
  41. minimize: true,
  42. minimizer: [
  43. new TerserPlugin({
  44. test: /\.js(\?.*)?$/i,
  45. }),
  46. ],
  47. },
  48. };
  49. ```
  50. ### `include`
  51. Type: `String|RegExp|Array<String|RegExp>`
  52. Default: `undefined`
  53. Files to include.
  54. **webpack.config.js**
  55. ```js
  56. module.exports = {
  57. optimization: {
  58. minimize: true,
  59. minimizer: [
  60. new TerserPlugin({
  61. include: /\/includes/,
  62. }),
  63. ],
  64. },
  65. };
  66. ```
  67. ### `exclude`
  68. Type: `String|RegExp|Array<String|RegExp>`
  69. Default: `undefined`
  70. Files to exclude.
  71. **webpack.config.js**
  72. ```js
  73. module.exports = {
  74. optimization: {
  75. minimize: true,
  76. minimizer: [
  77. new TerserPlugin({
  78. exclude: /\/excludes/,
  79. }),
  80. ],
  81. },
  82. };
  83. ```
  84. ### `chunkFilter`
  85. Type: `Function<(chunk) -> boolean>`
  86. Default: `() => true`
  87. Allowing to filter which chunks should be uglified (by default all chunks are uglified).
  88. Return `true` to uglify the chunk, `false` otherwise.
  89. **webpack.config.js**
  90. ```js
  91. module.exports = {
  92. optimization: {
  93. minimize: true,
  94. minimizer: [
  95. new TerserPlugin({
  96. chunkFilter: (chunk) => {
  97. // Exclude uglification for the `vendor` chunk
  98. if (chunk.name === 'vendor') {
  99. return false;
  100. }
  101. return true;
  102. },
  103. }),
  104. ],
  105. },
  106. };
  107. ```
  108. ### `cache`
  109. > ⚠ Doesn't work with webpack 5!
  110. Type: `Boolean|String`
  111. Default: `true`
  112. Enable file caching.
  113. Default path to cache directory: `node_modules/.cache/terser-webpack-plugin`.
  114. > ℹ️ If you use your own `minify` function please read the `minify` section for cache invalidation correctly.
  115. #### `Boolean`
  116. Enable/disable file caching.
  117. **webpack.config.js**
  118. ```js
  119. module.exports = {
  120. optimization: {
  121. minimize: true,
  122. minimizer: [
  123. new TerserPlugin({
  124. cache: true,
  125. }),
  126. ],
  127. },
  128. };
  129. ```
  130. #### `String`
  131. Enable file caching and set path to cache directory.
  132. **webpack.config.js**
  133. ```js
  134. module.exports = {
  135. optimization: {
  136. minimize: true,
  137. minimizer: [
  138. new TerserPlugin({
  139. cache: 'path/to/cache',
  140. }),
  141. ],
  142. },
  143. };
  144. ```
  145. ### `cacheKeys`
  146. > ⚠ Doesn't work with webpack 5!
  147. Type: `Function<(defaultCacheKeys, file) -> Object>`
  148. Default: `defaultCacheKeys => defaultCacheKeys`
  149. Allows you to override default cache keys.
  150. Default cache keys:
  151. ```js
  152. ({
  153. terser: require('terser/package.json').version, // terser version
  154. 'terser-webpack-plugin': require('../package.json').version, // plugin version
  155. 'terser-webpack-plugin-options': this.options, // plugin options
  156. path: compiler.outputPath ? `${compiler.outputPath}/${file}` : file, // asset path
  157. hash: crypto
  158. .createHash('md4')
  159. .update(input)
  160. .digest('hex'), // source file hash
  161. });
  162. ```
  163. **webpack.config.js**
  164. ```js
  165. module.exports = {
  166. optimization: {
  167. minimize: true,
  168. minimizer: [
  169. new TerserPlugin({
  170. cache: true,
  171. cacheKeys: (defaultCacheKeys, file) => {
  172. defaultCacheKeys.myCacheKey = 'myCacheKeyValue';
  173. return defaultCacheKeys;
  174. },
  175. }),
  176. ],
  177. },
  178. };
  179. ```
  180. ### `parallel`
  181. Type: `Boolean|Number`
  182. Default: `true`
  183. Use multi-process parallel running to improve the build speed.
  184. Default number of concurrent runs: `os.cpus().length - 1`.
  185. > ℹ️ Parallelization can speedup your build significantly and is therefore **highly recommended**.
  186. > ⚠️ 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)).
  187. #### `Boolean`
  188. Enable/disable multi-process parallel running.
  189. **webpack.config.js**
  190. ```js
  191. module.exports = {
  192. optimization: {
  193. minimize: true,
  194. minimizer: [
  195. new TerserPlugin({
  196. parallel: true,
  197. }),
  198. ],
  199. },
  200. };
  201. ```
  202. #### `Number`
  203. Enable multi-process parallel running and set number of concurrent runs.
  204. **webpack.config.js**
  205. ```js
  206. module.exports = {
  207. optimization: {
  208. minimize: true,
  209. minimizer: [
  210. new TerserPlugin({
  211. parallel: 4,
  212. }),
  213. ],
  214. },
  215. };
  216. ```
  217. ### `sourceMap`
  218. Type: `Boolean`
  219. Default: `false` (see below for details around `devtool` value and `SourceMapDevToolPlugin` plugin)
  220. **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.**
  221. Why?
  222. - `eval` wraps modules in `eval("string")` and the minimizer does not handle strings.
  223. - `cheap` has not column information and minimizer generate only a single line, which leave only a single mapping.
  224. The plugin respect the [`devtool`](https://webpack.js.org/configuration/devtool/) and using the `SourceMapDevToolPlugin` plugin.
  225. Using supported `devtool` values enable source map generation.
  226. Using `SourceMapDevToolPlugin` with enabled the `columns` option enables source map generation.
  227. Use source maps to map error message locations to modules (this slows down the compilation).
  228. If you use your own `minify` function please read the `minify` section for handling source maps correctly.
  229. **webpack.config.js**
  230. ```js
  231. module.exports = {
  232. optimization: {
  233. minimize: true,
  234. minimizer: [
  235. new TerserPlugin({
  236. sourceMap: true,
  237. }),
  238. ],
  239. },
  240. };
  241. ```
  242. ### `minify`
  243. Type: `Function`
  244. Default: `undefined`
  245. Allows you to override default minify function.
  246. By default plugin uses [terser](https://github.com/terser-js/terser) package.
  247. Useful for using and testing unpublished versions or forks.
  248. > ⚠️ **Always use `require` inside `minify` function when `parallel` option enabled**.
  249. **webpack.config.js**
  250. ```js
  251. module.exports = {
  252. optimization: {
  253. minimize: true,
  254. minimizer: [
  255. new TerserPlugin({
  256. minify: (file, sourceMap) => {
  257. const extractedComments = [];
  258. // Custom logic for extract comments
  259. const { error, map, code, warnings } = require('uglify-module') // Or require('./path/to/uglify-module')
  260. .minify(file, {
  261. /* Your options for minification */
  262. });
  263. return { error, map, code, warnings, extractedComments };
  264. },
  265. }),
  266. ],
  267. },
  268. };
  269. ```
  270. ### `terserOptions`
  271. Type: `Object`
  272. Default: [default](https://github.com/terser-js/terser#minify-options)
  273. Terser minify [options](https://github.com/terser-js/terser#minify-options).
  274. **webpack.config.js**
  275. ```js
  276. module.exports = {
  277. optimization: {
  278. minimize: true,
  279. minimizer: [
  280. new TerserPlugin({
  281. terserOptions: {
  282. ecma: undefined,
  283. warnings: false,
  284. parse: {},
  285. compress: {},
  286. mangle: true, // Note `mangle.properties` is `false` by default.
  287. module: false,
  288. output: null,
  289. toplevel: false,
  290. nameCache: null,
  291. ie8: false,
  292. keep_classnames: undefined,
  293. keep_fnames: false,
  294. safari10: false,
  295. },
  296. }),
  297. ],
  298. },
  299. };
  300. ```
  301. ### `extractComments`
  302. Type: `Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Object`
  303. Default: `true`
  304. Whether comments shall be extracted to a separate file, (see [details](https://github.com/webpack/webpack/commit/71933e979e51c533b432658d5e37917f9e71595a)).
  305. By default extract only comments using `/^\**!|@preserve|@license|@cc_on/i` regexp condition and remove remaining comments.
  306. If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`.
  307. 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.
  308. #### `Boolean`
  309. Enable/disable extracting comments.
  310. **webpack.config.js**
  311. ```js
  312. module.exports = {
  313. optimization: {
  314. minimize: true,
  315. minimizer: [
  316. new TerserPlugin({
  317. extractComments: true,
  318. }),
  319. ],
  320. },
  321. };
  322. ```
  323. #### `String`
  324. Extract `all` or `some` (use `/^\**!|@preserve|@license|@cc_on/i` RegExp) comments.
  325. **webpack.config.js**
  326. ```js
  327. module.exports = {
  328. optimization: {
  329. minimize: true,
  330. minimizer: [
  331. new TerserPlugin({
  332. extractComments: 'all',
  333. }),
  334. ],
  335. },
  336. };
  337. ```
  338. #### `RegExp`
  339. All comments that match the given expression will be extracted to the separate file.
  340. **webpack.config.js**
  341. ```js
  342. module.exports = {
  343. optimization: {
  344. minimize: true,
  345. minimizer: [
  346. new TerserPlugin({
  347. extractComments: /@extract/i,
  348. }),
  349. ],
  350. },
  351. };
  352. ```
  353. #### `Function<(node, comment) -> Boolean>`
  354. All comments that match the given expression will be extracted to the separate file.
  355. **webpack.config.js**
  356. ```js
  357. module.exports = {
  358. optimization: {
  359. minimize: true,
  360. minimizer: [
  361. new TerserPlugin({
  362. extractComments: (astNode, comment) => {
  363. if (/@extract/i.test(comment.value)) {
  364. return true;
  365. }
  366. return false;
  367. },
  368. }),
  369. ],
  370. },
  371. };
  372. ```
  373. #### `Object`
  374. Allow to customize condition for extract comments, specify extracted file name and banner.
  375. **webpack.config.js**
  376. ```js
  377. module.exports = {
  378. optimization: {
  379. minimize: true,
  380. minimizer: [
  381. new TerserPlugin({
  382. extractComments: {
  383. condition: /^\**!|@preserve|@license|@cc_on/i,
  384. filename: (file, fileData) => {
  385. // ⚠ webpack 5: there is only fileData parameter
  386. // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
  387. // You must consider this
  388. // The "fileData" argument contains object with "filename", "basename", "query"
  389. return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
  390. },
  391. banner: (licenseFile) => {
  392. return `License information can be found in ${licenseFile}`;
  393. },
  394. },
  395. }),
  396. ],
  397. },
  398. };
  399. ```
  400. ##### `condition`
  401. Type: `Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>`
  402. Condition what comments you need extract.
  403. **webpack.config.js**
  404. ```js
  405. module.exports = {
  406. optimization: {
  407. minimize: true,
  408. minimizer: [
  409. new TerserPlugin({
  410. extractComments: {
  411. condition: 'some',
  412. filename: (file, fileData) => {
  413. // ⚠ webpack 5: there is only fileData parameter
  414. // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
  415. // You must consider this
  416. return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
  417. },
  418. banner: (licenseFile) => {
  419. return `License information can be found in ${licenseFile}`;
  420. },
  421. },
  422. }),
  423. ],
  424. },
  425. };
  426. ```
  427. ##### `filename`
  428. Type: `String|Function<(string) -> String>`
  429. Default: `[file].LICENSE.txt[query]`
  430. Available placeholders: `[file]`, `[query]` and `[filebase]` (`[base]` for webpack 5).
  431. The file where the extracted comments will be stored.
  432. Default is to append the suffix `.LICENSE.txt` to the original filename.
  433. **webpack.config.js**
  434. ```js
  435. module.exports = {
  436. optimization: {
  437. minimize: true,
  438. minimizer: [
  439. new TerserPlugin({
  440. extractComments: {
  441. condition: /^\**!|@preserve|@license|@cc_on/i,
  442. filename: 'extracted-comments.js',
  443. banner: (licenseFile) => {
  444. return `License information can be found in ${licenseFile}`;
  445. },
  446. },
  447. }),
  448. ],
  449. },
  450. };
  451. ```
  452. ##### `banner`
  453. Type: `Boolean|String|Function<(string) -> String>`
  454. Default: `/*! For license information please see ${commentsFile} */`
  455. The banner text that points to the extracted file and will be added on top of the original file.
  456. 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.
  457. Will be wrapped into comment.
  458. **webpack.config.js**
  459. ```js
  460. module.exports = {
  461. optimization: {
  462. minimize: true,
  463. minimizer: [
  464. new TerserPlugin({
  465. extractComments: {
  466. condition: true,
  467. filename: (file, fileData) => {
  468. // ⚠ webpack 5: there is only fileData parameter
  469. // A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
  470. // You must consider this
  471. return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
  472. },
  473. banner: (commentsFile) => {
  474. return `My custom banner about license information ${commentsFile}`;
  475. },
  476. },
  477. }),
  478. ],
  479. },
  480. };
  481. ```
  482. ### `warningsFilter`
  483. Type: `Function<(warning, source, file) -> Boolean>`
  484. Default: `() => true`
  485. Allow to filter [terser](https://github.com/terser-js/terser) warnings.
  486. Return `true` to keep the warning, a falsy value (`false`/`null`/`undefined`) otherwise.
  487. > ⚠️ The `source` argument will contain `undefined` if you don't use source maps.
  488. **webpack.config.js**
  489. ```js
  490. module.exports = {
  491. optimization: {
  492. minimize: true,
  493. minimizer: [
  494. new TerserPlugin({
  495. warningsFilter: (warning, source, file) => {
  496. if (/Dropping unreachable code/i.test(warning)) {
  497. return true;
  498. }
  499. if (/source\.js/i.test(source)) {
  500. return true;
  501. }
  502. if (/file\.js/i.test(file)) {
  503. return true;
  504. }
  505. return false;
  506. },
  507. }),
  508. ],
  509. },
  510. };
  511. ```
  512. ## Examples
  513. ### Preserve Comments
  514. Extract all legal comments (i.e. `/^\**!|@preserve|@license|@cc_on/i`) and preserve `/@license/i` comments.
  515. **webpack.config.js**
  516. ```js
  517. module.exports = {
  518. optimization: {
  519. minimize: true,
  520. minimizer: [
  521. new TerserPlugin({
  522. terserOptions: {
  523. output: {
  524. comments: /@license/i,
  525. },
  526. },
  527. extractComments: true,
  528. }),
  529. ],
  530. },
  531. };
  532. ```
  533. ### Remove Comments
  534. If you avoid building with comments, use this config:
  535. **webpack.config.js**
  536. ```js
  537. module.exports = {
  538. optimization: {
  539. minimize: true,
  540. minimizer: [
  541. new TerserPlugin({
  542. terserOptions: {
  543. output: {
  544. comments: false,
  545. },
  546. },
  547. extractComments: false,
  548. }),
  549. ],
  550. },
  551. };
  552. ```
  553. ### Custom Minify Function
  554. Override default minify function - use `uglify-js` for minification.
  555. **webpack.config.js**
  556. ```js
  557. module.exports = {
  558. optimization: {
  559. minimize: true,
  560. minimizer: [
  561. new TerserPlugin({
  562. // Uncomment lines below for cache invalidation correctly
  563. // cache: true,
  564. // cacheKeys: (defaultCacheKeys) => {
  565. // delete defaultCacheKeys.terser;
  566. //
  567. // return Object.assign(
  568. // {},
  569. // defaultCacheKeys,
  570. // { 'uglify-js': require('uglify-js/package.json').version },
  571. // );
  572. // },
  573. minify: (file, sourceMap) => {
  574. // https://github.com/mishoo/UglifyJS2#minify-options
  575. const uglifyJsOptions = {
  576. /* your `uglify-js` package options */
  577. };
  578. if (sourceMap) {
  579. uglifyJsOptions.sourceMap = {
  580. content: sourceMap,
  581. };
  582. }
  583. return require('uglify-js').minify(file, uglifyJsOptions);
  584. },
  585. }),
  586. ],
  587. },
  588. };
  589. ```
  590. ## Contributing
  591. Please take a moment to read our contributing guidelines if you haven't yet done so.
  592. [CONTRIBUTING](./.github/CONTRIBUTING.md)
  593. ## License
  594. [MIT](./LICENSE)
  595. [npm]: https://img.shields.io/npm/v/terser-webpack-plugin.svg
  596. [npm-url]: https://npmjs.com/package/terser-webpack-plugin
  597. [node]: https://img.shields.io/node/v/terser-webpack-plugin.svg
  598. [node-url]: https://nodejs.org
  599. [deps]: https://david-dm.org/webpack-contrib/terser-webpack-plugin.svg
  600. [deps-url]: https://david-dm.org/webpack-contrib/terser-webpack-plugin
  601. [tests]: https://github.com/webpack-contrib/terser-webpack-plugin/workflows/terser-webpack-plugin/badge.svg
  602. [tests-url]: https://github.com/webpack-contrib/terser-webpack-plugin/actions
  603. [cover]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin/branch/master/graph/badge.svg
  604. [cover-url]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin
  605. [chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg
  606. [chat-url]: https://gitter.im/webpack/webpack
  607. [size]: https://packagephobia.now.sh/badge?p=terser-webpack-plugin
  608. [size-url]: https://packagephobia.now.sh/result?p=terser-webpack-plugin