Search code examples
reactjswebpackreact-routercode-splitting

Code splitting with Webpack


My current Route description looks as follows for one of my routes:

<Route path='auth' component = {AuthenticateContainer} onEnter = {checkAuth}/>

In order to split code for route paths I beleive the code may looks like this:

                <Route path="auth"  getComponent={(nextState, callback) => {
                    require.ensure([], function(require) {
                        callback(null, require('./AuthenticateContainer.js').default);
                    })
                }}/>

But What I'm missing is the OnEnter checkAuth Function, how do I include it ?


Solution

  • If you have checkAuth in ./AuthenticationContainer.js then move it to routes.js or create a new js file and require it in routes.js. Basically, the function to be run on onEnter hook has to be present before requiring component using getComponent.

    My routes.js looks like this-

    import React from 'react';
    import { Route } from 'react-router';
    
    export default (store) => {
      function requireAuth(nextState, replace) {
        if(!store.getState().auth.isAuthenticated) {
          replace({
            pathname: '/',
            state: { nextPathname: nextState.location.pathname }
          })
        }
      }
    
      return { childRoutes: [{
          path: '/',
          getComponents(location, callback) {
            require.ensure(['./containers/App/App.jsx'], function (require) {
                callback(null, require('./containers/App/App.jsx').default)
            })
          },
          childRoutes: [{
            path: 'about',
            onEnter: requireAuth,
            getComponents(location, callback) {
              require.ensure(['./containers/About/About.jsx'], function (require) {
                  callback(null, require('./containers/About/About.jsx').default)
              })
            }
          }]
        }]
      }
    };
    

    I am not sure if you can call checkAuth inside require.ensure and stop the component from being loaded if it isn't authenticated. By design, this is a bad approach since you are loading the component and then checking if it's authenticated. This negates the benefits of code splitting.

    Edit - Adding webpack.config.js

    var webpack = require('webpack');
    var path = require('path');
    
    var BUILD_DIR = path.resolve(__dirname, 'build');
    var APP_DIR = path.resolve(__dirname, 'src');
    
    var config = {
      entry: APP_DIR + '/index.jsx',
    
      output: {
        path: BUILD_DIR,
        filename: 'bundle.js',
        chunkFilename: '[id].chunk.js',
      },
    
      devtool: 'inline-source-map',
    
      module : {
        loaders : [
          {
            test : /\.jsx?/,
            include : APP_DIR,
            loader : 'babel'
          },
          {
            test: /\.css?$/,
            loaders: [ 'style', 'raw' ],
            include: __dirname
          }
        ]
      },
    
      plugins: [
        new webpack.optimize.CommonsChunkPlugin('shared.js')
      ]
    };
    
    module.exports = config;
    

    Webpack build output -

    webpack -d --watch
    
    Hash: 08b101d1e95f7633adb4
    Version: webpack 1.13.2
    Time: 2680ms
             Asset     Size  Chunks             Chunk Names
         bundle.js  1.05 MB    0, 3  [emitted]  main
        1.chunk.js  4.15 kB    1, 3  [emitted]  
        2.chunk.js  3.19 kB    2, 3  [emitted]  
         shared.js  3.66 kB       3  [emitted]  shared.js
     bundle.js.map  1.16 MB    0, 3  [emitted]  main
    1.chunk.js.map  2.32 kB    1, 3  [emitted]  
    2.chunk.js.map  1.18 kB    2, 3  [emitted]  
     shared.js.map  3.67 kB       3  [emitted]  shared.js
        + 269 hidden modules