Skip to content

GeekEast/react-code-split

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lazy Load Components

React lazy and Suspense

  • Declare Suspense and fallback
import { Suspense } from 'react';
// 只需要使用一次Suspense
<Suspense fallback={Fallback}>
  <Router>
  ...
  </Router>
</Suspense>  
  • Use lazy to import components
// anywhere inside the Router
const MyComponent = React.lazy(() => import("./MyComponent"))

Lodable

import Loadable from 'react-loadable'

const MyComponent = Loadable({
  loader: () => import("./MyComponent"),
  loading: Fallback
})

Compare

  • Tie: lazy and Suspense is embeded in React, no extra cost to import, but the size of Loadable is very small as well.
  • React wins: 1 suspense 1 fallback vs 1 loadable 1 fallback
  • Loadable wins: You don't need Suspense for loadable
  • Loadable wins: Loadable gives more features like error handling, prefetch

Conclusion: Loadable is just an encapsulation of lazy and Suspense

Lazy Load Modules

Situation 1

  • 假设有个组件,都引入了moment这个包,单个组件设置moment的lazy load,会使得moment单独打成包吗?
    • 不会, 引入了moment所有组件必须全部设置lazy load,才能实现这样的需求

Lazy Load Moment.js

  • without hooks
const Calendar = (props: RouteComponentProps) => {
  // 使用useState  
  const [time, setTime] = useState("0");

  // 使用useEffect
  useEffect(() => {
    const init = async () => {
      const module = await import('moment');
      setTime(module.default().format())
    };
    init();
  }, []);

  return (
    <div>
      <br />
      Calender: {time}
    </div>
  );
};
  • with hooks
import { useState, useEffect } from 'react';
import { Moment } from 'moment'; // won't break spliting moment out, just types

const useMoment = () => {
  const [moment, setMoment] = useState<Moment>();
  useEffect(() => {
    const getModule = async () => {
        const module = await import('moment');
        setMoment(module.default)
    };
    getModule();
  }, []);
  return [moment];
};

export default useMoment;

Merge Modules

  • merge moment.js and lodash.js together, any chunkname you want
import(/* webpackChunkName: "my_lib" */ 'moment');
import(/* webpackChunkName: "my_lib" */ 'lodash');

if you want them separate, just remove the comments! Easy!

Conclusion

  • You can now do lazy load on any modules

Situation 2

  • 假设在引入moment的所有组件中全部实现了lazy load hooks,那一个页面引入moment后,进入其他页面,是不是还要重新request引入一次moment呢?
    • 初步猜想: 不会, js文件会被浏览器缓存,不会重新request

Practice

  • 首先, 通过source-map-explorer来分析bundle组成,再分析的module在组件中的使用情况
  • 其次, 分析组件和module的对应关系, 一般来说Component Split就已经足够了
Component Module Code Split Complexity Note
1 1 Component Split Low
1 n Component Split Low Merge Package
n 1 Module Split High avoid
n n Module Split High avoid
  • 最后, 如果你像让多个module封装成一个chunk, 使用/* webpackChunkName: "my_lib" */这个webpack自带的magic comments功能

Future

  • 在后续项目开发中,对于非常大的包,要提前做好lazy-load分析和处理,在写代码的时候可以借助import cost这个vscode extension
  • 如有需要,可以使用prefetch预先在后台加载特定的lib,可以让人感觉不到任何lazy-load带来的延迟

About

Compare between React.lazy() and Loadable

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages