ES6 Everyday: Modules

For a lot of longtime JavaScript developers (and especially those from the Node world), this is long overdue: yes, ES6 has modules.

When writing a JavaScript-heavy application, things always seem to start simply:

function displayCampingSites() {
  // ...logic to display camping sites
}

And then things get a little more complex:

function getCampingSites() {
  // ...logic to pull camping sites from an API
}

function parseCampingSites() {
  // ...logic to parse data from API
}

function displayCampingSites() {
  // ...logic to display camping sites
}

And, then, even more complex:

function getUserLocation() { /* ... */ }
function getGeoBoundingBox() { /* ... */ }
function getCampingApiUri() { /* ... */ }
function makeJsonpRequest() { /* ... */ }
function getCampingSites() { /* ... */ }
function parseCampingSites() { /* ... */ }
function displayCampingSites() { /* ... */ }>

Until you’ve got a single JavaScript file stuffed to the brim with all of your code.

ES6 introduces a module syntax that lets you split this logic off into separate files.

You start by siphoning off your code into a module and exporting the members for public consumption using the export keyword:

// In a separate file: "geolocation.js"

export function getUserPosition() {
  // ...logic to get a user's current geolocation position
}

And then importing that module using the import keyword:

// In a separate file: "main.js"

import Geolocation from "geolocation.js";

Geolocation.getUserPosition()

As you can see, this puts Geolocation into the current scope with the member that we exported using export.

We aren’t tied to any specific name for our module:

import GeoUtility from "geolocation.js";

GeoUtility.getUserPosition();

We can also export multiple members, including variables:

// In a separate file: "geo-math.js"

export var defaultRadius = 20;

export function convertLatLonToXY() { /* ... */ }

export function convertXYToLatLon() { /* ... */ }

Which, if we like, we can express more cleanly as follows:

// In a separate file: "geo-math.js"

var defaultRadius = 20;

function convertLatLonToXY() { /* ... */ }

function convertXYToLatLon() { /* ... */ }

export { defaultRadius, convertLatLonToXY, convertXYToLatLon };

To import these multiple members, we can do the same thing as before:

import GeoMath from "geo-math.js";

GeoMath.convertLatLonToXY();

Or we can import individual members, in which case the individual members get dumped into our current scope:

import { defaultRadius, convertLatLonToXY } from "geo-math.js";

console.log(defaultRadius); // 20
convertLatLonToXY();

And we can provide aliases as well:

import { convertLatLonToXY as latLonToXY } from "geo-math.js";

latLonToXY();

Unfortunately, you can’t really see this one live in browsers yet: to try it for yourself, you’ll need to make use of a transpiler or polyfill; this 24 Ways article includes a number of resources for using ES6 modules today.

Resources