Search code examples
reactjssplitwebpackreact-routerbundle

React Router v3 per flow bundle splitting


Is there a way with what is available on React Roter v3 API to make per-flow bundle split? From documentation, and examples from the internet, there's a way to split, but it's per-component, using PlainRoute with getChildRoutes, getComponent etc. Using it with System.imports I get splited sub-bundle for every Route separately.

What I tried was something like this, and I got 0.js, 1.js ... 9.js chunks in the Network tab of dev-tools.

getChildRoutes(_, fetchComponents) {
    Promise.all([
        System.import('./pages/page1.jsx'),
        System.import('./pages/page2.jsx'),
        ...
        System.import('./pages/page10.jsx')
    ])
    .then(([page1, page2... page10]) => {
        fetchComponents(null, [
            {path: '...', indexRoute: {component: page1}},
            {path: '...', component: page2},
            ...
            {path: '...', component: page10}
        ])
    })
}

So is it possible with a structure like this two have only 3 chunks (sub-bundles)?

<Router ...>
 {/*flow 1*/}
  <Rote component...>
    <Route path... component... />
    <Route component>
      <IndexRoute .../>
      <Route path ... component... />
      <Route path ... component... />
      <Route path ... component... />
      ...
    </Route>
  </Route>

 {/*flow 2*/}
  <Route>
    ...
  </Route>

 {/*flow 3*/}
  <Route />
</Router>

If it's not possible to do it with React Router, I'd appreciate any hints how to do this properly with Webpack.


Solution

  • Yes it is!

    Here is how I did it in my project:

    Inside your router.js file if you are using plain routes :

    const componentRoutes = {
      path: '/',
      childRoutes: [
        {
          path: 'routeA',
          getChildRoutes (partialNextState, callback) {
            System.import('./aRoutes')
              .then(module => callback(null, module.default))
          }
        },
        {
          path: 'routeB',
          getChildRoutes (partialNextState, callback) {
            System.import('./bRoutes')
              .then(module => callback(null, module.default))
          }
        },
        {
          path: 'routeC',
          getChildRoutes (partialNextState, callback) {
            System.import('./cRoutes')
              .then(module => callback(null, module.default))
          }
        },
      ]
    }
    const Routes = () => {
      return (
        <Router history={browserHistory} routes={componentRoutes} />
      )
    }
    
    export default Routes
    

    Inside aRoutes.js:

    import aDashboard from './containers/aDashboard'
    import SomePage from './containers/SomePage'
    const aRoutes = [
      {
        path: 'aDashboard',
        component: aDashboard
      },
      {
        path: 'somePage',
        component: SomePage
      }
    ]
    
    export default aRoutes
    

    Inside bRoutes.js:

    import bDashboard from './containers/bDashboard'
    import SomePageB from './containers/SomePageB'
    
    const bRoutes = [
      {
        path: 'bDashboard',
        component: bDashboard
      },
      {
        path: 'somePageB',
        component: SomePageB
      }
    ]
    
    export default bRoutes
    

    Inside cRoutes.js:

    import cDashboard from './containers/cDashboard'
    import SomePageC from './containers/SomePagec'
    
    const cRoutes = [
      {
        path: 'cDashboard',
        component: cDashboard
      },
      {
        path: 'somePageC',
        component: SomePageC
      }
    ]
    
    export default cRoutes
    

    So for your case I would have 3 "route" files that you use 3 System.import statements to pull in their childRoutes. You can put as many components as you want into each of the route files but you will only have 3 bundles because you only have 3 System.import calls. This way you can split your bundle into only three files and not per component. Hope this helps