Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

Partial application loading is an essential technique for improving the time-to-first-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 loads route chunks dynamically. The entire project’s source code is available on Github and you can also see the final demo live.

Basic Setup

Our basic npm setup will include React, React Router and Webpack 2. You can set it up manually following my example or just clone this git repo.

Code 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 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

Ryan Florence authored a great article on the future of web application delivery that outlines a very similar process using require.ensure. My recent post on Tree Shaking with Webpack 2 explains how Webpack 2 is capable of reading native import statements. This example, in contrast to Ryan Florence’s approach, makes use of the newly introduced Webpack 2 features.

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);
     }
   },
   {
     path: 'about',
     getComponent(location, cb) {
       System.import('pages/About').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 will look for System.import statements to know which chunks of your code should be bundled. 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 is delivered, 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!

Tree Shaking for React Router

Tree shaking works with native ES6 modules, but not the CommonJS counterpart. Luckily, React Router ships with es6 module support, but you need to access them explicitly.

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

System.import should be straightforward for Webpack to read. Routes built from variables will not load properly, at least in Webpack 2.1 beta 4. This makes sense as it would take complex parsing to figure out all the possible combinations.

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

41% of modern React apps use React Router, according to npm package download stats for February 2016. This makes React Router an essential part of the modern React stack. Support for partial application loading is extremely important from the performance perspective. As we can see, it’s also a lot of fun to implement.

Posted in Application Development, DevOps
Share this

Grgur Grisogono

Grgur Grisogono is a software architect at Modus Create, specializing in JavaScript performance, React JS, and Sencha frameworks. He helped clients ranging from Fortune 100 to major governments and startups successfully release enterprise and consumer-facing web applications. He has also organized three tech conferences and co-authored Ext JS in Action SE. If Grgur's posts were helpful, maybe his 16 years of experience could help your project too.
Follow

Related Posts

  • New Instance Ext JS to React
    Ext JS to React: Class Instantiation and Code Style

    This is part of the Ext JS to React blog series. You can review the…

  • New Instance Ext JS to React
    Ext JS to React: Class Instantiation and Code Style

    This is part of the Ext JS to React blog series. You can review the…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
IT modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Careers
  • Let’s talk
  • EN
  • FR