Introduction to ES Modules
Tags: javascript
Published: 2018-06-15 08:07:19

---
title: Introduction to ES Modules
published: true
tags: javascript
canonical_url: https://flaviocopes.com/es-modules/
---

![ES Modules](https://flaviocopes.com/es-modules/banner.jpg)

<!-- TOC -->
- Introduction to ES Modules
- The ES Modules Syntax
- Other import/export options
- CORS
- What about browsers that do not support modules?
- Conclusion
<!-- /TOC -->
## Introduction to ES Modules

ES Modules is the ECMAScript standard for working with modules.

While [Node.js](https://dev.to/flaviocopes/introduction-to-nodejs-3can) has been using the CommonJS standard since years, the browser never had a module system, as every major decision such as a module system must be first standardized by ECMAScript and then implemented by the browser.

This standardization process completed with [ES6](https://dev.to/flaviocopes/the-complete-ecmascript-2015-2017-guide-14n8-temp-slug-2553173) and browsers started implementing this standard trying to keep everything well aligned, working all in the same way, and now ES Modules are supported in Chrome, Safari, Edge and Firefox (since version 60).

Modules are very cool, because they let you encapsulate all sorts of functionality, and expose this functionality to other JavaScript files, as libraries.

![ES Modules Support](https://flaviocopes.com/es-modules/browser-support.png)

## The ES Modules Syntax

The syntax to import a module is:

```
import package from 'module-name'

```

while CommonJS uses

```
const package = require('module-name')

```

A module is a JavaScript file that **exports** one or more value (objects, functions or variables), using the `export` keyword. For example, this module exports a function that returns a string uppercase:

> uppercase.js

```
export default (str) => str.toUpperCase()

```

In this example, the module defines a single, **default export** , so it can be an anonymous function. Otherwise it would need a name to distinguish it from other exports.

Now, **any other JavaScript module** can import the functionality offered by uppercase.js by importing it.

An HTML page can add a module by using a `<script>` tag with the special `type="module"` attribute:

```
<script type="module" src="index.js"></script>

```

> Note: this module import behaves like a `defer` script load. See [efficiently load JavaScript with defer and async](https://dev.to/flaviocopes/efficiently-load-javascript-with-defer-and-async-agm-temp-slug-9543671)

It’s important to note that any script loaded with `type="module"` is loaded in [strict mode](https://dev.to/flaviocopes/javascript-strict-mode-5b1g-temp-slug-822367).

In this example, the `uppercase.js` module defines a **default export** , so when we import it, we can assign it a name we prefer:

```
import toUpperCase from './uppercase.js'

```

and we can use it:

```
toUpperCase('test') //'TEST'

```

You can also use an absolute path for the module import, to reference modules defined on another domain:

```
import toUpperCase from 'https://flavio-es-modules-example.glitch.me/uppercase.js'

```

This is also valid import syntax:

```
import {foo} from '/uppercase.js';
import {foo} from '../uppercase.js';

```

This is not:

```
import {foo} from 'uppercase.js';
import {foo} from 'utils/uppercase.js';

```

It’s either absolute, or has a `./` or `/` before the name.

## Other import/export options

We saw this example above:

```
export default (str) => str.toUpperCase()

```

This creates one default export. In a file however you can export more than one thing, by using this syntax:

```
const a = 1
const b = 2
const c = 3

export { a, b, c }

```

Another module can import all those exports using

```
import * from 'module'

```

You can import just a few of those exports, using the [destructuring assignment](https://flaviocopes.com/ecmascript/#destructuring-assignments):

```
import { a } from 'module'
import { a, b } from 'module'

```

You can rename any import, for convenience, using `as`:

```
import { a, b as two } from 'module'

```

You can import the default export, and any non-default export by name, like in this common React import:

```
import React, { Component } from "react"

```

You can check an ES Modules example on [https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html](https://glitch.com/edit/#!/flavio-es-modules-example?path=index.html)

## CORS

Modules are fetched using [CORS](https://dev.to/flaviocopes/a-quick-guide-to-cors-18im-temp-slug-4845164). This means that if you reference scripts from other domains, they must have a valid CORS header that allows cross-site loading (like `Access-Control-Allow-Origin: *`)

## What about browsers that do not support modules?

Use a combination of `type="module"` and `nomodule`:

```
<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

```

## Conclusion

ES Modules are one of the biggest features introduced in modern browsers. They are part of ES6 but the road to implement them has been long.

We can now use them! But we must also remember that having more than a few modules is going to have a performance hit on our pages, as it’s one more step that the browser must perform at runtime.

[Webpack](https://dev.to/flaviocopes/introduction-to-webpack-1j40-temp-slug-3449549) is probably going to still be a huge player even if ES Modules land in the browser, but having such a feature directly built in the language is huge for a unification of how modules work in the client-side and on Node.js as well.