Understanding JavaScript Modules: Bundling & Transpiling

This article was peer reviewed by Dan Prince and Ravi Kiran. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Most folks consider modules, dependency management and dynamic loading a basic requirement for any modern programming language—these are some of the most important features added to JavaScript in 2015.

Modules are used extensively in Node but our focus here will be on how we can use modules inside of the browser. We’ll explore a little history, navigate through the hazardous current landscape with the end goal of having a clear path forward and appreciation for the most important module bundlers for JavaScript today: Browserify, Webpack and jspm.

Finally we’ll look at how to use these tools with transpilers like CoffeeScript, TypeScript and Babel.

Modules through the Ages

JavaScript has existed since 1995 and to this day no browser supports modules natively. Node and CommonJS were created in 2009 and the vast majority of packages in npm use CommonJS modules.

Browserify was released in 2011 and brought CommonJS modules to the browser allowing client-side JavaScript to require npm packages. The tool bundles up all of the required dependencies into a single JavaScript file.

The Past

A library such as jQuery adds $ to the global scope or window.

window.$ = function() { ... };

We include a script to a library and use the global objects it exposes.

These are shortened lists of popular tools currently in use—it’s a minefield for beginners and experts alike. The cost of transpiling also highlights that you can mix and match a lot of these tools and get different results.

Let’s Consolidate Tooling in 2016

Front-end developers have been using build tools for a very long time but it’s only in the last few years that we’ve seen a build step become the norm. Tools like Sass and CoffeeScript helped make pre-processing mainstream but the momentum around ES6 has now got everyone on board.

Personally, I don’t care for building asset pipelines any longer, what I’m looking for is minimal config tools that allow me to use modern tooling as needed: Things like Sass, Autoprefixer, Babel and Coffeescript, a proper module system and loader without having to worry about the implementation, configuration and ongoing maintenance. In essence, every developer has been investing time into creating asset pipelines over the last few years, that’s a lot of wheel re-invention going on and a lot of wasted hours.

The community is divided across tools like Browserify, Webpack, jspm, Sprockets and Gulp. That’s not really a problem, it’s just confusing for everyone trying to understand a clear path forward.

Clear Starting Points

There’s a few things we can agree on:

ES2015 modules are the one true future module format for JavaScript.

Babel is the ES2015 compiler of choice today.

Native loaders are still a while away from being available in browsers, a report on the Future of JavaScript by Telerik suggests that complete ES2015 support could take over two years given the module loading hurdle.

If you want to use modules now, that will very likely involve CommonJS at some point.

Let’s look at what minimal configuration setups look like using Browserify, Webpack and jspm, these are the most important JavaScript bundlers to know about today.

We’ll also need a server to run the code—for example live-server which is a great little zero-config HTTP server with live reload capability. Install it globally with npm install -g live-server and run live-server from the project root to start.

Browserify

Browserify lets you require('modules') in the browser by bundling up all of your dependencies.

Browserify will create bundle.js in the project root and you should see a most exiting 4 output to the console. To learn more about what Browserify is doing and how this bundle gets created I recommend watching Introduction to Browserify at egghead.io

Congratulations! We now have modules in the browser! 🎉

Another key benefit of Browserify is that it gives you access not only to modules that you author, but to npm modules as well, let’s install lodash to see.

Webpack will have rewritten bundle.js and the output in the browser should be exactly the same.

Try running npm run browserify and npm run webpack and examining the differences in the compiled bundle.js file. It’s not really important to understand how these tools work internally, the important thing to note is that whilst the implementations are different they are essentially doing the same task of compiling the same code with CommonJS modules into standard browser-friendly JavaScript. Each module is put inside a function within bundle.js and assigned an ID so that it can be loaded as required.

There’s far more to Webpack than this though! It truly is the swiss army knife of module bundlers. Webpack also comes with great tools for development out of the box, things like hot module replacement which will automatically reload individual modules in the browser as they are changed—similar to LiveReload but without the page refresh.

There is a growing list of loaders for different asset types too, even CSS with the css-loader and style-loader—loaders which can compile CSS into the JavaScript bundle and inject it into the page at runtime. This is outside of the scope of this article but more can be found on this at getting started with Webpack.

JavaScript Transpilers

These are three of the most popular transpilers used today, you may also want to use another from the very long list of languages that compile to JS.

Before looking at how we can use them with our module bundlers let’s look at how to use the tools directly first.

The compiler will complain about not being able to find lodash as it requires a type definition to know how to work with external modules that aren’t TypeScript files. You can fetch a definition file with:

The files in /dist now contain ES5 code in CommonJS module format that will work perfectly with Browserify or Webpack as we used previously. You can either transpile down to ES5 with CommonJS first and then bundle, or you can use other packages to do both in a single step.

You can also try loading the ES5 compiled versions of our CoffeeScript or TypeScript modules by uncommenting those lines one at a time. Another option is to use System.js plugins to transpile the code, rather than requiring precompiled ES5 code.

Add a final script to package.json for creating a bundle with jspm

"jspm": "jspm bundle src/entry bundle.js"

Run it with npm run jspm

Finally uncomment the script tag for bundle.js in index.html and the browser should load a production-ready bundle without any extra http requests.

<script src="bundle.js"></script>

Revisiting Webpack

Our Webpack example earlier was the simplest example using the default options, it compiled entry.js with CommonJS modules down into a single bundle. When doing more fancy things with Webpack you’ll want to create a custom config file for all of the loader configuration.

There is so much more to Webpack than I’ve covered here, but these simple setups are a great starting point.

There and Back Again

And so we end our exploration of modules, they do solve a lot of problems and can really reduce the complexity of our applications—if the tooling doesn’t get in our way. If you’re not already using modules, now is the time. No need to spend unnecessary hours building asset pipelines, instead use simple tools that Just Work™.

Webpack is the current juggernaut and you’ll be able to configure it to do almost anything. jspm is a great tool for all your bundling needs and works with a variety of formats and has a nice developer experience. Browserify is still a solid option, the grandfather of modern module bundlers—it’s ecosystem has grown to include some of Webpack’s much loved features (such as bundle splitting and hot reloading). Finally System.js is perfect for when you need to be able to load extra modules at runtime.

You won’t want to use all of the above tools in one project but it’s important to have an understanding of these three popular options, as well as how you can use transpilers when the need arises. If you just want to use modules, then Browserify, jspm or Webpack with the default options will do the job.

Hello. I'm a front end web developer from Melbourne, Australia. I enjoy working on the web, appreciate good design and working along side talented people I can learn from. I have a particular interest in visual programming so have fun working with SVG and Canvas.