TerserWebpackPlugin

npm node deps tests cover chat size

该插件使用 terser 来压缩 JavaScript。

入门

webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本。

首先,你需要安装 terser-webpack-plugin

$ npm install terser-webpack-plugin --save-dev

然后将插件添加到你的 webpack 配置文件中。例如:

webpack.config.js

const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
};

接下来,按照你习惯的方式运行 webpack

关于 source maps 说明

只对 devtool 选项的 source-mapinline-source-maphidden-source-mapnosources-source-map 有效

为何如此?

  • eval 会包裹 modules,通过 eval("string"),而 minimizer 不会处理字符串。
  • cheap 不存在列信息,minimizer 只产生单行,只会留下一个映射。

使用支持的 devtool 值可以生成 source map。

选项

选项名类型默认值描述
testString|RegExp|Array<String|RegExp>/\.m?js(\?.*)?$/i用来匹配需要压缩的文件。
includeString|RegExp|Array<String|RegExp>undefined匹配参与压缩的文件。
excludeString|RegExp|Array<String|RegExp>undefined匹配不需要压缩的文件。
parallelBoolean|Numbertrue使用多进程并发运行以提高构建速度。
minifyFunctionTerserPlugin.terserMinify允许你自定义压缩函数。
terserOptionsObjectdefaultTerser 的 minify 选项
extractCommentsBoolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Objecttrue注释是否需要提取到一个单独的文件中。

test

类型: String|RegExp|Array<String|RegExp> 默认值:/\.m?js(\?.*)?$/i

用来匹配需要压缩的文件。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        test: /\.js(\?.*)?$/i,
      }),
    ],
  },
};

include

类型: String|RegExp|Array<String|RegExp> 默认值: undefined

匹配参与压缩的文件。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        include: /\/includes/,
      }),
    ],
  },
};

exclude

类型: String|RegExp|Array<String|RegExp> 默认值: undefined

匹配不需要压缩的文件。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        exclude: /\/excludes/,
      }),
    ],
  },
};

parallel

类型: Boolean|Number 默认值: true

使用多进程并发运行以提高构建速度。 并发运行的默认数量: os.cpus().length - 1

并发运行可以显著提高构建速度,因此强烈建议添加此配置

如果你使用 Circle CI 或任何其他不提供 CPU 实际可用数量的环境,则需要显式设置 CPU 数量,以避免 Error: Call retries were exceeded(请参阅 #143#202 )。

Boolean

启用/禁用多进程并发运行功能。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },
};

Number

启用多进程并发运行并设置并发运行次数。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: 4,
      }),
    ],
  },
};

minify

类型: Function 默认值: TerserPlugin.terserMinify

允许你自定义压缩函数。 默认情况下,插件使用 terser 库。 对于使用和测试未发布的版本或 fork 的代码很帮助。

⚠️ 启用 parallel 选项时,在 minify 函数内部只能使用 require

webpack.config.js

// Can be async
const minify = (input, sourceMap, minimizerOptions, extractsComments) => {
  // The `minimizerOptions` option contains option from the `terserOptions` option
  // You can use `minimizerOptions.myCustomOption`

  // Custom logic for extract comments
  const { map, code } = require("uglify-module") // Or require('./path/to/uglify-module')
    .minify(input, {
      /* Your options for minification */
    });

  return { map, code, warnings: [], errors: [], extractedComments: [] };
};

// Used to regenerate `fullhash`/`chunkhash` between different implementation
// 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
// to avoid this you can provide version of your custom minimizer
// You don't need if you use only `contenthash`
minify.getMinimizerVersion = () => {
  let packageJson;

  try {
    // eslint-disable-next-line global-require, import/no-extraneous-dependencies
    packageJson = require("uglify-module/package.json");
  } catch (error) {
    // Ignore
  }

  return packageJson && packageJson.version;
};

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          myCustomOption: true,
        },
        minify,
      }),
    ],
  },
};

terserOptions

类型: Object 默认值: 默认

Terser 配置项

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          ecma: undefined,
          parse: {},
          compress: {},
          mangle: true, // Note `mangle.properties` is `false` by default.
          module: false,
          // Deprecated
          output: null,
          format: null,
          toplevel: false,
          nameCache: null,
          ie8: false,
          keep_classnames: undefined,
          keep_fnames: false,
          safari10: false,
        },
      }),
    ],
  },
};

extractComments

类型: Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Object 默认值: true

是否将注释剥离到单独的文件中(请参阅详细信息)。 默认情况下,仅剥离 /^\**!|@preserve|@license|@cc_on/i 正则表达式匹配的注释,其余注释会删除。 如果原始文件名为 foo.js ,则注释将存储到 foo.js.LICENSE.txtterserOptions.format.comments 选项指定是否保留注释,即可以在剥离其他注释时保留一些注释,甚至保留已剥离的注释。

Boolean

启用/禁用剥离注释功能。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: true,
      }),
    ],
  },
};

String

剥离 allsome (使用 /^\**!|@preserve|@license|@cc_on/i 正则表达式进行匹配)注释。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: "all",
      }),
    ],
  },
};

RegExp

与指定表达式匹配的所有注释将会被剥离到单独的文件中。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: /@extract/i,
      }),
    ],
  },
};

Function<(node, comment) -> Boolean>

