lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

重新认识 Webpack 的 optimization.minimizer #127

Open lmk123 opened 9 months ago

lmk123 commented 9 months ago

我有一个项目的 Webpack 配置,里面有且仅有一个 CopyWebpackPlugin,我用它复制了一些 js / css 文件到 dist 文件夹,同时,我使用了 CopyWebpackPlugin 的 transform 选项来压缩这些文件。

我的配置大概是这样:

// webpack.config.js

const CopyPlugin = require('copy-webpack-plugin')
const Terser = require('terser')
const CleanCSS = require('clean-css')

module.exports = {
  mode: 'production',
  plugin: [
    new CopyPlugin({
      patterns: [
        {
          from: '**/*.js'
          async transform (content) {
            return await Terser.minify(content.toString())).code
          }
        },
        {
          from: '**/*.css'
          async transform (content) {
            return await new CleanCSS().minify(content.toString()).styles
          }
        },
      ]
    })
  ]
}

这些文件来自第三方,我会定期更新它。今天,我更新了这些文件,然后报错了:

Terser: Unexpected token name «import», expected punc «,» [path/to/source.js:10,46]

我发现 path/to/source.js:10,46 现在多了一条 await import('...') 语句,这个问题好解决,只需要给 Terser 加个选项 module: true 就可以了。完成之后,我又试了下,结果仍然报错了:

ERROR in path/to/source.js
path/to/source.js from Terser plugin
Unexpected token name «import», expected punc «,» [path/to/source.js:10,46]

我一开始以为是我的 Terser 配置有问题,以为还需要加些别的什么配置。我翻遍了 Terser 的文档,都没有看出个所以然,而最后我突然注意到两次报错的内容不一样,后者的错误信息 from Terser plugin

这就奇怪了——我并没有给我的 Webpack 添加 TerserWebpackPlugin

难道 Webpack 在 production 模式下,会自动使用 TerserPlugin 吗?

这一点在文档里 https://webpack.js.org/configuration/mode/ 得到了确认,Webpack 确实会在 production 模式下启用 TerserPlugin(以及其它一些插件),但是我又有疑问了:由 CopyPlugin 复制的文件并不是 entry 引用的,难道 TerserPlugin 对 entry 外的文件也会起作用吗?

看了下 TerserPlugin 的文档,我发现它虽然是 Webpack 插件,但是它却不是声明在 plugins 里,而是在 optimization.minimizer,所以我又有了一个猜想:难道是 optimization.minimizer 里会对 entry 以外的文件生效?

为了验证我的猜想,我对 webpack 配置做了改造:

const CopyPlugin = require('copy-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
  mode: 'production',
  plugin: [
    new CopyPlugin({
      patterns: [
        {
          from: '**/*.js' // 去掉了 transform
        {
          from: '**/*.css'
      ]
    })
  ],
  optimization: {
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          module: true,
        },
      }),
      new CssMinimizerPlugin(),
    ],
  }
}

果然—— js 和 css 被压缩了 :joy:

总结