6

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

Muhammad Numan
  • 23,222
  • 6
  • 63
  • 80

2 Answers2

3

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;
  }
};
Indragith
  • 1,240
  • 6
  • 9
  • I know then but I want to load the first chunk when the user called from browser then call other chunks in asynchronously in the background – Muhammad Numan May 21 '20 at 09:46
  • Prefetch option will inform the browser to download the chunks during idle time. If you want more control over which chunks needs to be prefetched, you should add the mentioned plugin to the webpack config. – Indragith May 21 '20 at 09:52
  • I am using create react app. will it work on create react app? – Muhammad Numan May 21 '20 at 09:57
  • Mostly yes. I haven't tried with create react app. First option will work fine. If you are going with the plugin, then you need to include this plugin in the create react app. This might help: https://dev.to/nodewarrior/override-cra-and-add-webpack-config-without-ejecting-2f3n – Indragith May 21 '20 at 10:06
  • @Indragith there is no example of this anywhere. can i use __webpack_require__.pfc at run time? __webpack_require__ will be available at runtime? – Manjunath Gk Jan 21 '22 at 06:49
  • @ManjunathGk Yes it will be available at runtime. You need to add this plugin to the webpack config. https://github.com/SebastianS90/webpack-prefetch-chunk – Indragith Jan 21 '22 at 11:04
-2

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>
)
feupeu
  • 819
  • 7
  • 25
MVS KIRAN
  • 115
  • 1
  • 6