与指定表达式匹配的所有注释将会被剥离到单独的文件中。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: (astNode, comment) => {
          if (/@extract/i.test(comment.value)) {
            return true;
          }

          return false;
        },
      }),
    ],
  },
};

Object

允许自定义剥离注释的条件,指定剥离的文件名和标题。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: {
          condition: /^\**!|@preserve|@license|@cc_on/i,
          filename: (fileData) => {
            // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
            return `${fileData.filename}.LICENSE.txt${fileData.query}`;
          },
          banner: (licenseFile) => {
            return `License information can be found in ${licenseFile}`;
          },
        },
      }),
    ],
  },
};
condition

类型: Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>

自定义需要剥离的注释。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: {
          condition: "some",
          filename: (fileData) => {
            // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
            return `${fileData.filename}.LICENSE.txt${fileData.query}`;
          },
          banner: (licenseFile) => {
            return `License information can be found in ${licenseFile}`;
          },
        },
      }),
    ],
  },
};
filename

类型: String|Function<(string) -> String> 默认值: [file].LICENSE.txt [query]

可用的占位符: [file][query][filebase] (webpack 5 使用 [base] )。

剥离出来的注释将被存储到的文件的文件名。 默认是将后缀 .LICENSE.txt 附加到原始文件名。

⚠️我们强烈建议使用 txt 扩展名。

使用 js / cjs / mjs 扩展名可能会与现有资源文件冲突,从而导致代码运行出错。

webpack.config.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}`;
          },
        },
      }),
    ],
  },
};

类型: Boolean|String|Function<(string) -> String> 默认值: /*! For license information please see ${commentsFile} */

指向剥离文件的标语文本将被添加到原始文件的顶部。 可以为 false (无标题), String 或一个函数:Function<(string) -> String> ,该函数将被使用存储剥离的注释的文件名来调用。 标语内容将被合并到注释中。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: {
          condition: true,
          filename: (fileData) => {
            // The "fileData" argument contains object with "filename", "basename", "query" and "hash"
            return `${fileData.filename}.LICENSE.txt${fileData.query}`;
          },
          banner: (commentsFile) => {
            return `My custom banner about license information ${commentsFile}`;
          },
        },
      }),
    ],
  },
};

示例

保留注释

剥离所有有效的注释(即 /^\**!|@preserve|@license|@cc_on/i )并保留 /@license/i 注释。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          format: {
            comments: /@license/i,
          },
        },
        extractComments: true,
      }),
    ],
  },
};

删除注释

如果要在构建时去除注释,请使用以下配置:

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          format: {
            comments: false,
          },
        },
        extractComments: false,
      }),
    ],
  },
};

uglify-js

UglifyJS 是一款集 JavaScript 解析器,压缩器,美化器于一身的工具集。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        minify: TerserPlugin.uglifyJsMinify,
        // `terserOptions` options will be passed to `uglify-js`
        // Link to options - https://github.com/mishoo/UglifyJS#minify-options
        terserOptions: {},
      }),
    ],
  },
};

swc

swc 是一款采用 rust 编写的超快编译器;可以将最新标准和 TypeScript 的语法生成被广泛使用的 JavaScript。

extractComments 选项暂不支持,所有注释将默认被删除,会在将来得到修复。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        minify: TerserPlugin.swcMinify,
        // `terserOptions` options will be passed to `swc` (`@swc/core`)
        // Link to options - https://swc.rs/docs/config-js-minify
        terserOptions: {},
      }),
    ],
  },
};

esbuild

esbuild 是一款非常快速的 JavaScript 打包工具和压缩工具。

⚠ 不支持 extractComments 选项,所有法律相关的注释(如版权,许可证等)将被保留。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        minify: TerserPlugin.esbuildMinify,
        // `terserOptions` options will be passed to `esbuild`
        // Link to options - https://esbuild.github.io/api/#minify
        // 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:
        // terserOptions: {
        //   minify: false,
        //   minifyWhitespace: true,
        //   minifyIdentifiers: false,
        //   minifySyntax: true,
        // },
        terserOptions: {},
      }),
    ],
  },
};

自定义压缩函数

覆盖默认的 minify 函数 - 使用 uglify-js 进行压缩。

webpack.config.js

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        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);
        },
      }),
    ],
  },
};

Typescript

使用默认 terser 压缩函数:

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: true,
        },
      }),
    ],
  },
};

使用内置压缩函数:

import type { JsMinifyOptions as SwcOptions } from "@swc/core";
import type { MinifyOptions as UglifyJSOptions } from "uglify-js";
import type { TransformOptions as EsbuildOptions } from "esbuild";
import type { MinifyOptions as TerserOptions } from "terser";

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin<SwcOptions>({
        minify: TerserPlugin.swcMinify,
        terserOptions: {
          // `swc` options
        },
      }),
      new TerserPlugin<UglifyJSOptions>({
        minify: TerserPlugin.uglifyJsMinify,
        terserOptions: {
          // `uglif-js` options
        },
      }),
      new TerserPlugin<EsbuildOptions>({
        minify: TerserPlugin.esbuildMinify,
        terserOptions: {
          // `esbuild` options
        },
      }),

      // Alternative usage:
      new TerserPlugin<TerserOptions>({
        minify: TerserPlugin.terserMinify,
        terserOptions: {
          // `terser` options
        },
      }),
    ],
  },
};

Contributing

请花一点时间阅读我们的贡献指南。

CONTRIBUTING

许可证

MIT