Skip to content

Latest commit

 

History

History
241 lines (147 loc) · 13 KB

Webpack 性能优化.md

File metadata and controls

241 lines (147 loc) · 13 KB

Webpack 性能优化

Create by jsliang on 2020-10-20 15:00:19
Recently revised in 2020-12-07 07:50:10

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 针对 Webpack 本身构建优化
3.1 优化 resolve.modules 配置
3.2 优化 resolve.extensions 配置
3.3 优化 resolve.include/exclude 配置
四 通过 Loader 和 Plugin 优化
4.1 缓存
4.2 多进程
4.3 多进程压缩
4.4 静态资源分离
4.5 代码分离
4.6 打包资源压缩
五 其他优化点
5.1 Tree Shaking
5.2 Scope Hoisting
5.3 按需加载
六 优化体验
七 参考文献

二 前言

返回目录

Webpack 的优化瓶颈,主要是 2 个方面:

  • Webpack 的构建过程太花时间
  • Webpack 打包的结果体积太大

本文从这 2 个角度出发,收集一些相关优化资料。

三 针对 Webpack 本身构建优化

返回目录

3.1 优化 resolve.modules 配置

返回目录

resolve.modules 用于配置 Webpack 去哪些目录下寻找第三方模块,默认是 ['node_modules']

但是,它会先去当前目录的 ./node_modules 查找,没有的话再去 ../node_modules,最后到根目录 —— 即 npm 查找包的规则。

所以可以直接指定项目根目录,这样代码就不需要一层一层查找。

resolve: {
  modules: [path.resolve(__dirname, 'node_modules')],
}

3.2 优化 resolve.extensions 配置

返回目录

在导入没带文件后缀的路径时,Webpack 会自动带上后缀去尝试询问文件是否存在,而 resolve.extensions 用于配置尝试后缀列表;默认为 extensions:['js', 'json']

当遇到 require('./data')Webpack 会先尝试寻找 data.js,没有再去找 data.json;如果列表越长,或者正确的后缀越往后,尝试的次数就会越多。

所以在配置时为提升构建优化需遵守:

  1. 频率出现高的文件后缀优先放在前面。
  2. 列表尽可能的少,例如只有 3 个:jsjsxjson
  3. 书写导入语句时,尽量写上后缀名。

3.3 优化 resolve.include/exclude 配置

返回目录

babel-loader 为例,可以通过 includeexclude 帮助我们避免 node_modules 这类庞大文件夹。

即通过 include 告诉 Webpack 哪些我们是需要检测的,通过 exclude 告诉 Webpack 哪些我们是不需要检测的(例如已经收拾过的静态资源)

四 通过 Loader 和 Plugin 优化

返回目录

4.1 缓存

返回目录

babel-loader 开启 cache 后,将 loader 的编译结果写进硬盘缓存,再次构建如果文件没有发生变化则会直接拉取缓存。

  • uglifyjs-webpack-plugin

通过这个插件也可以解决缓存问题。

注:具体的要根据当前的 Webpack 版本,LoaderPlugin 表示 Webpack 每次更新都会淘汰一批没有跟进维护的 LoaderPlugin。就跟大佬还在持续学习,你几年没学习之后,遇到金融危机被淘汰的风险就高了。

4.2 多进程

返回目录

由于有大量文件需要解析和处理,构建是文件读写和计算密集型的操作,特别是当文件数量变多后,Webpack 构建慢的问题会显得严重。

文件读写和计算操作是无法避免的,那能不能让 Webpack 同一时刻处理多个任务,发挥多核 CPU 电脑的威力,以提升构建速度呢?

Happypack 可以将任务分解成多个子进程去并发执行,大大提升打包效率。

除此之外 thread-loaderHappypack 一样,但是配置比较简单。

Happypack 已经不维护了。Github - Happypack

4.3 多进程压缩

返回目录

因为自带的 UglifyjsWebpackPlugin 压缩插件是单线程运行的,而 TerserWebpackPlugin 可以并发运行压缩功能(多进程)。

所以通过 TerserWebpackPlugin 代替自带的 UglifyjsWebpackPlugin 插件。

4.4 静态资源分离

返回目录

