notoriousb1t

Getting Started with ES6 Modules

The ES6 module feature is one of the most important changes to come to JavaScript in recent history. It has the power to transform an unwieldy mess of 10,000 lines into smaller bite sized pieces and only use the parts you really need.

A Single Import/Export

ES6 modules allow you to export functions, classes, and variables with the export keyword and import them into other modules with the import keyword. Let's take a look at a simple example.

lists.js

/**
* returns the first item in the array or undefined
*/
export function head(list) {  
    if (!list || !list.length) {
         return undefined;
    }
    return list[0];
}

main.js

import { head } from './lists';

const array = ['first', 'second', 'third'];  
const first = head(array);

// prints first
console.log(first);  

In lists.js, I am exporting a head function that returns the first in the array. Then in main.js, I am importing only the head function in, defining an array of words, and then logging the first word to the console by calling the head function.

The beauty of this system is that I can define a lot of stuff elsewhere and then import all or some of each of those modules as I need in each file.

Let's try to import everything in.

Importing Everything

Sometimes it is easier to import everything at once. Fortunately, there is a concise syntax to do that. Instead of placing each imported thing in { }, I can simply assign an alias to all the objects in the module.

lists.js

/**
* returns the first item in the array or undefined
*/
export function head(list) {  
    if (!list || !list.length) {
         return undefined;
    }
    return list[0];
}
/**
* returns the last item in the array or undefined
*/
export function tail(list) {  
    if (!list || !list.length) {
         return undefined;
    }
    return list[list.length - 1];
}
/**
* returns a copy of the list or empty
*/
export function copy(list) {  
    if (!list || !list.length) {
         return [];
    }
    return Array.prototype.slice.call(list, 0)
}

main.js

import * as lists from './lists';

const array = ['first', 'second', 'third']; 

const first = lists.head(array);  
const last = lists.tail(array);

// prints 'firstthird'
console.log(first + last);  

In the example, I am importing the entire lists module as lists, creating an array of three items, getting the first and last items, and then printing them together on the console.

When you * alias a module, you get everything in the file. Sometimes I use this when I am importing more than six things from a file.

Exporting to Group Together

I can also import and export at the same time to group together files. I have heard these called barrel files.

./barrel/bananas.js

export var bananas = ['banana', 'bananas'];  

./barrel/kongs.js

export var donkey = 'Donkey';  
export var diddy = 'Diddy';  
export var dixie = 'Dixie';  

barrel.js

export { bananas } from './barrel/bananas';  
export { donkey, diddy, dixie } from './barrel/kongs';  

main.js

import { bananas, donkey, diddy, dixie } from './barrel';

const text = [bananas, donkey, diddy, dixie].join(', ')

// prints 'Bananas, Donkey, Diddy, Dixie'
console.log(text);  

In the example, I am combining the objects in the bananas.js and kong.js files into barrel.js and importing barrel into main and printing each of the things.

Barrels are a great tool to help organize large applications or libraries intended for other people to use.

Other Things I Don't Use Often

For the sake of being comprehensive, here are some ES6 module features I don't use very frequently, but are important to know about:

main.js

// imports the 'default' export
import defaultThing from './utils';

// imports the file for side effects, doesn't actually pull anything in
import './side-effect';

// exports myFunction as a default
export default function myFunction() {  
    return 'my';
}

Wrapping Up

I can't wait for modules to have native support in browsers. In the meantime, I recommend using SystemJS to load them as you need them, or a bundler like Webpack or RollupJS to glue everything together.