Erlo

学习 Webpack5 之路(优化篇)

2021-09-05 19:00:05 发布   603 浏览  
页面报错/反馈
收藏 点赞

一、前言

从 0 到 1 学习的朋友可参考前置学习文章:

  • 学习 Webpack5 之路(基础篇) [1]
  • 学习 Webpack5 之路(实践篇) [2]

前置文章 学习 Webpack5 之路(基础篇)[1] 对 webpack 的概念做了简单介绍,学习 Webpack5 之路(实践篇)[2] 则从配置着手,用 webpack 搭建了一个 SASS + TS + React 的项目。

本篇将从优化开发体验、加快编译速度、减小打包体积、加快加载速度 4 个角度出发,介绍如何对 webpack 项目进行优化。

本文依赖的 webpack 版本信息如下:

  • webpack-cli@4.7.2
  • webpack@5.46.0

二、优化效率工具

在优化开始之前,需要做一些准备工作。

安装以下 webpack 插件,帮助我们分析优化效率:

  • progress-bar-webpack-plugin [3]:查看编译进度;
  • speed-measure-webpack-plugin [4]:查看编译速度;
  • webpack-bundle-analyzer [5]:打包体积分析。

1. 编译进度条

一般来说,中型项目的首次编译时间为 5-20s,没个进度条等得多着急,通过 progress-bar-webpack-plugin[3] 插件查看编译进度,方便我们掌握编译情况。

安装:

npm i -D progress-bar-webpack-plugin

webpack.common.js 配置方式如下:

