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 |
|
---|
16 | This plugin uses [terser](https://github.com/terser/terser) to minify/minimize your JavaScript.
|
---|
17 |
|
---|
18 | ## Getting Started
|
---|
19 |
|
---|
20 | Webpack 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 |
|
---|
22 | To begin, you'll need to install `terser-webpack-plugin`:
|
---|
23 |
|
---|
24 | ```console
|
---|
25 | npm install terser-webpack-plugin --save-dev
|
---|
26 | ```
|
---|
27 |
|
---|
28 | or
|
---|
29 |
|
---|
30 | ```console
|
---|
31 | yarn add -D terser-webpack-plugin
|
---|
32 | ```
|
---|
33 |
|
---|
34 | or
|
---|
35 |
|
---|
36 | ```console
|
---|
37 | pnpm add -D terser-webpack-plugin
|
---|
38 | ```
|
---|
39 |
|
---|
40 | Then add the plugin to your `webpack` config. For example:
|
---|
41 |
|
---|
42 | **webpack.config.js**
|
---|
43 |
|
---|
44 | ```js
|
---|
45 | const TerserPlugin = require("terser-webpack-plugin");
|
---|
46 |
|
---|
47 | module.exports = {
|
---|
48 | optimization: {
|
---|
49 | minimize: true,
|
---|
50 | minimizer: [new TerserPlugin()],
|
---|
51 | },
|
---|
52 | };
|
---|
53 | ```
|
---|
54 |
|
---|
55 | And 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 |
|
---|
61 | Why?
|
---|
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 |
|
---|
66 | Using 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 |
|
---|
80 | Type:
|
---|
81 |
|
---|
82 | ```ts
|
---|
83 | type test = string | RegExp | Array<string | RegExp>;
|
---|
84 | ```
|
---|
85 |
|
---|
86 | Default: `/\.m?js(\?.*)?$/i`
|
---|
87 |
|
---|
88 | Test to match files against.
|
---|
89 |
|
---|
90 | **webpack.config.js**
|
---|
91 |
|
---|
92 | ```js
|
---|
93 | module.exports = {
|
---|
94 | optimization: {
|
---|
95 | minimize: true,
|
---|
96 | minimizer: [
|
---|
97 | new TerserPlugin({
|
---|
98 | test: /\.js(\?.*)?$/i,
|
---|
99 | }),
|
---|
100 | ],
|
---|
101 | },
|
---|
102 | };
|
---|
103 | ```
|
---|
104 |
|
---|
105 | ### `include`
|
---|
106 |
|
---|
107 | Type:
|
---|
108 |
|
---|
109 | ```ts
|
---|
110 | type include = string | RegExp | Array<string | RegExp>;
|
---|
111 | ```
|
---|
112 |
|
---|
113 | Default: `undefined`
|
---|
114 |
|
---|
115 | Files to include.
|
---|
116 |
|
---|
117 | **webpack.config.js**
|
---|
118 |
|
---|
119 | ```js
|
---|
120 | module.exports = {
|
---|
121 | optimization: {
|
---|
122 | minimize: true,
|
---|
123 | minimizer: [
|
---|
124 | new TerserPlugin({
|
---|
125 | include: /\/includes/,
|
---|
126 | }),
|
---|
127 | ],
|
---|
128 | },
|
---|
129 | };
|
---|
130 | ```
|
---|
131 |
|
---|
132 | ### `exclude`
|
---|
133 |
|
---|
134 | Type:
|
---|
135 |
|
---|
136 | ```ts
|
---|
137 | type exclude = string | RegExp | Array<string | RegExp>;
|
---|
138 | ```
|
---|
139 |
|
---|
140 | Default: `undefined`
|
---|
141 |
|
---|
142 | Files to exclude.
|
---|
143 |
|
---|
144 | **webpack.config.js**
|
---|
145 |
|
---|
146 | ```js
|
---|
147 | module.exports = {
|
---|
148 | optimization: {
|
---|
149 | minimize: true,
|
---|
150 | minimizer: [
|
---|
151 | new TerserPlugin({
|
---|
152 | exclude: /\/excludes/,
|
---|
153 | }),
|
---|
154 | ],
|
---|
155 | },
|
---|
156 | };
|
---|
157 | ```
|
---|
158 |
|
---|
159 | ### `parallel`
|
---|
160 |
|
---|
161 | Type:
|
---|
162 |
|
---|
163 | ```ts
|
---|
164 | type parallel = boolean | number;
|
---|
165 | ```
|
---|
166 |
|
---|
167 | Default: `true`
|
---|
168 |
|
---|
169 | Use multi-process parallel running to improve the build speed.
|
---|
170 | Default 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 |
|
---|
182 | Enable/disable multi-process parallel running.
|
---|
183 |
|
---|
184 | **webpack.config.js**
|
---|
185 |
|
---|
186 | ```js
|
---|
187 | module.exports = {
|
---|
188 | optimization: {
|
---|
189 | minimize: true,
|
---|
190 | minimizer: [
|
---|
191 | new TerserPlugin({
|
---|
192 | parallel: true,
|
---|
193 | }),
|
---|
194 | ],
|
---|
195 | },
|
---|
196 | };
|
---|
197 | ```
|
---|
198 |
|
---|
199 | #### `number`
|
---|
200 |
|
---|
201 | Enable multi-process parallel running and set number of concurrent runs.
|
---|
202 |
|
---|
203 | **webpack.config.js**
|
---|
204 |
|
---|
205 | ```js
|
---|
206 | module.exports = {
|
---|
207 | optimization: {
|
---|
208 | minimize: true,
|
---|
209 | minimizer: [
|
---|
210 | new TerserPlugin({
|
---|
211 | parallel: 4,
|
---|
212 | }),
|
---|
213 | ],
|
---|
214 | },
|
---|
215 | };
|
---|
216 | ```
|
---|
217 |
|
---|
218 | ### `minify`
|
---|
219 |
|
---|
220 | Type:
|
---|
221 |
|
---|
222 | ```ts
|
---|
223 | type 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 |
|
---|
281 | Default: `TerserPlugin.terserMinify`
|
---|
282 |
|
---|
283 | Allows you to override default minify function.
|
---|
284 | By default plugin uses [terser](https://github.com/terser/terser) package.
|
---|
285 | Useful 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
|
---|
295 | const 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`
|
---|
312 | minify.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 |
|
---|
325 | module.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 |
|
---|
342 | Type:
|
---|
343 |
|
---|
344 | ```ts
|
---|
345 | type 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 |
|
---|
365 | Default: [default](https://github.com/terser/terser#minify-options)
|
---|
366 |
|
---|
367 | Terser [options](https://github.com/terser/terser#minify-options).
|
---|
368 |
|
---|
369 | **webpack.config.js**
|
---|
370 |
|
---|
371 | ```js
|
---|
372 | module.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 |
|
---|
401 | Type:
|
---|
402 |
|
---|
403 | ```ts
|
---|
404 | type 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 |
|
---|
444 | Default: `true`
|
---|
445 |
|
---|
446 | Whether comments shall be extracted to a separate file, (see [details](https://github.com/webpack/webpack/commit/71933e979e51c533b432658d5e37917f9e71595a)).
|
---|
447 | By default extract only comments using `/^\**!|@preserve|@license|@cc_on/i` regexp condition and remove remaining comments.
|
---|
448 | If the original file is named `foo.js`, then the comments will be stored to `foo.js.LICENSE.txt`.
|
---|
449 | The `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 |
|
---|
453 | Enable/disable extracting comments.
|
---|
454 |
|
---|
455 | **webpack.config.js**
|
---|
456 |
|
---|
457 | ```js
|
---|
458 | module.exports = {
|
---|
459 | optimization: {
|
---|
460 | minimize: true,
|
---|
461 | minimizer: [
|
---|
462 | new TerserPlugin({
|
---|
463 | extractComments: true,
|
---|
464 | }),
|
---|
465 | ],
|
---|
466 | },
|
---|
467 | };
|
---|
468 | ```
|
---|
469 |
|
---|
470 | #### `string`
|
---|
471 |
|
---|
472 | Extract `all` or `some` (use `/^\**!|@preserve|@license|@cc_on/i` RegExp) comments.
|
---|
473 |
|
---|
474 | **webpack.config.js**
|
---|
475 |
|
---|
476 | ```js
|
---|
477 | module.exports = {
|
---|
478 | optimization: {
|
---|
479 | minimize: true,
|
---|
480 | minimizer: [
|
---|
481 | new TerserPlugin({
|
---|
482 | extractComments: "all",
|
---|
483 | }),
|
---|
484 | ],
|
---|
485 | },
|
---|
486 | };
|
---|
487 | ```
|
---|
488 |
|
---|
489 | #### `RegExp`
|
---|
490 |
|
---|
491 | All comments that match the given expression will be extracted to the separate file.
|
---|
492 |
|
---|
493 | **webpack.config.js**
|
---|
494 |
|
---|
495 | ```js
|
---|
496 | module.exports = {
|
---|
497 | optimization: {
|
---|
498 | minimize: true,
|
---|
499 | minimizer: [
|
---|
500 | new TerserPlugin({
|
---|
501 | extractComments: /@extract/i,
|
---|
502 | }),
|
---|
503 | ],
|
---|
504 | },
|
---|
505 | };
|
---|
506 | ```
|
---|
507 |
|
---|
508 | #### `function`
|
---|
509 |
|
---|
510 | All comments that match the given expression will be extracted to the separate file.
|
---|
511 |
|
---|
512 | **webpack.config.js**
|
---|
513 |
|
---|
514 | ```js
|
---|
515 | module.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 |
|
---|
535 | Allow to customize condition for extract comments, specify extracted file name and banner.
|
---|
536 |
|
---|
537 | **webpack.config.js**
|
---|
538 |
|
---|
539 | ```js
|
---|
540 | module.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 |
|
---|
563 | Type:
|
---|
564 |
|
---|
565 | ```ts
|
---|
566 | type 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 |
|
---|
584 | Condition what comments you need extract.
|
---|
585 |
|
---|
586 | **webpack.config.js**
|
---|
587 |
|
---|
588 | ```js
|
---|
589 | module.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 |
|
---|
612 | Type:
|
---|
613 |
|
---|
614 | ```ts
|
---|
615 | type filename = string | ((fileData: any) => string) | undefined;
|
---|
616 | ```
|
---|
617 |
|
---|
618 | Default: `[file].LICENSE.txt[query]`
|
---|
619 |
|
---|
620 | Available placeholders: `[file]`, `[query]` and `[filebase]` (`[base]` for webpack 5).
|
---|
621 |
|
---|
622 | The file where the extracted comments will be stored.
|
---|
623 | Default 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
|
---|
632 | module.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 |
|
---|
652 | Type:
|
---|
653 |
|
---|
654 | ```ts
|
---|
655 | type banner = string | boolean | ((commentsFile: string) => string) | undefined;
|
---|
656 | ```
|
---|
657 |
|
---|
658 | Default: `/*! For license information please see ${commentsFile} */`
|
---|
659 |
|
---|
660 | The banner text that points to the extracted file and will be added on top of the original file.
|
---|
661 | 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.
|
---|
662 | Will be wrapped into comment.
|
---|
663 |
|
---|
664 | **webpack.config.js**
|
---|
665 |
|
---|
666 | ```js
|
---|
667 | module.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 |
|
---|
692 | Extract all legal comments (i.e. `/^\**!|@preserve|@license|@cc_on/i`) and preserve `/@license/i` comments.
|
---|
693 |
|
---|
694 | **webpack.config.js**
|
---|
695 |
|
---|
696 | ```js
|
---|
697 | module.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 |
|
---|
716 | If you avoid building with comments, use this config:
|
---|
717 |
|
---|
718 | **webpack.config.js**
|
---|
719 |
|
---|
720 | ```js
|
---|
721 | module.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
|
---|
745 | module.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
|
---|
771 | module.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
|
---|
797 | module.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 |
|
---|
821 | Override default minify function - use `uglify-js` for minification.
|
---|
822 |
|
---|
823 | **webpack.config.js**
|
---|
824 |
|
---|
825 | ```js
|
---|
826 | module.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 |
|
---|
853 | With default terser minify function:
|
---|
854 |
|
---|
855 | ```ts
|
---|
856 | module.exports = {
|
---|
857 | optimization: {
|
---|
858 | minimize: true,
|
---|
859 | minimizer: [
|
---|
860 | new TerserPlugin({
|
---|
861 | terserOptions: {
|
---|
862 | compress: true,
|
---|
863 | },
|
---|
864 | }),
|
---|
865 | ],
|
---|
866 | },
|
---|
867 | };
|
---|
868 | ```
|
---|
869 |
|
---|
870 | With built-in minify functions:
|
---|
871 |
|
---|
872 | ```ts
|
---|
873 | import type { JsMinifyOptions as SwcOptions } from "@swc/core";
|
---|
874 | import type { MinifyOptions as UglifyJSOptions } from "uglify-js";
|
---|
875 | import type { TransformOptions as EsbuildOptions } from "esbuild";
|
---|
876 | import type { MinifyOptions as TerserOptions } from "terser";
|
---|
877 |
|
---|
878 | module.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 |
|
---|
915 | Please 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
|
---|