React 项目的打包优化

2021-05-01 Views react webpack tech

本文介绍基于 create-react-app的 react项目的编译优化经验,成功将编译打包时间由 2 min 20 s 左右降低至 1 min 20 s 左右

 

简介

 
最近因工作原因需要优化一个 react 项目,当前的开发环境下编译时间约为 2 分多钟,每次代码修改等待页面刷新都比较慢,因此效率比较低,此为前提。
 

问题分析

 
该项目是一个使用cra(create-react-app)创建的项目,而 cra 使用webpack打包,所以问题的本质即为分析优化webpack的打包编译过程,思路分为三步走:
 
1. 分析耗时与产出物体积确定瓶颈
2. 针对性的选择优化方案
3. 覆盖cra的webpack配置进行测试
 

过程

 

1. 时间与体积分析:

 
体积分析可以使用source-map-explorer这个工具,安装之后运行命令:
 

// 这里通过参数指定了目录和生成的结果文件
npm run build && source-map-explorer 'build/static/js/*.js' --html result.html

 
查看输出结果,发现node_modules打包体积占了很大部分,但具体耗时不确定。

 
时间分析可以考虑webpack插件,webpack在编译打包生命周期的一些节点上提供了钩子函数,可以考虑自己针对性的编写一个插件或者寻找现有插件,简单在社区找一下发现可以使用speed-measure-plugin,下面是耗时分析结果(多次运行结果相近):
 
运行start本地起开发服务:

 
运行build输出构建包

 
可以看到,时间花的较长的部分(红色字体)主要是babel-loader对js的转译,以及less代码的编译&预处理;另外在开发环境下,为了避免因为大小写错误导致代码内容变动监听不到的问题,cra内置了一个插件CaseSensitivePathsPlugin,这个插件会遍历检查项目目录下每一条引用路径(包括node_modules)花了较多时间。
 

2.针对性的选择优化方案:

 
cra已经内置了一些常规的webpack优化配置,在检查了cra默认的webpack配置后,针对上一步的分析结果,发现仍然有一些可操作的的余地:
 

  1. 首先是CaseSensitivePathsPlugin这个插件。
    这个插件的主要作用是扫描项目中的文件地址,是否存在大小写不一致的地方导致开发环境下失去对代码更改的监听,从而没有自动重新编译,see issue。但是缺点在于这个插件会扫描项目中全部的路径,包括node_modules,看了下这个插件的源码,并不支持自定义检查路径,这就比较因噎废食了,next项目就因为这个问题,在8.0.4以后就去除了该插件,see issue。所以不难想到在配置中默认禁用该插件,如果出现了类似问题再开启该插件进行检查。
  2. 针对babel-loader转义时间过长的问题:可以添加thread-loader开启多线程加速
  3. 针对css代码编译&预处理时间过长的问题:同 babel-loader,可以开多线程加速
     

3.修改配置&测试

 
覆盖cra的webpack需要使用到react-app-rewired/customiza-cra等插件,这个需要看一下对应的文档,修改根目录下的config-overrides.js,简单配置及测试后得到如下结果:
 
注:经测试thead-loader对less文件的一系列loader没有加速效果,根据thread-loader的官方文档说明,可能是由于webpack的机制所限:
 
运行start本地起开发服务(不给less系列loader开多线程)

 
运行start本地起开发服务(给less系列loader开多线程)

 
运行build输出构建包(不给less系列loader开多线程)

 
build情况下加速不明显,查阅cra默认的webpack配置可以发现,在production模式下,cra使用了WorkboxWebpackPlugin开了一个service worker来加速打包,起到了和thread-loader相同的效果,而并行加速的特点是边际效益递减,因此二者叠加并没有明显的效果提升(当然也可能是由于其他的原因🤣),所以,production模式下可不开启thread-loader.
 

结论

 
针对开发环境构建时开启thread-loader,同时默认不起用CaseSensitivePathsPlugin,构建时间可缩短一半左右

赏 支付宝扫码打赏 微信打赏

△