const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
module.exports = {
  plugins: [
    // 进度条
    new ProgressBarPlugin({
        format`  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
      })
  ],
}

贴心的为进度百分比添加了加粗和绿色高亮态样式。

包含内容、进度条、进度百分比、消耗时间,进度条效果如下:

2. 编译速度分析

优化 webpack 构建速度,首先需要知道是哪些插件、哪些 loader 耗时长,方便我们针对性的优化。

通过 speed-measure-webpack-plugin[4] 插件进行构建速度分析,可以看到各个 loader、plugin 的构建时长,后续可针对耗时 loader、plugin 进行优化。

安装:

npm i -D speed-measure-webpack-plugin

webpack.dev.js 配置方式如下:


const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
  // ...webpack config...
})

包含各工具的构建耗时,效果如下:

注意:这些灰色文字的样式,是因为我在 vscode 终端运行的,导致有颜色的字体都显示为灰色,换个终端就好了,如 iTerm2[6]

3. 打包体积分析

同样,优化打包体积,也需要先分析各个 bundle 文件的占比大小,来进行针对优化。

使用 webpack-bundle-analyzer[5] 查看打包后生成的 bundle 体积分析,将 bundle 内容展示为一个便捷的、交互式、可缩放的树状图形式。帮助我们分析输出结果来检查模块在何处结束。

安装:

npm i -D webpack-bundle-analyzer

webpack.prod.js 配置方式如下:


const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    // 打包体积分析
    new BundleAnalyzerPlugin()
  ],
}

包含各个 bundle 的体积分析,效果如下:

三、优化开发体验

1. 自动更新

自动更新[7] 指的是,在开发过程中,修改代码后,无需手动再次编译,可以自动编译代码更新编译后代码的功能。

webpack 提供了以下几种可选方式,实现自动更新功能:

  1. webpack's  Watch Mode [8]
  2. webpack-dev-server [9]
  3. webpack-dev-middleware [10]

webpack 官方推荐的方式是 webpack-dev-server,在 学习 Webpack5 之路(实践篇)[2] - DevServer 章节[11] 已经介绍了 webpack-dev-server[9] 帮助我们在代码发生变化后自动编译代码实现自动更新的用法,在这里不重复赘述。

这是针对开发环境的优化,修改 webpack.dev.js 配置。

2. 热更新

热更新[12] 指的是,在开发过程中,修改代码后,仅更新修改部分的内容,无需刷新整个页面。

2.1 修改 webpack-dev-server 配置

使用 webpack 内置的 HMR 插件,更新 webpack-dev-server 配置。

webpack.dev.js 配置方式如下:

module.export = {
    devServer: {
        contentBase'./dist',
        hottrue// 热更新
      },
}

2.2 引入 react-refresh-webpack-plugin

使用 react-refresh-webpack-plugin[13] 热更新 react 组件。

安装:

npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh

webpack.dev.js 配置方式如下:


const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new ReactRefreshWebpackPlugin(),
    ]
}

遇到的问题:

配置了 SpeedMeasurePlugin 后,热更新就无效了,会提示 runtime is undefined

解决方案:

仅在分析构建速度时打开 SpeedMeasurePlugin 插件,这里我们先关闭 SpeedMeasurePlugin 的使用,来查看热更新效果。

最终效果:

更新 react 组件代码时,无需刷新页面,仅更新组件部分。

四、加快构建速度

1. 更新版本

1.1 webpack 版本

使用最新的 webpack 版本,通过 webpack 自身的迭代优化,来加快构建速度。

这一点是非常有效的,如 webpack5 较于 webpack4,新增了持久化缓存、改进缓存算法等优化,webpack5 新特性可查看 参考资料[14]

1.2 包管理工具版本

将 Node.js 、package 管理工具(例如 npm 或者 yarn)更新到最新版本,也有助于提高性能。较新的版本能够建立更高效的模块树以及提高解析速度。

本文依赖的版本信息如下:

  • webpack@5.46.0
  • node@14.15.0
  • npm@6.14.8

2. 缓存

2.1 cache

通过配置 webpack 持久化缓存[15] cache: filesystem,来缓存生成的 webpack 模块和 chunk,改善构建速度。

简单来说,通过 cache: filesystem 可以将构建过程的 webpack 模板进行缓存,大幅提升二次构建速度、打包速度,当构建突然中断,二次进行构建时,可以直接从缓存中拉取,可提速 90% 左右。

webpack.common.js 配置方式如下:

module.exports = {
    cache: {
      type'filesystem'// 使用文件缓存
    },
}

引入缓存后,首次构建时间将增加 15%,二次构建时间将减少 90%,效果如下:

2.2 dll ❌

webpack 官网构建性能[16] 中看到关于 dll 的介绍:

dll 可以为更改不频繁的代码生成单独的编译结果。可以提高应用程序的编译速度。

我兴冲冲的开始寻找 dll 的相关配置说明,太复杂了,接着找到了一个辅助配置 dll 的插件 autodll-webpack-plugin[17],结果上面直接写了 webpack5 开箱即用的持久缓存是比 dll 更优的解决方案。

所以,不用再配置 dll了,上面介绍的 cache 明显更香。

2.3 cache-loader ❌

没错,cache-loader[18] 也不需要引入了,上面的 cache 已经帮助我们缓存了。

3. 减少 loader、plugins

每个的 loader、plugin 都有其启动时间。尽量少地使用工具,将非必须的 loader、plugins 删除。

3.1 指定 include

为 loader 指定 include,减少 loader 应用范围,仅应用于最少数量的必要模块,。

webpack 构建性能文档[19]

rule.exclude 可以排除模块范围,也可用于减少 loader 应用范围.

webpack.common.js 配置方式如下:

module.exports = {
    rules: [
        {
            test/.(js|ts|jsx|tsx)$/,
            include: paths.appSrc,
            use: [
              {
                loader'esbuild-loader',
                options: {
                  loader'tsx',
                  target'es2015',
                },
              }
            ]
         }
    ]
}

定义 loader 的 include 后,构建时间将减少 12%,效果如下:

3.2 管理资源

使用 webpack 资源模块[20] (asset module) 代替旧的 assets loader(如 file-loader/url-loader/raw-loader 等),减少 loader 配置数量。

配置方式如下:

module.exports = {
    rules: [
       {
        test/.(png|svg|jpg|jpeg|gif)$/i,
        include: [
          paths.appSrc,
        ],
        type'asset/resource',
      },
    ]
}

引入资源模块后,构建时间将减少 7%,效果如下:

4. 优化 resolve 配置

resolve[21] 用来配置 webpack 如何解析模块,可通过优化 resolve 配置来覆盖默认配置项,减少解析范围。

4.1 alias

alias 可以创建 import 或 require 的别名,用来简化模块引入。

webpack.common.js 配置方式如下:

module.exports = {
    resolve: {
        alias: {
          '@': paths.appSrc, // @ 代表 src 路径
        },
    }
}

4.2 extensions

extensions 表示需要解析的文件类型列表。

根据项目中的文件类型,定义 extensions,以覆盖 webpack 默认的 extensions,加快解析速度。

由于 webpack 的解析顺序是从左到右,因此要将使用频率高的文件类型放在左侧,如下我将 tsx 放在最左侧。

webpack.common.js 配置方式如下:

登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认