webpack优化实记-解决树摇失效+自定义分包

背景

使用lighthouse对首页进行"体检"时,发现首屏渲染慢。 chrome给出的其中一个建议是,可以减少未被使用的js文件。

除了main和vendor包较大之外,还有另一个需要注意的是,echarts在首页并没有引入,为什么在首屏加载时会用到

可以考虑两个方向:

  1. webpack对项目进行打包时,分包策略不是我们想要的,也许是依赖分析不在我们的意料之中;
  2. 树摇失败,没有摇掉没用到的包;

下一步我对打包后的资源进行分析,发现了两个问题:

  1. 为什么会有两个lodash
  2. 影响首屏加载的main把首屏不需要的DyformGen也引进来了

另外从业务的角度分析

  1. shared库的组件其实是可以缓存起来的,应该打成一个包

  2. @babel/standalone其实只有一个页面在用,其实并不用打进vendor里,像这种只有一个模块在用的第三方库,可以单独打包,避免vendor一下子搞了太多不用的代码

  3. 首页并没有使用echarts,为什么打开首页时会下载这个包?

小结

需要解决的问题包括:

  1. echarts在首页并没有引入,为什么在首屏加载时会用到
  2. 为什么会有两个lodash
  3. 影响首屏加载的main.js里,把首屏不需要的DyformGen也引进来了
  4. (业务角度)shared库的组件其实是可以缓存起来的,应该打成一个包
  5. (业务角度)@babel/standalone其实只有动态表单在用,其实并不用打进vendor里,像这种只有一个模块在用的第三方库,可以单独打包,避免vendor一下子搞了太多不用的代码

问题1:Echarts首屏加载分析

疑问:为什么首页加载的时候被引入?

检查路由分割是否有问题,导致动态导入/代码切割出现bug

查看代码的组织结构,发现页面都是通过从后端拿到的路由数据,进行动态导入的; 且通过检查打包后各个page是否被拆分为单独包,确认路由分割没有失效。 动态导入代码如下:

javascript 复制代码
    rendComponent: Loadable(() => import('../lib/pages/login/index.tsx')),

webpack代码分割见:代码分离 | webpack 中文文档 (docschina.org)

通过打包可视化分析的时候发现,main.js主要是由dashboard.tsx(首页组件)和shared(通用组件)组成的。

结论:路由的动态分割应该没有问题,问题应该在于整个shared包几乎都被引入到main里了,而shared包里是引入了echarts的,这可能就是为什么首屏加载有echarts的原因。

而shared和项目代码是通过nx构造的monorepo组织起来的,难道是nx的问题?

nx的树摇问题和sideEffect标记

在nx的GitHub搜了一下,发现nx确实有树摇问题:github.com/nrwl/nx/iss...

解决方案:手动给包打上side-effect:false的标签

sideEffects配置:告知 webpack 去辨识 package.json 中的 副作用 标记或规则,以跳过那些当导出不被使用且被标记不包含副作用的模块。见:优化(Optimization) | webpack 中文文档 (docschina.org)

然后发现确实解决了问题!main.js一下子从(stat)920.82kb降到86.03kb,且lighthouse的性能分数从73提升到84

同时,为了避免开发环境下热更新速度慢,仅在生产环境开启sideEffect检测

问题2:Loadash的按需加载问题

自上一步之后,lodash的总体积剩下

其他地方还捆绑了一些

解决方案:手动改成 import get from 'lodash/get'

大包(vendor)内容分析

大包分析:

  • @babel/standalone,由于体积占比大的不是业务代码,是第三方库,而且只有个别页面在用,所以可以单独提取出来做缓存,但是不需要放到vendor里

需要拆包,见webpack拆包插件SplitChunksPlugin | webpack 中文文档 (docschina.org),其中我比较关注的配置是:

  • splitChunks.minChunks 在拆分之前,模块必须在块之间共享的最小次数
  • splitChunks.minSizeReduction 主块最小缩小尺寸
  • splitChunks.maxSize

我的配置如下:

这样就把@babel/standalone拆分了出来

总结

问题分析

  • 树摇似乎失效了,首页加载的时候会将没有引用到的echart的js文件也下载下来
  • 入口文件main.js过大,几乎包含了shared仓库里的所有内容
  • 第三方库打包成的vendor.js过大,由于main.js一定会引用vendor.js,这样会导致首屏加载时,下载了很多没用到的vendor,但是由于可以击中缓存,所以这个问题比较小

解决方案

  • 修复nx失效问题,需要在mono仓库里配置各个仓库的sideEffect,声明该package没有副作用,从而使webpack进行树摇
  • 对于只被一个模块引用的第三方库,webpack会将第三方库和业务代码打包在一起,如果这种第三方库体积较大的话,则将其拆分出来,使这种第三方库可以充分利用缓存

优化效果

测试环境:本地将sms前端打包成镜像,在本地启动镜像,后端访问地址为10.53.0.207

  • main入口从(stat)920.82kb降到(stat)86.03kb
  • 通过配置,实现自动将echart、@babel/standalone之类的大chunk提取出来,无需单独配置

使用lighthouse对首页进行评估,优化前:

优化后:

相关推荐
zifer7 小时前
在 Webpack 中使用 TypeScript语言 编写配置文件的完整指南
webpack
Tandy12356_2 天前
js逆向——webpack实战案例(一)
前端·javascript·安全·webpack
TonyH20022 天前
webpack 4 的 30 个步骤构建 react 开发环境
前端·css·react.js·webpack·postcss·打包
你会发光哎u2 天前
Webpack模式-Resolve-本地服务器
服务器·前端·webpack
Small-K2 天前
前端框架中@路径别名原理和配置
前端·webpack·typescript·前端框架·vite
ziyu_jia6 天前
webpack配置全面讲解【完整篇】
前端·webpack·前端框架·node.js
谢尔登6 天前
【Webpack】优化前端开发环境的热更新效率
前端·webpack·node.js
你会发光哎u6 天前
了解Webpack并处理样式文件
前端·webpack·node.js
不穿铠甲的穿山甲6 天前
webpack使用
前端·webpack·npm
几何心凉6 天前
Webpack 打包后文件过大,如何优化?
前端·webpack·node.js