通过 DllPlugin 或者 Externals 进行静态依赖包的分离。

由于 CommonsChunkPlugin 每次构建会重新构建一次 vendor,所以出于效率考虑,使用 DllPlugin 将第三方库单独打包到一个文件中,只有依赖自身发生版本变化时才会重新打包。

4.5 代码分离

返回目录

Webpack 中,到底什么是代码分离?代码分离允许你把代码拆分到多个文件中。如果使用得当,你的应用性能会提高很多。因为浏览器能缓存你的代码。

每当你做出一次修改,包含修改的文件需要被所有访问你网站的人重新下载。但你并不会经常修改应用的依赖库。

如果你能把那些依赖库拆分到完全分离的文件中,即使业务逻辑发生了更改,访问者也不需要再次下载依赖库,直接使用之前的缓存就可以了。

由于有了 SplitChunksPlugin,你可以把应用中的特定部分移至不同文件。如果一个模块在不止一个 chunk 中被使用,那么利用代码分离,该模块就可以在它们之间很好地被共享。

4.6 打包资源压缩

返回目录

  • JS 压缩:UglifyjsWebpackPlugin
  • HTML 压缩:HtmlWebpackPlugin
  • CSS 压缩:MiniCssExtractPlugin
  • 图片压缩:image-webpack-loader
  • Gzip 压缩:不包括图片

五 其他优化点

返回目录

5.1 Tree Shaking

返回目录

通过 ES6 的 import/export 来检查未引用代码,以及 sideEffects 来标记无副作用代码,最后用 UglifyJSPlugin 来做 Tree Shaking,从而删除冗余代码。

5.2 Scope Hoisting

返回目录

Scope Hoisting 是 Webpack3 的新功能,直译为 「作用域提升」,它可以让 Webpack 打包出来的 「代码文件更小」「运行速度更快」

熟悉 JavaScript 都应该知道 「函数提升」「变量提升」 ,JavaScript 会把函数和变量声明提升到当前作用域的顶部。

「作用域提升」 也类似于此,Webpack 会把引入的 js 文件 “提升到” 它的引入者顶部。

Scope Hoisting 的实现原理其实很简单:分析出模块之间的依赖关系,尽可能将打散的模块合并到一个函数中,前提是不能造成代码冗余。因此「只有那些被引用了一次的模块才能被合并」。

由于 Scope Hoisting 需要分析出模块之间的依赖关系,因此源码「必须采用 ES6 模块化语句」,不然它将无法生效。原因和 Tree Shaking 中介绍的类似。

5.3 按需加载

返回目录

  • 什么是 代码分割(code splitting)?

代码分割是指:将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程。

在 Webpack 构建时,会避免加载已声明要异步加载的代码,异步代码会被单独分离出一个文件,当代码实际调用时被加载至页面。

代码分割技术的核心是 异步加载资源

可喜的是,浏览器允许我们这么做,W3C stage 3 规范: whatwg/loader 对其进行了定义:你可以通过 import() 关键字让浏览器在程序执行时异步加载相关资源。

在 Vue 中,可以直接使用 import() 关键字做到这一点,而在 React 中,你需要使用 react-loadable 去完成同样的事。

六 优化体验

返回目录

  • progress-bar-webpack-plugin:在终端底部,将会有一个构建的进度条,可以让你清晰的看见构建的执行进度。
  • webpack-build-notifier:在构建完成时,能够像微信、Lark 这样的 APP 弹出消息的方式,提示构建已经完成。
  • webpack-dashboard:对 Webpack 原始的构建输出不满意的话,也可以使用这样一款 Plugin 来优化你的输出界面。
  • speed-measure-webpack-plugin:该插件可以测量各个插件和 loader 所花费的时间。
  • webpack-bundle-analyzer:可视化分析。通过矩阵树图的方式将包内各个模块的大小和依赖关系呈现出来。
  • webpack-chart
  • webpack-analyse

七 参考文献

返回目录

2019 年文章

2018 年文章

2017 年文章


jsliang 的文档库由 梁峻荣 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议 进行许可。
基于 https://github.com/LiangJunrong/document-library 上的作品创作。
本许可协议授权之外的使用权限可以从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处获得。