Automatic Code Splitting for React Router w/ ES6 Imports

Grgur Grisogono
Mar 10, 2016 · 5 min read
Dynamic React Routes With Webpack 2 Chunks

Partial application loading is an essential technique for improving the time-to-initial-impression for single page applications. The goal is to prioritize loading of the code needed to render the view whilst deferring other assets. We are about to see how we can achieve that with modern web development’s latest and greatest tools:

  • React 15.0
  • React Router 2.0
  • Webpack 2.1

In addition to using the latest versions of the above stack, we’ll also do it in style:

  • Use native ES6 imports (without requires)
  • Implement code splitting
  • Harness tree shaking

I showcased the process in a simple React app that uses React Router and 1Code Splitting (Webpack Chunks)

Webpack is smart enough to figure out the chunks automatically when it scans your application code. All you need to provide it with is an entry point.

Our sample Webpack config file lists two entry points, application logic (js) and libraries (vendor):

entry: {
js: [
'index', 'pages/Home'
],
vendor: [
'react', 'react-dom'
]
},

While this step isn’t required, it makes sense to separate libraries (in this case React and ReactDOM) from app logic so that we can leverage browser caching to a greater extent. Vendors will become a separate javascript bundle that we can reuse for any initial route the visitors use to access the app.

The js entry point should load most of the shared application code. This is how we expect Webpack to learn about the code that needs to be split into separate chunks. All direct imports that belong to the js entry point will be bundled into a single file. However, Webpack will read through our source code and understand which bits we might need to load asynchronously, then create meaningful chunks (separate javascript files) for future usage.

How does it do that, you might ask? Let’s take a look at that now.

Dynamic Routes — Automatic Code Splitting

Here’s the key concept: React Router configuration will use getter functions for the routes that we want bundled separately. Check it out:

import App from 'containers/App';function errorLoading(err) {
console.error('Dynamic page loading failed', err);
}
function loadRoute(cb) {
return (module) => cb(null, module.default);
}
export default {
component: App,
childRoutes: [
{
path: '/',
getComponent(location, cb) {
System.import('pages/Home')
.then(loadRoute(cb))
.catch(errorLoading);
}
},
{
path: 'blog',
getComponent(location, cb) {
System.import('pages/Blog')
.then(loadRoute(cb))
.catch(errorLoading);
}
}
]
};

In our example, we used the getComponent function that Router automatically calls when a route is requested. System.import will know which file to load because Webpack created all the instructions needed. Webpack 2 will look for System.import statements to understand which chunks of your code should be automatically bundled into separate chunks. Magic!

Let’s review the process:

  1. Webpack scans your code during the build process. It treats System.import calls as import statements and bundles the imported file along with its dependencies. It’s important to know that dependencies will not collide with those in the main application bundle (aka the initial entry point of the Webpack configuration file).
  2. A visitor accesses the app, starting from any random route. Anything from index.html is loaded, including the vendor files and the initial entry point (your main app logic). React Router executes getComponent based on the requested route path.
  3. System.import is now a polyfill that executes a JSONP request in order to fetch the bundle required for the route to execute. This is an asynchronous process (like any XHR request).
  4. System.import is also a Promise. When the response isdelivered, we loadRoute. In other words, we execute the chunk that was loaded. Voila, the view is displayed to our user.
  5. If the route is accessed again, the router (actually the System.import polyfill) will already know about it and no additional code downloading will occur.

Go ahead and try it on the demo site. Open your network inspector tab and monitor the traffic. You will see how chunks are loaded (or not) automatically. You can also go to a route (e.g. /blog) and reload from there. Pure awesomeness!

Webpack 2 will look for System.import statements to understand which chunks of your code should be automatically bundled into separate chunks

Tree Shaking for React Router

Our index.js shows exactly how to do it:

import { Router, browserHistory } from 'react-router/es6';

Notice the trailing /es6. Now our Webpack 2 build process will only load the components it needs from the React Router package.

Caveats

There is a good reason why we didn’t include React Router and the History package in our vendors chunk. Remember, we only used React in it. That’s because we want to leverage the tree shaking technology and bundle only the code our app needs. React doesn’t ship with ES6 imports quite yet, so we can move the entire thing into vendors.js. To recap, we put infrequently changed libraries into the vendors bundle, which can be more aggressively cached on the browser side. Having a separate file also helps with download concurrency.

Conclusion

Modus Create: Front End Development

Tutorials, tips, and walk-throughs on web & mobile…

Modus Create: Front End Development

Tutorials, tips, and walk-throughs on web & mobile enterprise applications. JavaScript, HTML5, ReactJS, React Native, Angular, iOS, Android. From the developers at www.moduscreate.com

Grgur Grisogono

Written by

Principal @ModusCreate. Making the web better with @Reactjs and @Webpack. Certified @ScrumAlliance developer. @ManningBooks author. @MozDevNet contributor.

Modus Create: Front End Development

Tutorials, tips, and walk-throughs on web & mobile enterprise applications. JavaScript, HTML5, ReactJS, React Native, Angular, iOS, Android. From the developers at www.moduscreate.com

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store