Update on 2015/11/08: Now works with Babel 6.0

Just want a starter kit? Clone webpack-black-triangle for something minimal, or the Unicorn Standard Starter Kit for the works.

There’s been a huge amount of press since ES6 was finalised as ES2015 – but for all the awesome features it adds, it won’t help you much if you can’t actually use it. The problem is that while ES6 is the future, the current crop of browsers are stuck in the past. Want proof? Give Chrome an arrow function, and it’ll give you this:

Of course, there is more to the story than this. You can use ES6 in the vast majority of modern browsers, but with a catch: you’ll need a build step. And while this has been a deal-breaker for many in the past, we’ve entered an age where it doesn’t have have to be.

Build steps no longer mean 300 line configuration files

There’s been a lot of progress in the world of JavaScript build tools over the past few years. In particular, webpack burst onto the scene to the delight of all who’ve had to deal with long, complicated Gulpfiles and Gruntfiles.

Webpack lets us do a lot with very little effort – for example, the configuration file in the github project for this post tells webpack how to transpile ES6 with Babel, compile LESS, and reload the page when files are changed – all in 26 lines.

Reddit’s /u/nickguletskii200 put it like this:

Webpack is the least retarded piece of software I’ve used that’s written in JS.

With all this in mind, I recently chose webpack for the build system of memamug.com, a small open-source app I’m writing with a React-based frontend. And given the biggest complaint with webpack is it’s lack of documentation, I thought I’d walk you through the process while it’s still fresh in my mind.

The code we’ll use to test our build process

But before we can start, we need some ES6 code to run our build process on. And as luck might have it, I’ve made an over-engineered black triangle, just for you. It will even start spinning once you’ve got things working.

Let’s give the code a directory and get it displaying in your browser before we worry about the build process. To start, either copy across the files to a new directory, or clone the gist with git:

$ git clone https://gist.github.com/9b7db05268e747b4aa4d.git black-triangle

Assuming you’ve now got a black-triangle directory, let’s change into it and improve the project’s feng-shui by moving the source files to their own directory:

$ cd black-triangle $ mkdir src $ mv index.html main.js BlackTriangle.js src

Then all that’s left is to start her up – by opening index.html in a web browser. And assuming you’re not living in the future, you should see an incredibly boring (and immobile) black triangle, like this:

Minimum Viable Webpack

Of course this isn’t a blog about black triangles – it’s a blog about webpack & Babel – so let’s install them. Assuming you have node.js set up, this is as easy as:

$ npm install webpack-dev-server -g $ npm install webpack-dev-server webpack babel-core babel-loader babel-preset-es2015 babel-polyfill

All that’s left is to start the server! We do so with the webpack-dev-server command, which takes the path to our HTML content ( src in our case), and the JavaScript entry point ( src/main.js ). Give it a shot from your black-triangle directory:

$ webpack-dev-server --content-base src src/main.js

Doh. It looks like webpack is still choking on ES6. And, if we view our app at localhost:8080, we still see an immobile black triangle. What gives?

Configuring Webpack

While we’ve installed everything we need to get webpack to understand ES6, we still need to tell it how to do so. We do this with webpack’s configuration file, webpack.config.js . This file lives in the root directory of your project, and is just plain-ol’ JavaScript.

To spin your triangle up, add a webpack.config.js file in your black-triangle directory with the following content, then restart webpack-dev-server and reload your page. Don’t worry about how it works just yet – I’ll walk you through it in a moment.

var path = require('path'); var webpack = require('webpack'); module.exports = { entry: [ 'babel-polyfill', './src/main' ], output: { publicPath: '/', filename: 'main.js' }, devtool: 'source-map', module: { loaders: [ { test: /\.js$/, include: path.join(__dirname, 'src'), loader: 'babel-loader', query: { presets: ["es2015"], } } ] }, debug: true };

To stop webpack-dev-server, press ctrl-c (yes, even on a mac).

There is no need to restart the server after changing files other than webpack.config.js – just refresh the page.

Have you got your triangle spinning? If not – leave a comment and I’ll try and help you out! Otherwise, let’s take a quick tour of the config file.

webpack.config.js in two minutes

First, about the file itself:

webpack.config.js is a normal JavaScript file, evaluated with node.js. You can do normal node.js things like require modules and check environment variables. Webpack’s configuration is placed in the object which the file exports, i.e. whatever you assign to module.exports .

Now, about the keys in the configuration object we just set up:

entry is an array of files which will be run at startup. We run Babel’s polyfill first, before running our main JavaScript file. output tells webpack-dev-server where to serve compiled files from. We tell it to build a single file labeled main.js , directly on the server’s root – hiding the original main.js from your browser. devtool tells webpack to automatically serve us source maps as well, so browsers can display the original source in their development console (as opposed to the compiled source). module.loaders is a list of loaders – npm packages which allow webpack to transform our source. We tell webpack to run .js files from the src directory through babel-loader, using the es2015 plugin to transform ES2015 (i.e. ES6) to ES5. debug let’s our loaders know that they don’t need to make release-ready code

If you ever need to know more about webpack’s config object, there is documentation available on it’s website. It’s not for the faint of heart, though, so don’t read it until you have to.

