最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 项目优化实践:Webpack 动态导入 react-toastify

    正文概述 掘金(JackySummer)   2021-03-27   716

    本文同步发布在我的 Github 个人博客

    前言

    如果你的项目正在使用 react-toastify,可以看看本文。我是最近通过webpack-bundle-analyzer发现的一个问题,其实我们只有某个页面会可能用到弹框,比如你点了收藏之后会有弹框出来。但是通过打包结果和运行得出,每个页面无论有没有使用,一开始都引入了 react-toastify

    react-toastify 的使用

    如果你打开它 Github,它是这么使用的:

    import React from 'react';
    
    import { ToastContainer, toast } from 'react-toastify';
    import 'react-toastify/dist/ReactToastify.css';
    
    function App(){
        const notify = () => toast("Wow so easy!");
    
        return (
          <div>
            <button onClick={notify}>Notify!</button>
            <ToastContainer />
          </div>
        );
    }
    

    而如果整个项目多个地方用或者需要控制好数据流的话,一个做法往往是把它拉到 Redux 管理,在我们项目就变成

    app.tsx

    // 里面封装了逻辑和返回了 <ToastContainer />
    import Toast from "src/containers/Toast";
    
    const { noToast } = this.props
    
    return (
        /* ... */
        {!noToast && <Toast />}
    )
    

    项目使用的是 Next.js

    我们的每个pages/页面都引入了这个app.tsx公共文件,上面代码中,Toast是经过 Redux 等封装好的 Toast组件,由上面代码粗略看出,如果在每个页面的app.tsx组件传入noToast属性,那么<Toast />就不会被加载,调用 toast方法也不会有弹框出现。

    这段代码已经是几年前的了,推测是这个意图,默认导入,假设确认你页面真的不需要弹框,就传noToast属性,然而我搜索了整个项目,用到noToast的地方只有一个,所以这个属性并不被后来接手的人所知,也就不会手动传入noToast,导致每个页面都引入了react-toasify

    现有的问题

    1. 我们只有在页面详情页点击收藏,才会有弹框(使用react-toastify),其他页面都没有。但每个页面都加载了该 chunk 包
    2. 项目中使用 toast 方法是通过Redux触发,通过useUpdateEffect监听了全局

    src/containers/Toast.tsx

    useUpdateEffect(() => {
      // toastProp从redux获取而来的
      if (toastProp.message || toastProp.errors) notify(toastProp); // notify里面判断和调用toast
    }, [notify, toastProp]);
    

    优化

    1. 当然是不要每个页面都引入,而是用到的页面再引入
    2. 最好用到的页面,没点击时也不加载,比如只有点击收藏,才让react-toasify加载。

    这就让人想到动态导入了,做法即是不再需要在app.tsx判断引入react-toastify,如新封装了一个组件

    import { ToastContent, ToastOptions } from "react-toastify";
    		
    // 动态导入	 ./Toastify是封装好的 Toastify			
    export const toastify = () => import("./Toastify");
    				
    export const toast = (message: ToastContent, toastOptions?: ToastOptions) => {	
      return toastify().then((toast) => {	
        toast.showToast(message, toastOptions);	
      });		
    };
    

    上面做到的效果即是:

    // before
    import { toast } from "./toastify";
    toast("Hello World");
    
    // after
    import("./toastify").then(module => {
      module.toast("Hello World");
    });
    

    现在看看这个文件 ./Toastify.tsx(省略很多代码...)

    
    const setupToastContainer = () => {
      if (!hasToastContainer) {
        hasToastContainer = true;
        // 需要去给根html添加一个div,id为 root-toastify                
        ReactDOM.render(
          <>
            <ToastGlobalStyle />
            <ToastWrapper/>
          </>,
          document.getElementById("root-toastify")
        );
      }	
    };
    	
    
    export const showToast = (message, toastOptions = {}) => {
      setupToastContainer();
      toast(message, toastOptions);
    };
    

    直接摆脱了 Redux 依赖,而且只有你点击的一瞬间才会加载react-toastify的chunk包,初始加载并不会,故最后优化结果是每个页面都打包压缩体积都减少15-20K+。

    这次就有点偷懒写文了,因为这只是项目优化的其中一个小点,以前也没有记录优化点,这次做了就马上回顾一下,上面代码可能看的有点懵,没有放出完整代码和做个Demo。

    不过没关系,因为我在 Github 找到了完整的 PR 例子供大家参考 enhancement: move react-toastify to its own bundle,同样是动态导入react-toastify,做法一样。


    • ps:
      • 个人技术博文 Github 仓库

    起源地下载网 » 项目优化实践:Webpack 动态导入 react-toastify

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元