Andy Crum

A Quick Introduction to ES6 Modules

It’s no simple task to organize JavaScript. There are many different techniques for modularizing/namespacing your JavaScript, but there’s never been anything native to the language that makes it particularly easy. The “next version” of JavaScript, referred to as EcmaScript 6 (ES6 for short), includes a module specification sure to appeal to most JavaScript developers. The best part: you can start using it right now. But we’ll get to that in a minute. First, let’s look at the syntax.

What do they look like?

Let’s say you would like to create a toaster app to toast your bread. Pretty normal and awesome thing to do, right? Here’s a simple ES6 module for bread:

// bread.js
var canBeToasted = function(type) {
  // only wheat bread can be toasted (your toaster is super picky)
  return (type === 'wheat');

var Bread = function(type) {
  this.type = type;
  this.canBeToasted = canBeToasted(type);
  this.isToasted = false;

export default Bread;

By default, no variables in ES6 modules are accessible outside of the module. So in this case, canBeToasted is declared inside the module and cannot be defined somewhere else.

In order for variables to be accessed outside of the module, they must be exported via the export keyword. Because the Bread function is the only variable we want to make accessible outside of the module, the var Bread = function(type) assignment could actually just be replaced with export default function(type), but for clarity I’ve written it out here. If I also wanted to export the canBeToasted function, the export line would look like this:

export { canBeToasted, Bread };

Bread by itself won’t be that useful, so we need a toaster module. LET’S DO THIS:

// toaster.js
var Toaster = function() {};

Toaster.prototype.toast = function(item) {
  if (item.canBeToasted) {
    item.isToasted = true;
    window.alert('TOTAL TOAST SUCCESS');
  } else {
    window.alert('Toasting this item is IMPOSSIBLE.');

export default Toaster;

Same sort of deal as the Bread module. We’re just exporting the Toaster constructor so we can use it elsewhere.

Let’s say we have a breakfast module, which is the part of our app that needs to actually make our breakfast. One of its tasks will be toasting some bread.

// breakfast.js
import Bread from 'bread';
import Toaster from 'toaster';

var toaster = new Toaster();
var wheatBread = new Bread('wheat');
var whiteBread = new Bread('white');

toaster.toast(wheatBread); // TOTAL TOAST SUCCESS
toaster.toast(whiteBread); // nope.

Something new! As you can see, using ES6 modules, we just need to use the import keyword to grab the exports of the modules we made already. I didn’t need to use the names Bread and Toaster for the imports here – you can call the imported variables whatever you want.

Using explicit import and export statements allows you to easily interact with other modules, but also keep any code private (contained within the module) that doesn’t need to be shared. This is a huge advantage of ES6 modules.

How you can use ES6 modules right now

Currently, the ES6 module specification is still “under development” by the TC39 standardization group. Because of this, browsers don’t understand ES6-speak yet, so your ES6 code needs to be transpiled to JavaScript that the browser understands.

The best way to do this right now is using Square’s ES6 Module Transpiler. You can read more about it at the project’s page, but it works by translating ES6 modules to CommonJS or AMD modules, which are fast and perfectly understandable by the browser. There are ES6 Module Transpiler plugins available for every major build tool, which makes using it pretty simple.

I also should mention that because the module specification is still under development, it is subject to change. It’s likely to remain mostly unchanged, but there may be some syntax changes before ES6 is finalized. Regardless, it’s worth trying out ES6 Modules for yourself – you might even end up having fun organizing your JavaScript.

Do you have questions or comments about something I wrote here? Let me know at @andy_crum or!