UNPKG

21.1 kBMarkdownView Raw
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
7[![npm][npm]][npm-url]
8[![node][node]][node-url]
9[![tests][tests]][tests-url]
10[![cover][cover]][cover-url]
11[![discussion][discussion]][discussion-url]
12[![size][size]][size-url]
13
14# terser-webpack-plugin
15
16This plugin uses [terser](https://github.com/terser/terser) to minify/minimize your JavaScript.
17
18## Getting Started
19
20Webpack v5 comes with the latest `terser-webpack-plugin` out of the box. If you are using Webpack v5 or above and wish to customize the options, you will still need to install `terser-webpack-plugin`. Using Webpack v4, you have to install `terser-webpack-plugin` v4.
21
22To begin, you'll need to install `terser-webpack-plugin`:
23
24```console
25npm install terser-webpack-plugin --save-dev
26```
27
28or
29
30```console
31yarn add -D terser-webpack-plugin
32```
33
34or
35
36```console
37pnpm add -D terser-webpack-plugin
38```
39
40Then add the plugin to your `webpack` config. For example:
41
42**webpack.config.js**
43
44```js
45const TerserPlugin = require("terser-webpack-plugin");
46
47module.exports = {
48 optimization: {
49 minimize: true,
50 minimizer: [new TerserPlugin()],
51 },
52};
53```
54
55And run `webpack` via your preferred method.
56
57## Note about source maps
58
59**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.**
60
61Why?
62
63- `eval` wraps modules in `eval("string")` and the minimizer does not handle strings.
64- `cheap` has not column information and minimizer generate only a single line, which leave only a single mapping.
65
66Using supported `devtool` values enable source map generation.
67
68## Options
69
70- **[`test`](#test)**
71- **[`include`](#include)**
72- **[`exclude`](#exclude)**
73- **[`parallel`](#parallel)**
74- **[`minify`](#minify)**
75- **[`terserOptions`](#terseroptions)**
76- **[`extractComments`](#extractcomments)**
77
78### `test`
79
80Type:
81
82```ts
83type test = string | RegExp | Array<string | RegExp>;
84```
85
86Default: `/\.m?js(\?.*)?$/i`
87
88Test to match files against.
89
90**webpack.config.js**
91
92```js
93module.exports = {
94 optimization: {
95 minimize: true,
96 minimizer: [
97 new TerserPlugin({
98 test: /\.js(\?.*)?$/i,
99 }),
100 ],
101 },
102};
103```
104
105### `include`
106
107Type:
108
109```ts
110type include = string | RegExp | Array<string | RegExp>;
111```
112
113Default: `undefined`
114
115Files to include.
116
117**webpack.config.js**
118
119```js
120module.exports = {
121 optimization: {
122 minimize: true,
123 minimizer: [
124 new TerserPlugin({
125 include: /\/includes/,
126 }),
127 ],
128 },
129};
130```
131
132### `exclude`
133
134Type:
135
136```ts
137type exclude = string | RegExp | Array<string | RegExp>;
138```
139
140Default: `undefined`
141
142Files to exclude.
143
144**webpack.config.js**
145
146```js
147module.exports = {
148 optimization: {
149 minimize: true,
150 minimizer: [
151 new TerserPlugin({
152 exclude: /\/excludes/,
153 }),
154 ],
155 },
156};
157```
158
159### `parallel`
160
161Type:
162
163```ts
164type parallel = boolean | number;
165```
166
167Default: `true`
168
169Use multi-process parallel running to improve the build speed.
170Default number of concurrent runs: `os.cpus().length - 1`.
171
172> **Note**
173>
174> Parallelization can speedup your build significantly and is therefore **highly recommended**.
175
176> **Warning**
177>
178> 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)).
179
180#### `boolean`
181
182Enable/disable multi-process parallel running.
183
184**webpack.config.js**
185
186```js
187module.exports = {
188 optimization: {
189 minimize: true,
190 minimizer: [
191 new TerserPlugin({
192 parallel: true,
193 }),
194 ],
195 },
196};
197```
198
199#### `number`
200
201Enable multi-process parallel running and set number of concurrent runs.
202
203**webpack.config.js**
204
205```js
206module.exports = {
207 optimization: {
208 minimize: true,
209 minimizer: [
210 new TerserPlugin({
211 parallel: 4,
212 }),
213 ],
214 },
215};
216```
217
218### `minify`
219
220Type:
221
222```ts
223type minify = (
224 input: {
225 [file: string]: string;
226 },
227 sourceMap: import("@jridgewell/trace-mapping").SourceMapInput | undefined,
228 minifyOptions: {
229 module?: boolean | undefined;
230 ecma?: import("terser").ECMA | undefined;
231 },
232 extractComments:
233 | boolean
234 | "all"
235 | "some"
236 | RegExp
237 | ((
238 astNode: any,
239 comment: {
240 value: string;
241 type: "comment1" | "comment2" | "comment3" | "comment4";
242 pos: number;
243 line: number;
244 col: number;
245 }
246 ) => boolean)
247 | {
248 condition?:
249 | boolean
250 | "all"
251 | "some"
252 | RegExp
253 | ((
254 astNode: any,
255 comment: {
256 value: string;
257 type: "comment1" | "comment2" | "comment3" | "comment4";
258 pos: number;
259 line: number;
260 col: number;
261 }
262 ) => boolean)
263 | undefined;
264 filename?: string | ((fileData: any) => string) | undefined;
265 banner?:
266 | string
267 | boolean
268 | ((commentsFile: string) => string)
269 | undefined;
270 }
271 | undefined
272) => Promise<{
273 code: string;
274 map?: import("@jridgewell/trace-mapping").SourceMapInput | undefined;
275 errors?: (string | Error)[] | undefined;
276 warnings?: (string | Error)[] | undefined;
277 extractedComments?: string[] | undefined;
278}>;
279```
280
281Default: `TerserPlugin.terserMinify`
282
283Allows you to override default minify function.
284By default plugin uses [terser](https://github.com/terser/terser) package.
285Useful for using and testing unpublished versions or forks.
286
287> **Warning**
288>
289> **Always use `require` inside `minify` function when `parallel` option enabled**.
290
291**webpack.config.js**
292
293```js
294// Can be async
295const minify = (input, sourceMap, minimizerOptions, extractsComments) => {
296 // The `minimizerOptions` option contains option from the `terserOptions` option
297 // You can use `minimizerOptions.myCustomOption`
298
299 // Custom logic for extract comments
300 const { map, code } = require("uglify-module") // Or require('./path/to/uglify-module')
301 .minify(input, {
302 /* Your options for minification */
303 });
304
305 return { map, code, warnings: [], errors: [], extractedComments: [] };
306};
307
308// Used to regenerate `fullhash`/`chunkhash` between different implementation
309// Example: you fix a bug in custom minimizer/custom function, but unfortunately webpack doesn't know about it, so you will get the same fullhash/chunkhash
310// to avoid this you can provide version of your custom minimizer
311// You don't need if you use only `contenthash`
312minify.getMinimizerVersion = () => {
313 let packageJson;
314
315 try {
316 // eslint-disable-next-line global-require, import/no-extraneous-dependencies
317 packageJson = require("uglify-module/package.json");
318 } catch (error) {
319 // Ignore
320 }
321
322 return packageJson && packageJson.version;
323};
324
325module.exports = {
326 optimization: {
327 minimize: true,
328 minimizer: [
329 new TerserPlugin({
330 terserOptions: {
331 myCustomOption: true,
332 },
333 minify,
334 }),
335 ],
336 },
337};
338```
339
340### `terserOptions`
341
342Type:
343
344```ts
345type terserOptions = {
346 compress?: boolean | CompressOptions;
347 ecma?: ECMA;
348 enclose?: boolean | string;
349 ie8?: boolean;
350 keep_classnames?: boolean | RegExp;
351 keep_fnames?: boolean | RegExp;
352 mangle?: boolean | MangleOptions;
353 module?: boolean;
354 nameCache?: object;
355 format?: FormatOptions;
356 /** @deprecated */
357 output?: FormatOptions;
358 parse?: ParseOptions;
359 safari10?: boolean;
360 sourceMap?: boolean | SourceMapOptions;
361 toplevel?: boolean;
362};
363```
364
365Default: [default](https://github.com/terser/terser#minify-options)
366
367Terser [options](https://github.com/terser/terser#minify-options).
368
369**webpack.config.js**
370
371```js
372module.exports = {
373 optimization: {
374 minimize: true,
375 minimizer: [
376 new TerserPlugin({
377 terserOptions: {
378 ecma: undefined,
379 parse: {},
380 compress: {},
381 mangle: true, // Note `mangle.properties` is `false` by default.
382 module: false,
383 // Deprecated
384 output: null,
385 format: null,
386 toplevel: false,
387 nameCache: null,
388 ie8: false,
389 keep_classnames: undefined,
390 keep_fnames: false,
391 safari10: false,
392 },
393 }),
394 ],
395 },
396};
397```
398
399### `extractComments`
400
401Type:
402
403```ts
404type extractComments =
405 | boolean
406 | string
407 | RegExp
408 | ((
409 astNode: any,
410 comment: {
411 value: string;
412 type: "comment1" | "comment2" | "comment3" | "comment4";
413 pos: number;
414 line: number;
415 col: number;
416 }
417 ) => boolean)
418 | {
419 condition?:
420 | boolean
421 | "all"
422 | "some"
423 | RegExp
424 | ((
425 astNode: any,
426 comment: {
427 value: string;
428 type: "comment1" | "comment2" | "comment3" | "comment4";
429 pos: number;
430 line: number;
431 col: number;
432 }
433 ) => boolean)
434 | undefined;
435 filename?: string | ((fileData: any) => string) | undefined;
436 banner?:
437 | string
438 | boolean
439 | ((commentsFile: string) => string)
440 | undefined;
441 };
442```
443
444Default: `true`
445
446Whether comments shall be extracted to a separate file, (see [details](https://github.com/webpack/webpack/commit/71933e979e51c533b432658d5e37917f9e71595a)).
447By default extract only comments using `/^\**!|@preserve|@license|@cc_on/i` regexp condition and remove remaining comments.
448If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`.
449The `terserOptions.format.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.
450
451#### `boolean`
452
453Enable/disable extracting comments.
454
455**webpack.config.js**
456
457```js
458module.exports = {
459 optimization: {
460 minimize: true,
461 minimizer: [
462 new TerserPlugin({
463 extractComments: true,
464 }),
465 ],
466 },
467};
468```
469
470#### `string`
471
472Extract `all` or `some` (use `/^\**!|@preserve|@license|@cc_on/i` RegExp) comments.
473
474**webpack.config.js**
475
476```js
477module.exports = {
478 optimization: {
479 minimize: true,
480 minimizer: [
481 new TerserPlugin({
482 extractComments: "all",
483 }),
484 ],
485 },
486};
487```
488
489#### `RegExp`
490
491All comments that match the given expression will be extracted to the separate file.
492
493**webpack.config.js**
494
495```js
496module.exports = {
497 optimization: {
498 minimize: true,
499 minimizer: [
500 new TerserPlugin({
501 extractComments: /@extract/i,
502 }),
503 ],
504 },
505};
506```
507
508#### `function`
509
510All comments that match the given expression will be extracted to the separate file.
511
512**webpack.config.js**
513
514```js
515module.exports = {
516 optimization: {
517 minimize: true,
518 minimizer: [
519 new TerserPlugin({
520 extractComments: (astNode, comment) => {
521 if (/@extract/i.test(comment.value)) {
522 return true;
523 }
524
525 return false;
526 },
527 }),
528 ],
529 },
530};
531```
532
533#### `object`
534
535Allow to customize condition for extract comments, specify extracted file name and banner.
536
537**webpack.config.js**
538
539```js
540module.exports = {
541 optimization: {
542 minimize: true,
543 minimizer: [
544 new TerserPlugin({
545 extractComments: {
546 condition: /^\**!|@preserve|@license|@cc_on/i,
547 filename: (fileData) => {
548 // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
549 return `${fileData.filename}.LICENSE.txt${fileData.query}`;
550 },
551 banner: (licenseFile) => {
552 return `License information can be found in ${licenseFile}`;
553 },
554 },
555 }),
556 ],
557 },
558};
559```
560
561##### `condition`
562
563Type:
564
565```ts
566type condition =
567 | boolean
568 | "all"
569 | "some"
570 | RegExp
571 | ((
572 astNode: any,
573 comment: {
574 value: string;
575 type: "comment1" | "comment2" | "comment3" | "comment4";
576 pos: number;
577 line: number;
578 col: number;
579 }
580 ) => boolean)
581 | undefined;
582```
583
584Condition what comments you need extract.
585
586**webpack.config.js**
587
588```js
589module.exports = {
590 optimization: {
591 minimize: true,
592 minimizer: [
593 new TerserPlugin({
594 extractComments: {
595 condition: "some",
596 filename: (fileData) => {
597 // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
598 return `${fileData.filename}.LICENSE.txt${fileData.query}`;
599 },
600 banner: (licenseFile) => {
601 return `License information can be found in ${licenseFile}`;
602 },
603 },
604 }),
605 ],
606 },
607};
608```
609
610##### `filename`
611
612Type:
613
614```ts
615type filename = string | ((fileData: any) => string) | undefined;
616```
617
618Default: `[file].LICENSE.txt[query]`
619
620Available placeholders: `[file]`, `[query]` and `[filebase]` (`[base]` for webpack 5).
621
622The file where the extracted comments will be stored.
623Default is to append the suffix `.LICENSE.txt` to the original filename.
624
625> **Warning**
626>
627> We highly recommend using the `txt` extension. Using `js`/`cjs`/`mjs` extensions may conflict with existing assets which leads to broken code.
628
629**webpack.config.js**
630
631```js
632module.exports = {
633 optimization: {
634 minimize: true,
635 minimizer: [
636 new TerserPlugin({
637 extractComments: {
638 condition: /^\**!|@preserve|@license|@cc_on/i,
639 filename: "extracted-comments.js",
640 banner: (licenseFile) => {
641 return `License information can be found in ${licenseFile}`;
642 },
643 },
644 }),
645 ],
646 },
647};
648```
649
650##### `banner`
651
652Type:
653
654```ts
655type banner = string | boolean | ((commentsFile: string) => string) | undefined;
656```
657
658Default: `/*! For license information please see ${commentsFile} */`
659
660The banner text that points to the extracted file and will be added on top of the original file.
661Can be `false` (no banner), a `String`, or a `Function<(string) -> String>` that will be called with the filename where extracted comments have been stored.
662Will be wrapped into comment.
663
664**webpack.config.js**
665
666```js
667module.exports = {
668 optimization: {
669 minimize: true,
670 minimizer: [
671 new TerserPlugin({
672 extractComments: {
673 condition: true,
674 filename: (fileData) => {
675 // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
676 return `${fileData.filename}.LICENSE.txt${fileData.query}`;
677 },
678 banner: (commentsFile) => {
679 return `My custom banner about license information ${commentsFile}`;
680 },
681 },
682 }),
683 ],
684 },
685};
686```
687
688## Examples
689
690### Preserve Comments
691
692Extract all legal comments (i.e. `/^\**!|@preserve|@license|@cc_on/i`) and preserve `/@license/i` comments.
693
694**webpack.config.js**
695
696```js
697module.exports = {
698 optimization: {
699 minimize: true,
700 minimizer: [
701 new TerserPlugin({
702 terserOptions: {
703 format: {
704 comments: /@license/i,
705 },
706 },
707 extractComments: true,
708 }),
709 ],
710 },
711};
712```
713
714### Remove Comments
715
716If you avoid building with comments, use this config:
717
718**webpack.config.js**
719
720```js
721module.exports = {
722 optimization: {
723 minimize: true,
724 minimizer: [
725 new TerserPlugin({
726 terserOptions: {
727 format: {
728 comments: false,
729 },
730 },
731 extractComments: false,
732 }),
733 ],
734 },
735};
736```
737
738### [`uglify-js`](https://github.com/mishoo/UglifyJS)
739
740[`UglifyJS`](https://github.com/mishoo/UglifyJS) is a JavaScript parser, minifier, compressor and beautifier toolkit.
741
742**webpack.config.js**
743
744```js
745module.exports = {
746 optimization: {
747 minimize: true,
748 minimizer: [
749 new TerserPlugin({
750 minify: TerserPlugin.uglifyJsMinify,
751 // `terserOptions` options will be passed to `uglify-js`
752 // Link to options - https://github.com/mishoo/UglifyJS#minify-options
753 terserOptions: {},
754 }),
755 ],
756 },
757};
758```
759
760### [`swc`](https://github.com/swc-project/swc)
761
762[`swc`](https://github.com/swc-project/swc) is a super-fast compiler written in rust; producing widely-supported javascript from modern standards and typescript.
763
764> **Warning**
765>
766> the `extractComments` option is not supported and all comments will be removed by default, it will be fixed in future
767
768**webpack.config.js**
769
770```js
771module.exports = {
772 optimization: {
773 minimize: true,
774 minimizer: [
775 new TerserPlugin({
776 minify: TerserPlugin.swcMinify,
777 // `terserOptions` options will be passed to `swc` (`@swc/core`)
778 // Link to options - https://swc.rs/docs/config-js-minify
779 terserOptions: {},
780 }),
781 ],
782 },
783};
784```
785
786### [`esbuild`](https://github.com/evanw/esbuild)
787
788[`esbuild`](https://github.com/evanw/esbuild) is an extremely fast JavaScript bundler and minifier.
789
790> **Warning**
791>
792> the `extractComments` option is not supported and all legal comments (i.e. copyright, licenses and etc) will be preserved
793
794**webpack.config.js**
795
796```js
797module.exports = {
798 optimization: {
799 minimize: true,
800 minimizer: [
801 new TerserPlugin({
802 minify: TerserPlugin.esbuildMinify,
803 // `terserOptions` options will be passed to `esbuild`
804 // Link to options - https://esbuild.github.io/api/#minify
805 // Note: the `minify` options is true by default (and override other `minify*` options), so if you want to disable the `minifyIdentifiers` option (or other `minify*` options) please use:
806 // terserOptions: {
807 // minify: false,
808 // minifyWhitespace: true,
809 // minifyIdentifiers: false,
810 // minifySyntax: true,
811 // },
812 terserOptions: {},
813 }),
814 ],
815 },
816};
817```
818
819### Custom Minify Function
820
821Override default minify function - use `uglify-js` for minification.
822
823**webpack.config.js**
824
825```js
826module.exports = {
827 optimization: {
828 minimize: true,
829 minimizer: [
830 new TerserPlugin({
831 minify: (file, sourceMap) => {
832 // https://github.com/mishoo/UglifyJS2#minify-options
833 const uglifyJsOptions = {
834 /* your `uglify-js` package options */
835 };
836
837 if (sourceMap) {
838 uglifyJsOptions.sourceMap = {
839 content: sourceMap,
840 };
841 }
842
843 return require("uglify-js").minify(file, uglifyJsOptions);
844 },
845 }),
846 ],
847 },
848};
849```
850
851### Typescript
852
853With default terser minify function:
854
855```ts
856module.exports = {
857 optimization: {
858 minimize: true,
859 minimizer: [
860 new TerserPlugin({
861 terserOptions: {
862 compress: true,
863 },
864 }),
865 ],
866 },
867};
868```
869
870With built-in minify functions:
871
872```ts
873import type { JsMinifyOptions as SwcOptions } from "@swc/core";
874import type { MinifyOptions as UglifyJSOptions } from "uglify-js";
875import type { TransformOptions as EsbuildOptions } from "esbuild";
876import type { MinifyOptions as TerserOptions } from "terser";
877
878module.exports = {
879 optimization: {
880 minimize: true,
881 minimizer: [
882 new TerserPlugin<SwcOptions>({
883 minify: TerserPlugin.swcMinify,
884 terserOptions: {
885 // `swc` options
886 },
887 }),
888 new TerserPlugin<UglifyJSOptions>({
889 minify: TerserPlugin.uglifyJsMinify,
890 terserOptions: {
891 // `uglif-js` options
892 },
893 }),
894 new TerserPlugin<EsbuildOptions>({
895 minify: TerserPlugin.esbuildMinify,
896 terserOptions: {
897 // `esbuild` options
898 },
899 }),
900
901 // Alternative usage:
902 new TerserPlugin<TerserOptions>({
903 minify: TerserPlugin.terserMinify,
904 terserOptions: {
905 // `terser` options
906 },
907 }),
908 ],
909 },
910};
911```
912
913## Contributing
914
915Please take a moment to read our contributing guidelines if you haven't yet done so.
916
917[CONTRIBUTING](./.github/CONTRIBUTING.md)
918
919## License
920
921[MIT](./LICENSE)
922
923[npm]: https://img.shields.io/npm/v/terser-webpack-plugin.svg
924[npm-url]: https://npmjs.com/package/terser-webpack-plugin
925[node]: https://img.shields.io/node/v/terser-webpack-plugin.svg
926[node-url]: https://nodejs.org
927[tests]: https://github.com/webpack-contrib/terser-webpack-plugin/workflows/terser-webpack-plugin/badge.svg
928[tests-url]: https://github.com/webpack-contrib/terser-webpack-plugin/actions
929[cover]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin/branch/master/graph/badge.svg
930[cover-url]: https://codecov.io/gh/webpack-contrib/terser-webpack-plugin
931[discussion]: https://img.shields.io/github/discussions/webpack/webpack
932[discussion-url]: https://github.com/webpack/webpack/discussions
933[size]: https://packagephobia.now.sh/badge?p=terser-webpack-plugin
934[size-url]: https://packagephobia.now.sh/result?p=terser-webpack-plugin