« Previous Tutorial Next Tutorial »

Welcome back to Five Minute React. While we’re still a ways away from deploying any code to production, things like our Webpack configuration and Redux setup are starting to get fairly complex. This isn’t inherently a problem—this is complicated stuff we’re doing, here!—but it makes sense to start thinking about the differences between a production environment, and a development environment before we move further into coding.

When working in a development environment, there are things that are extremely beneficial to us that are actually a detriment in a production environment. For example, non-minified code is tremendously useful in dev. In prod, it increases filesize significantly for no real reason. You shouldn’t need to be combing through lines of JavaScript in prod, because you shouldn’t be deploying anything there that hasn’t already been thoroughly tested.

There are some other things we’ll want to avoid in production. We’re not making code changes in prod, so hot-reloading just burdens our users with increased bundle size for no reason. We also certainly won’t want to be serving our bundled javascript and CSS via a dev server when we can just one-time output static files that the browser will cache. Additionally, our Express webserver behaves differently in dev than in prod; it caches more stuff in the latter environment.

So, we need to make some changes to our configurations to deal with the differences between a production and development environment. We’re going to do that by setting what’s called an environment variable, which tells our Node and React applications which environment we’re in. Setting an environment variable is straightforward. There are several ways to permanently set your server environment, but I prefer not to do that. Instead, I prefer to create scripts that set the environment for me right before running the application.

As is often the case, we’re going to start by installing a few modules. We’ve been using Babel’s “ES2017” settings but unfortunately, they currently conflict with the minifying plugin we’re going to use with Webpack. The good news is: we’re not using anything that requires ES2017 right now, so we can safely downgrade to ES2015, which still supports all of the ES6 goodness we’ve grown accustomed to. Your arrow functions are safe! So, let’s add those modules. Hit a command prompt or terminal window and type the following:

yarn add babel-preset-es2015

Hit enter and let that run. You may note we’re not adding anything for Webpack. That’s because it has an “uglify” plugin built in that minifies your code by reducing variable names down to single letters and sticking everything on one line, among other things. Hooray!

Now let’s open package.json. In addition to writing some scripts, we’re going to do a little cleanup, since there are a few things in here now that we no longer need. Start by removing line 8:

    "start-w": "webpack-dev-server",

We no longer run a separate dev server for Webpack (we exchanged that for Express middleware instead), so we don’t need that. We can also remove this line:

    "babel-preset-es2017": "^6.24.1",

Because we’re not going to be using it anymore. Finally, we can remove the last line of our devDependencies block, near the bottom of the file:

    "webpack-dev-server": "^2.4.5"

because we’re not using that anymore, either. Don’t forget to remove the trailing comma on the line above.

Hey, notice that whole “devDepenencies” thing? That’s another thing we can use to reduce the overall size of our application. If, when we deploy our application to a production server, we run yarn install --production , it will ignore the entire devDependencies block and not bother to install any of those modules. That’s a handy thing to know, and I’ll remind you of it when we get to actually deploying a production build.

By the way, removing this stuff from package.json does NOT remove it from your node_modules folder. There are ways to do that with Yarn or NPM, but we’re manually editing package.json right now because we’re shortly going to just nuke node_modules and start over again, which is sometimes easier than trying to keep track of what’s been installed and removed.

OK, save package.json and open .babelrc. We have to make some changes here because the ES2015 preset will break hot reloading if we’re not careful. So let’s be careful! Change this code:

{
  "presets": ["es2017", "react"],
}

to the following:

{
  "presets": [
    "react",
    [ "es2015", { "modules": false } ]
  ]
}

Save that, and move on. It’s now time to dive into our Webpack config, so open webpack.config.js. This is not going to be as complicated as you might think … at least, not right away! Our Webpack config file will grow progressively more complex as this series continues and our app takes shape, but that kind of makes sense, right?

Here’s all we need for right now: at the very bottom of the file, add the following three lines of code:

if (process.env.NODE_ENV === 'production') {
  module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

What’s happening here is we’re checking for our “NODE_ENV” environment variable, which is available to Node applications via the “process.env” global variable. If it’s equal to production, we’re uglifying our JS bundle. If it’s not, we skip that step, leaving us with unminified code, which is much easier to debug.

Save this file, and head back to package.json. We’re going to create a new script, just under our “start” script. This will be different depending on whether you’re on Windows or Mac … but not different enough to bother switching between videos. Here’s the code for Windows:

    "start-prod": "SET NODE_ENV=production&& node ./bin/www",

Note: it’s really important to not have a space between the word “production” and those ampersands, otherwise Windows thinks you’re setting your environment to “production ” with a space, and then your if block will fail.

Here’s there code for Mac (or other Unix-based OS’s):

    "start-prod": "NODE_ENV=production node ./bin/www",

In both cases we’re just saying “set our environment variable to ‘production’ and then run our launch script as normal.” This will allow us to test that our minification is working. Obviously, there’s more to come, because for right now we’re still going to be running our Webpack development server, which we don’t want. But we should see an immediate and fairly massive reduction in file size.

So let’s check. Real quick, head for your command prompt or terminal window. First, kill your server, and then just run

yarn start

to get your development build. If you look at the top of the big chunk of Webpack output, you can see the exact file size of your bundle. I get the following:

Asset     Size  Chunks                    Chunk Names
javascripts/build.js  2.74 MB       0  [emitted]  [big]  main
stylesheets/style.css   192 kB       0  [emitted]         main

2.74 MB is horrific. Just awful, especially if you’re planning on catering to mobile users. Let’s see what our production build looks like. Kill your server, and run this command instead:

yarn run start-prod

And let’s take a look at our build size now:

Asset     Size  Chunks                    Chunk Names
javascripts/build.js  1.14 MB       0  [emitted]  [big]  main
stylesheets/style.css   192 kB       0  [emitted]         main

Holy crap! With one little change, we’ve cut our filesize by over 60%! Yes, 1.14 MB is still too large (notice that Webpack is even giving us a “big” warning), but that’s a massive, insane savings for a three-line JS change. Great work!

That’s it for this tutorial. In the next one, we’ll continue with optimization and preparing for production. See you then!

« Previous Tutorial Next Tutorial »