ES2015 using Node, Babel and Webpack
Jul 13, 2016
warning
This post is more than 5 years old. While math doesn't age, code and operating systems do. Please use the code/ideas with caution and expect some issues due to the age of the content. I am keeping these posts up for archival purposes because I still find them useful for reference, even when they are out of date!
In this post I will cover setting up a project that uses ES2015/ES6 -- modern JavaScript-- that will still work in current web browsers that need ES5. The trick is to use Babel to transpile ES2015/ES6 code to ES5, which can run on current browsers. Why do this? Well, ES2015/ES6 is the future of JavaScript and I'd like to start using it now.
All readers should be aware that I am not an expert. This post is as much for me to remember what I did as to inform others on what to do. So, let me know if you have better ways to do this or you find mistakes -- please use the comments at the end of the post.
To get started, I would like to credit posts by others that really helped me sort this out (however, all mistakes are my own). I will be using a combination or re-mix of the following two sources:
- Understanding JavaScript Modules: Bundling & Transpiling (by Mark Brown) -- this covers a lot of ground, including the topics here. I found it very useful but it's definitely not for the beginner.
- Introduction to Webpack: Part 1 (by Stuart Memo) and Introduction to Webpack: Part 2 (by Stuart Memo) -- these posts are at more basic level and are focused on using webpack. In particular, the first part is a very nice reference for the topics covered here.
So, credit to both authors, Mark Brown and Stuart Memo, for the original source material as well as motivation!!!
node and npm
In a previous post, Installing node LTS version on Ubuntu 14.04 , I covered installing node and the node package manager (npm) on Ubuntu 14.04. I will be using these tools to drive everything so you should look at the post if you do not have them installed. For reference, at the time of this post I have:
$ node --version
v4.4.7
$ npm --version
2.15.8
You should have similar versions, or higher. Next, I will install two packages globally: webpack and live-server --
$ npm install -g live-server webpack
If this command complains about permission issues, try setting up a sudo-free location for global installs of npm packages. I've added a section to Installing node LTS version on Ubuntu 14.04 that covers how to do this on Ubuntu 14.04.
project setup
Next, I will create a project directory and use npm to create a package.json file
$ mkdir es2015-project
$ cd es2015-project/
$ npm init -y
Using the -y
tag forces the defaults to
be used for package.json and the resulting file looks
something like this:
{
"name": "es2015-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Of course, you can init without this flag or change the file after-the-fact to your liking. Next, I create some directories and files that will be filled with code:
$ mkdir src
$ touch src/{main,lib}.js index.html
If I use tree
to show the project layout
at this point it looks like this:
$ tree .
.
├── index.html
├── package.json
└── src
├── lib.js
└── main.js
1 directory, 4 files
index.html
First, I setup an index.html file that will be used to load the resulting code and do some simple calculations (this is motivated by the Mark Brown's example; see link above):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>es2015-project</title>
</head>
<body>
<h1>Results</h1>
<p>timesTwo(2) = <em id="result1"></em></p>
<p>addFive(2) = <em id="result2"></em></p>
<script src="bundle.js"></script>
</body>
</html>
As you can see, I left the two results empty-- look for the
em
tags in the above html. These will be
filled with our fantastic ES2015/ES6 code below.
At this point I fire up live-server
,
installed above, to watch the index.html
file, as well as others, that I have created:
$ live-server
This will load index.html
in the
default system browser-- of course, the
answers will not be there because the code still needs to be written.
Note:
To be clear, make sure that you are in the root project directory, where the
index.html
file is located, when running the
live-server
command. It also
helpful to start this up in another terminal so that the messages from
live-server
can be monitored/ignored
and it is easy to shutdown (use
control-c
). Or, if you use
tmux
or
screen
, open a new window and start
live-server
there.
lib.js and main.js
Next, we create out ES2015/ES6 code in two files so that we can illustrate
import and export. First, let's create
lib.js
(again, motivated by original
code from Mark Brown's post; link above):
// lib.js
const timesTwo = (number) => number * 2
const addFive = (number) => number + 5
export {
timesTwo,
addFive
}
and then, main.js
that uses the
functions defined in lib.js
and changes the
contents of index.html
// main.js
import {timesTwo, addFive} from './lib.js'
document.getElementById('result1').textContent = timesTwo(2)
document.getElementById('result2').textContent = addFive(2)
Okay, that's our ES2015/ES6 code, but we still need to use Babel to
transpile the code and webpack to create the
bundle.js
file.
babel and webpack
Next, we install the babel requirements for our project using npm:
$ npm install --save-dev babel-loader babel-core babel-preset-es2015
The install command, with the --save-dev
switch, will install the babel-related code locally (in the node_modules
directory) and save the requirements in the
packages.json
file.
Next, we create a file called webpack.config.js
that will use Babel to transpile and create the
bundle.js
that is
imported and used by
index.html
. The contents are (this is
motivated by Stuart Memo's post; links above):
// webpack.config.js
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015']
}
}
]
}
};
Finally, we run webpack
in the project
root directory -- the same level as the
webpack.config.js
,
index.html
and
package.json files
. To be concrete, the
project looks like this:
├── node_modules
│ ├── babel-core
│ ├── babel-loader
│ ├── babel-preset-es2015
│ └── webpack
├── src
│ ├── lib.js
│ └── main.js
├── index.html
├── package.json
└── webpack.config.js
Hopefully that's clear. Now run webpack, the result should look something like this:
$ webpack
Hash: 33586f23235394783d03
Version: webpack 1.13.1
Time: 3413ms
Asset Size Chunks Chunk Names
bundle.js 1.99 kB 0 [emitted] main
+ 2 hidden modules
Now the index.html
page, being displayed
and updated with live-server
, should
show calculated values inserted into the page-- very cool.
adding npm packages
As a final example, again motivated by Mark Brown's post, I will install
lodash
and use that do the sum in
addFive
. The point of this is mainly
to show that it is possible -- also very useful! It turns out that I have
already done most of the hard work. First, I install lodash:
$ npm install --save-dev lodash
Next, I modify the lib.js
to use
lodash
, as below:
// lib.js
import sum from 'lodash/sum'
const timesTwo = (number) => number * 2
const addFive = (number) => sum([number, 5])
export {
timesTwo,
addFive
}
Notice that I only make two small changes:
-
import
sum
fromlodash
-
change the
addFive()
function to usesum()
Otherwise, there are no changes. To make this live, we need to run webpack again to transpile to ES5 and live-server will automatically refresh the new code:
$ webpack
Hash: 733b2ca4f2f0c808b86e
Version: webpack 1.13.1
Time: 3619ms
Asset Size Chunks Chunk Names
bundle.js 3.91 kB 0 [emitted] main
+ 5 hidden modules
That's it -- I'm coding in ES2015/ES6 and running it in the browser. Try it out and see what you think. Also, don't forget to checkout the motivating posts by Mark Brown and Stuart Memo -- links at the top of the post.