Tag Archives: Webpack

Make your own React production version with webpack

react-webpack

If you’ve been developing with React, you must have seen that you are provided with very verbose errors/warnings that can come in handy.

Quote from the download page of React:

We provide two versions of React: an uncompressed version for development and a minified version for production. The development version includes extra warnings about common mistakes, whereas the production version includes extra performance optimizations and strips all error messages.

When you’re making your production bundle, you should not include all the extra code used in development (which makes extra checks not useful in production and at the end makes your bundle heavy).

The way to do that is to use the Webpack.DefinePlugin or envify, if you’re using browserify.

By doing the following, you’ll be injecting a variable process.env.NODE_ENV set to "production" at build time which is used inside React as we’ll see.

webpack.config.prod.js

module.exports = {
  //...
  plugins:[
    new webpack.DefinePlugin({
      'process.env':{
        'NODE_ENV': JSON.stringify('production')
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress:{
        warnings: true
      }
    })
  ]
  //...
}

That way, you’ll be including the same kind of code which is in react.min.js inside your bundle. If you take a look at the source code of React inside ./node_modules/react/lib, you’ll see a lot of places with a ternary like process.env.NODE_ENV !== 'production'. All those development related features will be dropped at the minification step.

Resources:

Continue reading

Optimize your bundle’s weight with webpack

webpack-logo

The usage of a package manager for the dependencies in front-end JavaScript development has become mainstream for some time now. One of the downsides is that since it’s now very easy to install and require external modules in your application, if you’re not careful, you’ll end up with a big main.js file in production …

To avoid that, you can use multiple strategies of optimization:

  • uglify
  • deduplicate code
  • split your bundle in multiple ones and only load them on demand

But the very first thing to do is to drop the unnecessary code. For that, webpack provides the Webpack.DefinePlugin which lets you inject your own variables at build time, so that if they are set to false in a conditional, the minification step will drop the dead code.

But if you are using ES6 modules import statement, there is a catch …

webpack.config.js

module.exports = {
  //...
  plugins:[
    new webpack.DefinePlugin({
      '__DEVTOOLS__': false //set it to true in dev mode
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress:{
        warnings: true
      }
    })
  ]
  //...
}

test.js

import { DevTools, logger } from 'some-devtools';

if(__DEVTOOLS__){
  DevTools();
  logger();
}

With this configuration, the code inside the if statement will be dropped at minification since it will be inlined as if(false). But you’ll still be importing those packages that you won’t be using (aka dead code).

In this case you shouldn’t be using ES6 static imports but CommonJS require syntax:

if(__DEVTOOLS__){
  const { DevTools, logger } = require('some-devtools');
  DevTools();
  logger();
}

That way, if __DEVTOOLS__ === false, not only the calls inside this if statements will be dropped but the modules DevTools and logger wont even be part of the bundle, which will make it lighter.

Note: I made this example with webpack, but this kind of feature is available on other module bundlers such as browserify. An other way to resolve that kind of problem would be to specify a list of modules to exclude at build time in production mode …

Update: If you’re doing universal JavaScript (running your code on both client and server side), a good practice would be to use process.env.DEVTOOLS instead of __DEVTOOLS__. A good example is the React setup where you make your own production version of React.

Resources:

Upgraded to react v0.14

logo-reactjs

The genesis of the project:

On october 7th, 2015, Facebook released the v0.14 of React. I took it as an opportunity to get back at React and upgrade those projects to the latest version, to check it out.

The easy part

Upgrading React was in fact the easy part … Since my app was react-warnings free, as said on the upgrade-guide, I only had to:

  • switch to react-dom (and react-dom/server for the server-side). As of now the render engine is a different module (React already did the render on browser and server, but now that there is react-native, it really makes sense to split)
  • switch to react-addons-* modules and drop React.addons which were deprecated (more modularity)

The tricky part

I was using react-router@0.13.2 and by upgrading to react@0.14.0, I ran into invalid peerDependencies problem (react-router@0.13.x couldn’t work with a version of React over 0.13).

So I also upgraded react-router to the v1.0.0-rc3, which has a new API … In fact, the refactor went pretty smoothly for the client-side part (the upgrade guide is well documented).

But for the server-side, I hit an issue: on previous versions, you could attach pretty much any attribute to the object passed from the router to your components. Now if you do that, it won’t get all the way down to your components. The workaround I finally found is to attach those data to the params attribute of the object passed by the router and retrieve them in the props.params of the component … There might be a better way (the createElement API …)

UPDATE: Since then, react-router has released the v0.13.4 which is compatible with react@0.13.x, but I’m glad I did the upgrade, so now I have a client & a server-side project that work with the latest versions of React & react-router!

Sugar

I refactored some components with the syntax introduced in react@0.14 for stateless functional components using ES6 fat arrow (no this, class or anything alike).

As I was at it, I enhanced the build routines:

  • I added banners on html/js/css containing description/version/git revision (something I’m doing by default now on my projects) – for those who are building their project on heroku, check this commit 😉
  • I fixed react-hot-reload for the client-side project (this is a great workflow)
  • I fixed livereloading for the server-side project (when you make changes on a component in development, not only your browser has to reload but your also has your node server, since there is server-side rendering and they both need to have the same version)

Conclusion

This sprint was a great exercise to get back into React – both client and server-side. I also got to play with webpack and gulp (yeah, I enjoy setting up build routines 🙂 ). But moreover, coding in ES6 is great … I enjoy it, I did it on my previous project and please, don’t get left behind, don’t fear webpack/Babel, those are great tools that you could easily setup via a yeoman generator or a boilerplate from git …

I’ll keep using React, I do like this library. My next steps will be to add some animation/transition and setting up redux (or a flux-like implementation).

Tophe

All the code is available on github, each tag has its own release providing a changelog with a list of items pointing to the commits of the version, so if you want to take a peak, please do.

Resources:

Playing with ES6 (and React)

logo-reactjs

UPDATES:

For the last two years, I’ve heard a lot about ES6 : on blog posts, videos, attending at meetups … It was like I knew it already but never really used it … I felt that it was time to get my hands dirty and get on board with this new version of JavaScript – which will be the one we’ll be using in the next years – as some of you will point out : “are already using …”.

As I also wanted to try React (same : heard a lot about it just as if I knew it, but never really wrote any line of code with it). My POC’s endgoal is to do an isomorphic app (server-side rendering, same code running on client and server), for the moment, I finished the client-side part.

Checkout the demo

Using Webpack

Webpack takes your modules (and all their dependencies) then creates a bundle out of them. Since you can run multiple transformers, it will be able to handle ES6 modules, jsx, sass/scssMore infos on Webpack.

Setting up .js and .jsx transpiling (turning ES6 to ES5) using Babel was the easy part. But I also wanted sass stylesheets, with sourceMaps support and not having to require them via js (but in a regular link tag). This part of the Webpack documentation lacks informations (I don’t even know if I did it right, though, it works – as well in dev as in build prod …).

Coding in ES6

At first, it feels like you’re coding in a whole new language (at least, not in JavaScript) 😉 . Using import, export, class, extends … But after all, this is only syntactic sugar, which you would have added by yourself with your own tools or a third party library. Now it’s built-in (this may let JavaScript more accessible to Java/C like devs 😉 ).

Using React

I’ve been using Angular for a long time now. We all know its drawbacks … Some devs are even switching to React for its performances. This is why I was interested in the library (that and the server-side rendering part).

One of the good things in React is it forces you to think “Component” (not the first library to do that – a lot of them are converging towards this concept). You need to know where you’ll keep your state, which part of your app will be mutable, which one will be immutable.

Conclusion

I achieved my goal as I finished this part of my project : coding a POC in ES6, using React. You can see more of the steps on the github repository of topheman/react-es6. The next step will be to use this project to make some server-side rendering (since I used npm packages available for front and back such as superagent, I should be able to take the project “as is”).

You should try ES6, it’s fun to code with and we are seeing it more and more in libraries source code – why not in yours ?

Tophe

PS : The backend of topheman/react-es6 is based on topheman-apis-proxy, a project I made to handle my public APIs. Check it out on github if you’re interested in. I hosted it on heroku, so the VM takes about 3s to warm up when it’s asleep …