webpack-bundle-analyzer 优化实战

6,659 阅读4分钟

问题

oh,shit!这个 js 竟然要加载 4.39 秒,why?

接入步骤

安装依赖

// npm 方式
npm install webpack-bundle-analyzer --save-dev

// yarn 方式
yarn -D webpack-bundle-analyzer

配置webpack.config.js文件

使用环境变量控制是否执行该 plugin,相关配置参数可查看 官方文档

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports={
  plugins: [
    // ... 其他 plugin 配置
    process.env.ANALYZER && new BundleAnalyzerPlugin()  // 使用默认配置
  ]
}

配置package.json 文件

不同项目命令不同,根据自身的项目进行调整,这边是对 build 完后的包进行分析。

{
 "scripts": {
    "analyzer": "cross-env ENV_TYPE=staging ANALYZER=true node scripts/build.js"
  }
}

执行命令

npm run analyzer
// or 
yarn analyzer

执行效果

浏览器会自动打开 127.0.0.1:8888,可查看相关模块的依赖的组成

实战案例

案例一:发现同一库存在多个版本

发现竟然引入了三个 @ant-design/icons 的模块,先使用 npm 命令查看一下包的依赖状态

npm list @ant-design/icons

结果:还真的依赖了 @ant-design/icons 的 v4.2.2 和 v4.4.0 两个版本

解决方式:将 @ant-design/icons 升级到 4.4.0 版本即可。

重新安装依赖再次分析后发现已经没有引入多个 @ant-design/icons 模块了。

效果分析:该文件压缩后大小 从 549.08KB 降到了 484.56KB,减少了 11.75% (64.52 KB)

案例二:第三方包太大

看图中的 moment 还是占用了挺大一块的,结合功能来看,只是使用了里面处理时间的少量功能,但是包的体积却十分的大,包含了多语言相关的内容,但是我们并没有使用到,可以更换成 date-fn 、dayjs 等包体积更小并且可以按需加载的包~

将 momentjs 更换成 date-fn 后效果,整体减少了 65.44KB:

案例三:没有按需加载

紧跟着上一个案例,可以看到 lodash 占了大头,明明在项目中只使用了 lodash 的一个函数,ahooks 的两个函数,怎么这个打包出来的包有一半都是 lodash 呀~

import { uniqBy } from 'lodash';
import { useMount, useThrottleFn } from 'ahooks';

原因:没有使用按需引入,默认会把整个包都打包进项目里的

怎么解决?很简单,这种库的通常都会提供按需加载的方式,只需要修改一下引入方式即可~

import uniqBy from 'lodash/uniqBy';
import useMount from 'ahooks/lib/useMount';
import useThrottleFn from 'ahooks/lib/useThrottleFn';

修改后包大小:

效果分析:该文件压缩后大小 从 77.89KB降到了 56.35KB,减少了 21.54KB

在引入第三库的时候都可以去了解下是否有提供按需引入的方式,建议优先选择有提供按需引入的库~

案例四:在某些场景下才会使用到的包

发现这个 Logrocket 的包还挺大的,回顾了一下业务流程,这个 Logrocket 是干什么的呢?主要是为了当用户报问题的时候加载这个插件即可录下用户操作的全过程,有的时候是用户的操作路径比较隐藏,无法复现bug,或者是用户操作不对以为是bug,感兴趣的朋友可以去查看它的官网 logrocket.com/

这个插件并不是每次打开页面的时候都会开启,这样可以把流程修改成在 url 上添加一个开启该插件的参数,并且在代码中改成动态加载。

if(url.params.openLogrocket === 'true'){
    import('logrocket').then(() => {

    })
}

发现问题

  • 打包出的文件中都包含了什么?

  • (案例三)每个文件的尺寸在总体中的占比,哪些文件尺寸大,思考一下,为什么那么大,是否有替换方案,是否使用了它包含的所有代码;

  • (案例一)是否有重复的依赖项,是否存在一个库在多个文件中重复? 或者捆绑包中是否具有同一库的多个版本?

  • 是否有相似的依赖库, 尝试使用一种依赖库实现相似的功能。

  • 例如处理时间的库:momentJs,dayJs。

  • 每个文件的压缩后的大小。

解决问题

当发现有这个问题了之后就是去思考如何去解决/避免这个问题。

  • 是否引入了第三方库的多个版本,例如 antd,react 等库

  • 在引入第三方库的时候要先进行思考(考验的就是选型的能力)

  • 是否要引入第三方库,能否自己手写实现一个?

  • 多个第三方库进行对比,哪个更适合当下的场景?

  • 第三方库包体积有多大?是否支持按需引入?

  • 总结&寻求更多的包体积优化方案,在这里讲的只是发现问题的方式之一。

  • 建立前端性能指标,例如包体积应该要小于多少才是合理的?(当然还有其他指标)。

  • 寻求自动化解决方案,例如在构建完之后获取检查包体积是否符合指标,不符合则进行邮件 OR 钉钉通知对应的负责人进行优化。