webpack5升级&优化指南,webpack5真香!

2,499 阅读6分钟

背景

由于公司的后台项目比较大,构建时间非常久,觉得很浪费时间,就起了优化的心思。看了一些webpack优化的文章,大部分都提到了webpack5的持久性缓存大大提升了构建速度,而且官方也说了尽可能长时间地保持在v5版本。所以!干起来吧!
官方给出的这个版本重点在于以下几点。

  • 尝试用持久性缓存来提高构建性能。
  • 尝试用更好的算法和默认值来改进长期缓存。
  • 尝试用更好的 Tree Shaking 和代码生成来改善包大小。
  • 尝试改善与网络平台的兼容性。
  • 尝试在不引入任何破坏性变化的情况下,清理那些在实现 v4 功能时处于奇怪状态的内部结构。
  • 试图通过现在引入突破性的变化来为未来的功能做准备,使其能够尽可能长时间地保持在 v5 版本上

本次升级基于webpack4.3.0 升级至webpack5.54.0 再提一句,本文完全基于我司的配置进行优化,也仅代表个人愚见(webpack小白),文内也留了一些问题,望各位大佬解惑,不甚感激~

建议在开干之前也先阅读一下迁移指南

升级webpack

首先先将webpack工具及一些基础包升级到最新版本

npm install --save-dev webpack-cli@latest webpack@latest webpack-merge@latest webpack-dev-server@latest

Webpack 5 对 Node.js 的版本要求至少是 10.13.0 (LTS),因此,如果你还在使用旧版本的 Node.js,请升级它们。

loader

file-loader & url-loader

webpack5内置了资源模块的处理,可以替代以往的file-loader,url-loader,raw-loader,所以可以卸载这几个loader,直接内置处理

{
  test: /\.png$/,
  loader: 'url-loader',
    options: {
      limit: 10 * 1024,
      name: 'images/[name].[ext]'
    }
}

上方配置可以看出,如果图片大于10kb将会启用file-loader将文件单独导出,资源模块配置如下

{
  test: /\.png$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 10 * 1024 // 10kb
    }
  },
  generator: {
    filename: 'images/[name][ext]'
  }
}
  • type: asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。
  • parser
    • 如果 Rule.type 的值为 asset,那么 Rules.parser 选项可能是一个对象或一个函数,其作用可能是将文件内容编码为 Base64,还可能是将其当做单独文件 emit 到输出目录。
    • 如果 Rule.type 的值为 asset 或 asset/inline,那么 Rule.generator 选项可能是一个描述模块源编码方式的对象,还可能是一个通过自定义算法对模块源代码进行编码的函数
  • dataUrlCondition:如果一个模块源码大小小于 maxSize,那么模块会被作为一个 Base64 编码的字符串注入到包中, 否则模块文件会被生成到输出的目标目录中
  • generator.filename:控制文件输出

vue-loader

之前vue-loader用的是15.9.1版本的,然后一直编译不成功,然后也找了很多资料,都挺尴尬。然后猜测是不是不兼容webpack5,然后升级了一下vue-loader版本,确实编译成功
15.9.1升级至15.9.8,升级完后发现页面内有一处完成不兼容的报错,目前是手动修改的。

<script>
export default {
    data() {
        return {
            // 通过webpack.Defineplugin全局注入的常量,直接报页面编译错误
            DOMIN_URL// 修改为
            "DOMIN_URL": DOMIN_URL
        }
    }
}
</script>

sass-loader

之前项目中sass-loader依赖Node Sass,非常耗费时间,官方更推荐使用Dart Sass,至于为什么选择Dart Sass可以看看官方的解释,大致就是更快,更容易安装等等

npm install --save-dev sass

重新编译后有如下警告,原因是因为Dart Sass 2.0.0以后使用math.div替代/,但是这里的警告涉及到element-ui包,只能手动降级到Dart Sass 1.32.13版本,重新编译警告消失

DEPRECATION WARNING: Using / for division is deprecated and will be removed in Dart Sass 2.0.0.

Recommendation: math.div($--tooltip-arrow-size, 2)

babel-loader

从一篇文章里看到esbuild可以大大提高构建速度,然后就起了试一试的心态,效果简直惊人,构建速度提升20s+