To summarise, you’ll generally find that all you need to know is:

entry points are where self-contained scripts go

points are where self-contained scripts go module.loaders is where you put things which transform your code

There is, as always, an exception: the plugins configuration options is super-useful – but generally only once you want to deploy. I’ll explain how to use plugins for things like minification in a future guide, and the only way to ensure you don’t miss out is to join my Newsletter. And in return for your e-mail, you’ll immediately receive a free print-optimised ES6 cheatsheet! But for today, let’s finish by adding a few nifty tweaks to your webpack configuration.

Get the ES6 Cheatsheet Thanks! Please check your email for the link to your cheatsheets.

Tweaks to make your life easier

1. Automatically reload page on save

One of the biggest wins from using webpack-dev-server is that it notifies your browser when files change. Of course, nothing will happen unless you listen to these notifications, but luckily, webpack-dev-server includes a handy self-contained script which both listens to the notifications, and reloads the page for you when it receives them.

The script in question is 'webpack-dev-server/client?http://localhost:8080' . Why not have a shot at adding it yourself based on what you learned above. Once you’re done, touch or hover over the blank box below for an answer.

entry: [ 'babel-polyfill', './src/main', 'webpack-dev-server/client?http://localhost:8080' ],

2. Default options for webpack-dev-server

Typing out this monstrosity every time you want to start the server can get a little tiring:

$ webpack-dev-server --content-base src src/main.js

Luckily, you can specify default options for webpack-dev-server by adding a devServer object in webpack.config.js . The keys in this object are just the camelized versions of those you’d pass to the command line version.

If that’s a bit of a mouthful, don’t worry – all you need to know is you should add this to your webpack.config.js :

devServer: { contentBase: "./src" }

And then you can omit the --content-base src from the above command.

3. Record your dependencies and entry point with package.json

If you already know how package.json works, you can skip this section.

My final tip is to set up a package.json . There are so many good reasons to use it that I can’t list all of them, but here are two relevant ones:

You can record your dependencies (e.g. webpack & babel), then install them again using npm install .

. You can define a start script, so you don’t even need to remember webpack-dev-server – just npm start .

Setting up package.json is so incredibly simple that you really have no reason not to do it, so let’s do it now. Ready? From your black-triangle directory, type this:

npm init

Now follow the prompts, remembering to enter src/main.js as your entry point.

And now you’ve got your package.json . How easy was that! Let’s finish it off by telling npm about what to do when we type npm start : do so by adding a new key to the generated package.json file’s scripts object, as so:

"start": "node_modules/webpack-dev-server/bin/webpack-dev-server.js"

Finally, test it out by shutting off your existing server (if it is running), typing in npm start , and visiting localhost:8080.

And there you have it – an ES6-compiling, automatic reloading dev server, which can be started as easily as typing npm start . Neat!

But don’t close the tab just yet. To really make it worth your while having read this article, you need to remember the important parts – and what better way to do so than with a useful exercise.

Exercise: Compiling and watching your LESS/SCSS files

This exercise is small in scope but big in result. It involves adding only two lines to your webpack.config.js , and in return you’ll get near-instant updates to your browser’s stylesheet as soon as you save the changes to your .less or .scss files.

To get started, you’ll need to install a few loader packages:

npm install style-loader autoprefixer-loader css-loader less-loader --save-dev

Substitute less-loader for scss-loader if that’s how you roll.

Once the packages are installed, you’ll need to make two changes to webpack.config.js :

Add your new loaders to a .less or .css line in the module.loaders section, using the ! character to feed loaders into each other (see the documentation for more details) Add your new stylesheet to the entry section (yep, you can include more than just JavaScript with webpack)

Don’t forget to move the styles out of index.html while testing!

Make sure you don’t get bogged down in this exercise – feel free to quit after 10 minutes or so. The important thing is that you give it a shot. Once you have given it a shot, you can check out my solution, and how I’ve wired this whole project together, at github.com/jamesknelson/webpack-black-triangle.

Awesome. Now how do I configure my app for deployment?

Well, first you’ll want to minify it. Then, you may want to bake in some environment variables so you can set different API keys in development and production. You’ll probably want to extract your CSS to a separate file, and you’ll also want to cache-bust your generated assets. And that will require some way to modify the src attribute of your <script> tag to match.

Now you could just clone my Unicorn Standard Starter Kit. But if you actually want to understand what is going on under the hood, the only way to ensure you don’t miss the guide is to get on my Newsletter.

And to sweeten the deal, you’ll immediately receive three bonus print-optimised PDF cheatsheets – for React (see preview), ES6 and JavaScript promises – completely free!

I will send you useful articles, cheatsheets and code. I won't send you useless inbox filler. No spam, ever. Thanks! Please check your email for the link to your cheatsheets.

One more thing – I love hearing from readers. If you have something to say, send @james_k_nelson a tweet, or send me an e-mail at james@jamesknelson.com. Thanks for reading!

Resources

Unicorn Standard Starter Kit – a deployable React project skeleton built on webpack-black-triangle

webpack-black-triangle – a minimal webpack configuration based on this guide

Official Webpack Documentation

Read more