Ian Obermiller

Part time hacker, full time dad.

Shave 45kb off your production webpack + React build

If you’re building a React app for production using webpack, don’t forget this simple plugin for your production build:

new webpack.DefinePlugin({
  'process.env': {NODE_ENV: '"production"'}
})

It will replace all instances of process.env.NODE_ENV with the string "production". When used in conjunction with the uglify plugin, all the code in React that is inside a dev only conditional like if ("production" !== process.env.NODE_ENV) { ... } will be stripped.

On my simple app, this shaved 45kb off the production build before gzip. After gzip saved 13.5kb, still not bad. Win!

Conditionally Load Intl Polyfill with Webpack

So, you want to use the new JavaScript Internationalization API, Intl? Perhaps you even want to use it with the awesome React Intl library. Browser support is okay, but if you want to support <IE11 and any version of Safari you’ll have to use a polyfill. Unfortunately, the polyfill is pretty large if you use the full build with all languages, clocking in at ~150k minified and gzipped. Wouldn’t it be great if we could set up our JavaScript app to download the Intl library only if the browser needs the polyfill? Fortunately, this is really easy to do using webpack.

1. Install intl

npm install --save intl

2. Modify app’s entry point

Before, ¬†our app’s entry point using React was simple and synchronous:


var React = require('react');
var App = require('./App');

React.render(<App />, document.body);

Now, we need to put all our initialization code into a function, and wait to invoke the function until the polyfill is loaded:

function run() {
  var React = require('react');
  var App = require('./App');

  React.render(<App />, document.body);
}

// Check if polyfill required
if (!window.Intl) {
  // Webpack parses the inside of require.ensure at build time to know that intl
  // should be bundled separately. You could get the same effect by passing
  // ['intl'] as the first argument.
  require.ensure([], () => {
    // Ensure only makes sure the module has been downloaded and parsed.
    // Now we actually need to run it to install the polyfill.
    require('intl');

    // Carry on
    run();
  });
} else {
  // Polyfill wasn't needed, carry on
  run();
}

That’s all there is to it. Webpack takes care of splitting the bundle and downloading the polyfill on require.ensure! This method should work with all kinds of polyfills, and keeps your app lean for modern browsers yet working in the rest. For more information, see the webpack documentation for code splitting.