jsliang 求职系列 - 35 -Webpack 性能优化

一 目录

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

目录
一 目录
二 前言
三 针对 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 缓存

  • cache-loader

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 年文章

  • Webpack优化——将你的构建效率提速翻倍【阅读建议:10min】

  • 性能优化篇---Webpack构建速度优化【阅读建议:10min】

  • 使用webpack4提升180%编译速度【阅读建议:10min】

  • 多进程并行压缩代码【阅读建议:5min】

  • webpack 4: Code Splitting和chunks切分优化【阅读建议:5min】

2018 年文章

  • Tree-Shaking性能优化实践 - 原理篇【阅读建议:10min】

  • 体积减少80%!释放webpack tree-shaking的真正潜力【阅读建议:10min】

  • 你的Tree-Shaking并没什么卵用【阅读建议:5min】

  • webpack 如何通过作用域分析消除无用代码【阅读建议:5min】

  • 让你的Webpack起飞—考拉会员后台Webpack优化实战【阅读建议:5min】

  • webpack dllPlugin打包体积和速度优化【阅读建议:5min】

  • webpack优化之code splitting【阅读建议:5min】

2017 年文章

  • Webpack 打包优化之速度篇【阅读建议:5min】

  • 加速Webpack-缩小文件搜索范围【阅读建议:5min】

  • Webpack 大法之 Code Splitting【阅读建议:5min】


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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值