如果你的项目正在使用 react-toastify
,可以看看本文。我是最近通过webpack-bundle-analyzer
发现的一个问题,其实我们只有某个页面会可能用到弹框,比如你点了收藏之后会有弹框出来。但是通过打包结果和运行得出,每个页面无论有没有使用,一开始都引入了 react-toastify
。
react-toastify 的使用
如果你打开它 Github,它是这么使用的:
1 | import React from 'react' |
而如果整个项目多个地方用或者需要控制好数据流的话,一个做法往往是把它拉到 Redux 管理,在我们项目就变成
app.tsx
1 | // 里面封装了逻辑和返回了 <ToastContainer /> |
项目使用的是 Next.js
我们的每个pages/
页面都引入了这个app.tsx
公共文件,上面代码中,Toast 是经过 Redux 等封装好的 Toast 组件,由上面代码粗略看出,如果在每个页面的app.tsx
组件传入noToast
属性,那么<Toast />
就不会被加载,调用 toast
方法也不会有弹框出现。
这段代码已经是几年前的了,推测是这个意图,默认导入,假设确认你页面真的不需要弹框,就传noToast
属性,然而我搜索了整个项目,用到noToast
的地方只有一个,所以这个属性并不被后来接手的人所知,也就不会手动传入noToast
,导致每个页面都引入了react-toasify
使用 toast 方法必须页面要挂载了
<ToastContainer />
,才可以弹出弹框
现有的问题
- 我们只有在页面详情页点击收藏,才会有弹框(使用
react-toastify
),其他页面都没有。但每个页面都加载了该 chunk 包 - 项目中使用 toast 方法是通过 Redux 触发,通过
useUpdateEffect
监听了全局
src/containers/Toast.tsx
1 | useUpdateEffect(() => { |
优化
- 当然是不要每个页面都引入,而是用到的页面再引入
- 最好用到的页面,没点击时也不加载,比如只有点击收藏,才让
react-toasify
加载。
这就让人想到动态导入了,做法即是不再需要在app.tsx
判断引入react-toastify
,如新封装了一个组件
1 | import { ToastContent, ToastOptions } from 'react-toastify' |
上面做到的效果即是:
1 | // before |
现在看看这个文件 ./Toastify.tsx
(省略很多代码…)
1 | const setupToastContainer = () => { |
直接摆脱了 Redux 依赖,而且只有你点击的一瞬间才会加载react-toastify
的 chunk 包,初始加载并不会,故最后优化结果是每个页面都打包压缩体积都减少 15-20K+。
这次就有点偷懒写文了,因为这只是项目优化的其中一个小点,以前也没有记录优化点,这次做了就马上回顾一下,上面代码可能看的有点懵,没有放出完整代码和做个 Demo。
不过没关系,因为我在 Github 找到了完整的 PR 例子供大家参考 enhancement: move react-toastify to its own bundle,同样是动态导入react-toastify
,做法一样。