React router base code-splitting (get first chunk and then get other chunks async in background)

3.4k Views Asked by At

I am using create-react-app. I want to react-router base code-splitting but I want to get the first chunk which user open in browser and then get other chunks asynchronously in the background

Routes

const HomeModule  = React.lazy(() => import('./modules/ft_home_module/src/main'));
const AuthModule  = React.lazy(() => import('./modules/ft_auth_module/src/main'));
const ProfileModule  = React.lazy(() => import('./modules/ft_profile_module/src/main'));
const MerchantModule  = React.lazy(() => import('./modules/ft_merchant_module/src/main'));

<Route path="/home" component={HomeModule} />
<Route path="/auth" component={AuthModule} />
<Route path="/profile" component={ProfileModule} />
<Route path="/merchant" component={MerchantModule} />

suppose, if user open /home in the browser then home chunk will be loaded first after loading first chunk call other chunks asynchronously in the background

Required Output

  1. Open /home in browser
  2. Get home chunk first
  3. then other three chunks asynchronously in the background

actually I am testing performance through lighthouse chrome extension. router base code-splitting gives me the good performance of the first page but when I open second page it takes time but it should not take time. I think it is possible if we get other chunks async in the background after loading first chunk

2

There are 2 best solutions below

6
On

You can achieve this by using browser resource hints(Preload and prefetch)

If you are using webpack, then magic comments will be helpful. you can try something like this:

const HomeModule  = React.lazy(() => import(/* webpackPreload: true */'./modules/ft_home_module/src/main'));
const AuthModule  = React.lazy(() => import(/* webpackPrefetch: true */'./modules/ft_auth_module/src/main'));
const ProfileModule  = React.lazy(() => import(/* webpackPrefetch: true */'./modules/ft_profile_module/src/main'));
const MerchantModule  = React.lazy(() => import(/* webpackPrefetch: true */ './modules/ft_merchant_module/src/main'));

In the above case, no matter what the url is it will preload the homemodule and prefetch the other three modules with low priority.

If you want the dynamic behaviour, you can try using the plugin: https://github.com/SebastianS90/webpack-prefetch-chunk

After adding the plugin, you can use webpack_require.pfc method to load the chunks in background.

const prefetchChunk = chunkName => {
  if (!window.requestIdleCallback) {
    return;
  } else if (chunkName) {
    let chunkArray = [].concat(chunkName);
    window.requestIdleCallback(() => {
      chunkArray.forEach(chunk => {
        __webpack_require__.pfc(chunk);
      });
    });
  } else {
    return;
  }
};
1
On

Wrap the Router with Suspense that takes a fallback(show some content while loading chunk, if it was not yet loaded)...

import React,{Suspense} from 'react';
import {Router} from '@reach/router';    
                
const HomeModule  = React.lazy(() => import('./modules/ft_home_module/src/main'));
const AuthModule  = React.lazy(() => import('./modules/ft_auth_module/src/main'))
const ProfileModule  = React.lazy(() => import('./modules/ft_profile_module/src/main'));
const MerchantModule  = React.lazy(() => import('./modules/ft_merchant_module/src/main'));
    
const Loading = () => <div>Loading chunk..</div>;
    
return (
  <Suspense fallback={<Loading/>}>
    <Router>
      <HomeModule path="/home" />
      <AuthModule path="/auth" />
      <ProfileModule path="/profile" />
      <MerchantModule path="/merchant" />
    </Router>
  </Suspense>
)