注意: 官方文档中提到针对大部分语法esbuild只支持转换到es6,因此只适合在开发环境使用,生产环境不建议使用
// dev
module: {
  rules: [
    {
      test: /\.js$/,
      use: [
        {
          loader: 'esbuild-loader',
          options: {
            loader: 'js',
            target: 'es2015',
          }
        }
      ],
      exclude: /node_modules/,
      include: resolve('src')
    }
  ]
}

cache-loader & dllplugin

webpack5之前优化大部分依赖cache-loader对一些耗时比较大的地方增加缓存,或者依赖dllplugin减少打包内容,使构建加速。
webpack5提供了开箱即用的持久化缓存,引入缓存后,基于我的项目首次构建时间将增加 10%,二次构建时间大致缩小了百分之85%

module.exports = {
  cache: {
    type: 'filesystem', // 启用持久化缓存
    cacheDirectory: resolve('.temp_cache'), // 缓存文件存放的位置
    buildDependencies: { // 缓存失效的配置
      config: [__filename]
    }
  }
}

plugins

html-webpack-plugin

有报错,就直接升级到最新版本就可以了

npm i --save-dev html-webpack-plugin@latest

clean-webpack-plugin

output多了一个clean参数,在生成文件之前清空 output 目录,所以加上这个参数后就可以把插件去掉啦

optimize-css-assets-webpack-plugin

官方提示我们对于webpack5或者更高的版本请改用css-minimizer-webpack-plugin,使用新的plugin后打包发现少了400kb左右
给个官网的例子

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /.s?css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
    ],
  },
  optimization: {
    minimizer: [
      // 在 webpack@5 中,你可以使用 `...` 语法来扩展现有的 minimizer(即 `terser-webpack-plugin`)
      '...',
      new CssMinimizerPlugin(),
    ],
  },
  plugins: [new MiniCssExtractPlugin()],
};

devServer

原先的配置如下

devServer: {
  ..., // 一些没有改变的配置,类似hot,open等
  quiet: true,
  overlay: true,
  disableHostCheck: true,
  clientLogLevel: 'warning' // 控制台提示信息级别是 warning 以上
}
  • quiet:移除,官方迁移文章建议可以在infrastructrueLogging中修改,这部分其实没看明白,目前直接把infrastructrueLogging.level设置为info,显示错误告警与信息,但是又用了friendly-errors-webpack-plugin,导致错误告警显示2次,直接用none的话又没有基础设施日志,求解答!
  • overlay:移至client中
  • clientLogLevel:移至client中,更改为logging属性
  • disableHostCheck:更改为allowedHosts,可以自行增加白名单

修改后配置如下

devServer: {
	client: {
    overlay: { // 只显示错误信息
      errors: true,
      warnings: false,
    },
    logging: 'warn' // 控制台只显示warn以上信息
  },
  allowedHosts: 'all'
},
infrastructrueLogging: {
  level: 'info'
}

其它

devtool一键打开vscode源码

首先安装launch-editor-middleware

npm install --save-dev launch-editor-middleware

在webpack.dev.js里配置
然后把编辑器加入到环境变量里
以vscode为例,Command + Shift + P打开Command Palette,输入shell command,选择第一个就可以大功告成了:
image.png
在ch点击如下按钮就可以打开vscode对应的组件了
image.png

shelljs

我目前用的node版本是14.17.1的,跑起来后发现有一堆警告,虽然不影响运行,但是终究很难受,所以还是解决一下

Warning: Accessing non-existent property 'cd' of module exports inside circular dependency
(node:21085) Warning: Accessing non-existent property 'chmod' of module exports inside circular dependency
(node:21085) Warning: Accessing non-existent property 'cp' of module exports inside circular dependency

在package.json run的命令行后面加上下方命令查看node报错的具体信息

"test": "cross-env NODE_OPTIONS=--trace-warnings ..."

image.png
可以猜测这是shelljs的问题,我们更新一下shelljs后报错消失

前后对比

所有对比都在文件没有任何变动的情况下,图一为优化后,图二为优化前
首次打包缩短20s
二次打包缩短60s
首次构建缩短100s
二次构建缩短80s

首次打包

image.png
image.png

二次打包

image.png
image.png

首次构建

image.png
image.png

二次构建

image.png
image.png

参考文档

官方博客:webpack5发布
官方v4升级v5:迁移指南
sass-loader:链接
esbuild优化:参考文章
devServer:官方迁移文章
devtool:参考文章