Things I wish I’d known sooner about… JavaScript modules
Tags: javascript, programming, modules, thingsiwishiknew
Published: 2022-05-22 21:00:46

---
title: Things I wish I’d known sooner about… JavaScript modules
published: true
date: 2021-11-10 22:57:58 UTC
tags: javascript,programming,modules,thingsiwishiknew
canonical_url: https://www.solarwinter.net/things-i-wish-i-knew-about-javascript-part-2/
---

 ![Things I wish I knew about… JavaScript modules](https://www.solarwinter.net/content/images/2021/10/things-javascript-modules-.png)

I have to confess it took me a while to get my head around JavaScript modules. This is at least partly because there are two different popular module systems, [CommonJS](http://www.commonjs.org/) and [ECMAScript 2015](https://en.wikipedia.org/wiki/ECMAScript) (usually shortened to ES2015).

The ECMAScript 2015 standard is newer than CommonJS. Personally I find it more straightforward, and I use it in preference where I can. Quite a lot of the modules on [NPM](https://www.npmjs.com/) still use the old style, however.

One important note - browsers only support ES2015, not CommonJS.

## CommonJS

CommonJS was started in 2009 by a member of the [Mozilla](https://www.mozilla.org/) team, as an attempt to unify JavaScript functionality. [CommonJS](http://www.commonjs.org/) covers more than just modules - check the website.

### Exports

In CommonJS modules, symbols are exported in an object (understandably named `exports`). Each property of the object is an exported symbol.

The usual object assignment rules apply. This means you can easily export a symbol with a different name than it has internal to the file.

```
function sayHello(name) {
  console.log("Hello", name);
}

module.exports = {
  sayHello,
  anotherSayHello: sayHello
};

```

### Require

You can then `require` either the whole module or some symbols from that module.

```
const testModule = require("./module_name");
const { sayHello } = require("./module_name");

testModule.sayHello("world");
sayHello("second world");
```

**NB** : importing named symbols from a CJS-style module was only introduced in Node 14, and doesn't work perfectly - it relies on some heuristics within Node.

## ES2015

### Export

Exporting is easier in ES2015; an item (function, constant, variable etc) can be exported simply by adding the `export` keyword.

```
export function sayHello(name) {
  console.log("Hello", name);
}

export const myName = "Rumpelstiltskin";
```

Alternatively, you can export the items en-masse at the end of the file.

```
export { sayHello, myName };

```

### Import

Like many other languages - Java, Python - you then import the parts of the module that you want to use.

```
import { sayHello } from "./moduleName";

sayHello("world");
```

Or if you want to keep them namespaced:

```
import * as moduleStuff from "./moduleName";

moduleStuff.sayHello(moduleStuff.myName);
```

##   
Default exports

In most of the examples above, we've imported a specific named symbol from module:

```
import { sayHello } from "./module_name";
```

A module can also have a default export, which is what you then get if you don't specify what you want to import from the module.

### CommonJS

CJS modules actually only export one single item - in that sense, they only have a default export. It's why the items we want to export need to be properties of an object.

### ES2015

With this system you do get more flexibility. More than one thing can be exported, and you're able to mark which one you want to be the default.

```
export default const theAnswer = 42;
```

### User beware

This isn't always a good thing; you're never totally sure what you're importing, and it can be imported with a completely different (and misleading) name to the original.

For example, take the trivial module `basicMaths`:

```
export default sum(x, y) { return x + y; }
```

That default export can be imported as anything.

```
import divide from "./basicMaths";

// This will not do what you expect.
divide(2, 4);
```

The advantage of named exports is that you import exactly what you want, no surprises.

```
import { divide } from "./basicMaths";

// divide is empty, so this crashes (or doesn't build, depending on how
// good your tools are). Either way it's better than using the wrong 
// function.
divide(2, 4);
```

## Other reading

- The Mozilla Developer Network has a [page covering "native JavaScript modules"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) in more depth, with a tutorial.
- Simon Plenderleith [has a good in-depth look](https://simonplend.com/node-js-now-supports-named-imports-from-commonjs-modules-but-what-does-that-mean/) at Node's support for CommonJS-style modules.

Credits

- Image: [Laura C-F](https://www.deviantart.com/laura-c-f/)

[https://www.deviantart.com/laura-c-f/art/Confused-Dog-286725830](https://www.deviantart.com/laura-c-f/art/Confused-Dog-286725830)