Volver

JSBits #0: an introduction to JavaScript modules

Diario del capitán, fecha estelar d60.y38/AB

Javascript Backend Frontend Development
JSBits #0: an introduction to JavaScript modules

We have been accumulating a lot of knowledge in JavaScript over the years that we want to share with you in frequent bits, so we'll call this JSBits!

I have been advocating for greater use of JavaScript inside the company since I joined in 2017. Back then, at MarsBased we only used Ruby on Rails for the backend and Angular for the frontend. However, that's changed over the years, and we've done projects in Ionic, Node.js, React, and Vue, which show the evolution of the company as it has expanded to almost 20 people nowadays.

Since 2018, I have been sharing cherry-picked pieces of information about JavaScript on our Basecamp, for those interested in learning more about JS as a whole, and thus expand the knowledge within the company. I thought it'd be equally important to share them with the rest of the world, even if some might be too basic for those knee-deep into JavaScript already.

Let's start with the first one!

JSBits #0

Javascript modules

In JavaScript, a module is a file exposing some code to other modules. JavaScript has had modules for a long time. However, they were implemented with libraries, and was part of the JavaScript specification a while back ago.

That situation has led to a certain proliferation of module formats. Most prominently: CommonJS, AMD, and ES6 modules. A variation of CommonJS is what Node.js uses, and the ES6 modules format is now part of the JS official specification.

CommonJS modules

This is, by far, the most popular module format since it's supported natively by Node.js. More exactly, Node.js implements a variation of CommonJS, which is the one I'll explain here.

Again: it's not part of the JS specification, but it's part of the Node.js implementation, and there are lot of tools to convert this format into something browsers understand.

Most of the Node.js npm packages, if not all, are published using this module format.

Basically, a module is a file with a module.exports declaration where you specify the public part of the module.

For example, a file called one.js:

function print (string) {
  console.log(string);
}

function sayHello (name) {
  print( `Hello ${name}`);
}

module.exports = { sayHello };

We are saying that the module "one" exports a function called sayHello. We can't use the print function outside module one (isolation works!), but we can import the public part of that module from another using the require keyword.

Given a file called "two.js" in the same directory:

const one = require('./one');

one.sayHello('MarsBased');

Notice that the path is relative to the current file and no .js extension is required, and that this second file and invoke the functions in the first one through require.

AMD modules

AMD was a module format designed to load asynchronous code. Nowadays, there are better solutions, so they are no longer used and therefore I won't explain them to keep this short and to-the-point.

ES6 modules

Conceptually, ES6 modules and CommonJS modules are very similar but have different syntax and some important differences (I will only scratch the surface of these differences. For further detail, check the links I recommend below.

The syntax: instead of a module.export declaration, we use the export keyword to designate the public code.

The one.js module can be written in ES6 syntax:

function print (string) {
  console.log(string);
}

export function sayHello (name) {
  print( `Hello ${name}`);
}

Similarly, instead of require we use the keywords import and from. But instead of importing the whole module, we specify what parts of the module you want to import.

The two.js module in ES syntax is:

import { sayHello } from './one'

sayHello('MarsBased');

However, there's a way to import all exported declarations from a module:

import * as one from './one';

one.sayHello('MarsBased');

Another difference is that in ES6 modules you can specify one (and only one) default export that is imported by default. This is a ES6 module only feature.

For example, we could write one.js like this:

function print (string) {
  console.log(string);
}

export default function sayHello (name) {
  print( `Hello ${name}`);
}

And we can import the default export like this:

import sayHello from './one';

sayHello('MarsBased');

The syntax is subtle but important: we are importing the default export, not the entry module. This does not work:

import one from './one';

one.sayHello('MarsBased');

So, what format I should use?

It depends a lot of the context. If you are a...

... a frontend developer

On the frontend side, the answer is clear: ES6 modules. Both CommonJS and ES6 modules are not supported (yet) by browsers, so you will need a tool to pack all the modules into one file that browser will understand.

There are a lot of tools for this purpose: browserify, babel, webpack, rollup and parcel are the most popular. Some of them (like rollup) just convert the ES6 modules into other module formats (or one big file, like browserify), and some others (like babel, webpack or parcel) are capable of performing a lot of transformations in between.

... a backend developer

If you work on the backend side, the easy path is to go with CommonJS modules, since they are natively supported. I don't recommend using CommonJS for the backend even if ES6 modules increase the complexity of the project.

In order to use ES6 modules in Node.js, you have two options:

... a npm module publisher

Things go crazy when you want to publish an npm package. The norm was to publish using CommonJS modules, but now it's recommended to publish in both formats: ES6 and CommonJS.

So you write the code using ES6 modules and, before publishing, you create a CommonJS version of the modules (babel, rollup or webpack again) and publish both.

... an electron developer

Electron uses both Node.js and browser technologies. I'd recommend to stick with ES6 modules and convert them.

Summary

ES6 modules have been the JS standard for a good couple of years. You should use ES6 when possible but, now, you will need a build step to convert those modules into something your system (browser, Node.js) understands.

Resources

Compartir este post

Artículos relacionados

JSBits #1: My favourite ES6 syntax

JSBits #1: My favourite ES6 syntax

Here's another JavaScript bits we wanted to share with you. Small tips and tricks for JavaScript developers for all levels.

Leer el artículo
JSBits #2: Return more than one value

JSBits #2: Return more than one value

Here's another JavaScript bits we wanted to share with you. Small tips and tricks for JavaScript developers for all levels. This time around, we share how to return more than one value.

Leer el artículo
JSBits #3: 10 things to remember

JSBits #3: 10 things to remember

Here's another JavaScript bits we wanted to share with you. 10 things to remember when coding.

Leer el artículo