关于react.js:项目优化实践Webpack-动态导入-reacttoastify

42次阅读

共计 2436 个字符,预计需要花费 7 分钟才能阅读完成。

本文同步公布在我的 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

应用 toast 办法必须页面要挂载了 <ToastContainer />,才能够弹出弹框

现有的问题

  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 仓库

正文完
 0