Writing client-side ES6 with webpack

This blog post is outdated (it covers Babel 5). Please read Sect. “Browser setup: ES6 via webpack and Babel” in “Setting up ES6”.

webpack is a client-side module builder and module loader. This blog post shows you how to write ECMAScript 6 code with it.

The code shown here is on GitHub, in the project webpack-es6-demo.

webpack features

Notable webpack features include:

  • Supported module formats: AMD, CommonJS
    • Via loader (plug-in): ES6
  • Supported package managers: Bower, npm
  • Loaders for non-code: CSS, templates, …
  • On-demand loading (chunked transfer)
  • Built-in development server

Installing webpack

Install webpack:

    npm install -g webpack

Enable support for ECMAScript 6 (via Babel):

  • Per project: npm install babel-loader --save-dev
  • In your home directory: cd $HOME ; npm install babel-loader
  • Globally: npm install -g babel-loader

Using webpack and ES6 in a project

The demo project webpack-es6-demo has the following structure:


The following command compiles the ES6 files es6/Point.js and es6/main.js to a file bundle.js:

    webpack --watch

After executing the previous command, you can open index.html in a web browser (directly from the file system if you’d like). index.html runs bundle.js, which means that you get to see what main.js is doing.

In real-world projects, you probably won’t use webpack directly, but via build tools, such as grunt, gulp, etc.


This is the configuration file for webpack:

    var path = require('path');
    module.exports = {
        entry: './es6/main.js',
        output: {
            path: __dirname,
            filename: 'bundle.js'
        module: {
            loaders: [
                { test: path.join(__dirname, 'es6'),
                  loader: 'babel-loader' }

Things work as follows:

  • Input: is specified via the property entry. This is where the execution of JavaScript code starts.
  • Output: webpack bundles the entry file and everything it depends on into the output file bundle.js (which resides in the same directory as webpack.config.js).
  • Support for ES6: is enabled via a the module loader babel-loader.
    • Property test: specifies what files the loader should be used for.
      • Single test: regular expression or string with an absolute path
      • Multiple tests: array of single tests (logical “and”)


The HTML file starts JavaScript via the bundle file that was created by webpack.

    <!doctype html>
        <meta charset="UTF-8">
        <title>webpack ES6 demo</title>
    <script src="bundle.js"></script>

ECMAScript 6 code

The following two ECMAScript 6 files were packaged into bundle.js.


    import Point from './Point.js';
    var body = document.querySelector('body');
    body.textContent = 'Good point: ' + new Point(1, 23);


    class Point {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        toString() {
            return '('+this.x+','+this.y+')';
    export default Point;

Note that the paths follow Node.js conventions.

Using npm packages

You can install packages via npm and use them from your ES6 code, seamlessly. For example: First install lodash.

    $ mkdir node_modules
    $ npm install lodash

Then use it anywhere in your ES6 code:

    import { zip } from 'lodash';
    console.log(zip(['1', '2'], ['a', 'b']));

Alternatives to webpack

If webpack is not your cup of tea, there are several capable alternatives for writing client-side ES6 code. For example:

webpack, jspm and Browserify can also use Traceur instead of Babel, if you want to.


Axel Rauschmayer said...

Somewhat OT but: Is there *any* sane convergence of app dependencies and dev dependencies?

Using NPM+package.json .. you'd think there would be a trivial addition to that to make both possible.

Or, on the other hand, a jspm solution which would also work for dev dependencies.

Workflow is starting to overtake the development itself!

Axel Rauschmayer said...

Unsure what you mean, npm has devDependencies and dependencies that you can use separately; devDependencies for development tooling / creating builds; dependencies for code used by your application at runtime.

Axel Rauschmayer said...

Here is a personal project: Woc.ts, a framework for front-end applications in TypeScript. I built it to handle the two loading ways: load each file.js when developing, or load a limited number of deployed bundles, as part of modular developments (by components, but not Web components). It is a framework approach, the framework defines also a way of organizing the code, that helps to work with other programmers or teams. But with modules ES6, I can't determine whether my work is questioned. Can still be useful? What do you think? Is it meets a need?

Axel Rauschmayer said...

Yup, both --save & --save-dev are useful and maintain the package.json file correctly. But, AFAIK both go in node_modules, thus making it a bit awkward to package up your front-end app. I suppose grep-ing the package.json could build your app dependencies.

But really, from a higher level point of view, I see a lot of discussion on workflow and they divide into separate front-end and dev workflows. I'd like a simpler system that did both.

I guess if I could use --save but have it use a different folder, that would do the trick.

My bet is that most of this gets resolved with ES6 modules becoming ubiquitous. Hence this post including jspm.

You can tell my workflow-fu is pretty lacking! :)

Axel Rauschmayer said...

You can also use `npm prune --production` to remove dev dependencies prior to creating your deployable artifact.

My general workflow looks similar to the following (I use / make build servers):

git clone $REPO_URL ./repo
cp -r ./repo $BUILD_DIR/fresh
cp -r $BUILD_DIR/fresh $BUILD_DIR/test
cd $BUILD_DIR/test
npm i
npm test
# put failure logic here
# move to fresh dir where no test files may have cluttered our artifact
cd $BUILD_DIR/fresh
npm i --production
npm shrinkwrap
# other hardening logic / bootstrapping here
zip -y -q -r artifact.zip .
mv artifact.zip $DESTINATION
rm -rf $BUILD_DIR

Axel Rauschmayer said...

You should fix your Point.js file. In Babel 5.0.0+ you should always invoke `super()` before using `this`

Axel Rauschmayer said...

That is only necessary for derived classes (that extend other classes).

Axel Rauschmayer said...

oh sure. sorry

Axel Rauschmayer said...

I just clone the repo to another directory and do npm i --production

Axel Rauschmayer said...

and must never be called in not derived classes.

Axel Rauschmayer said...

so many technologies in JavaScript... it's hard to know which one to choose... What is the simple way to do ES6 in the browser ? webpack, jspm, SystemJS ? and ES6 with ReactJS ?


Axel Rauschmayer said...

The setup described in this blog post gives you ES6 + React/JSX in browsers. If you want to make it simpler, you can omit gulp and use webpack directly (as described in the webpack documentation).

Axel Rauschmayer said...

Thanx ! I will try it.