> For the complete documentation index, see [llms.txt](https://founders-and-coders.gitbook.io/coursebook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://founders-and-coders.gitbook.io/coursebook/src/workshops/es-modules/index.md).

# index

ES Modules are a way to isolate your JS files. This is similar to Node's `require` syntax, but build-in to the JS language (rather than a proprietary Node feature).

[Modern browsers](https://caniuse.com/#search=modules) support modules loaded from a script tag with `type="module"`. This tells the browser that this JS code may load additional code from other files.

```markup
<script type="module">
  import { add } from "./maths.js";

  add(1, 2);
</script>
```

Generally (for wider browser support) apps use a tool called a "bundler" to parse all the imports and "bundle" them into a single file that older browsers will understand. For ease of learning we won't be using a bundler yet.

## Module scope

Modules help with JavaScript's global variable problem: usually variables defined in one file are able to be accessed (and changed) in any other. This can be confusing and dangerous, since you can't tell where things are defined/changed.

With modules variables defined in separate files are **not** accessible in another. This means you can have 100 variables named `x`, as long as they're all in different files.

The only way to use a value from another module is to explicitly export it from one file, then import it where you want to use it.

## Exports

Files can have two types of exports: "default" and "named". A file can only have **one** default export, but can have **many** named exports. This is conceptually similar to the difference between `module.exports = myFunction` and `module.exports = { myFunction, otherFunction }` in Node.

This is how you create a default export:

```javascript
const a = 1;
export default a;
```

And this is how you create a named export:

```javascript
const a = 1;
export { a };
```

You can only default export a single thing, but you can have as many named exports as you like:

```javascript
const a = 1;
const b = 2;
export { a, b };
```

You don't have to export things at the end of the file. You can do it inline:

```javascript
export const a = 1;
export const b = 2;
```

## Imports

There are also two kinds of imports: default and named. The way you import a value must match the way you exported it. A default-exported variable must be default-imported (and vice versa).

This is how you import something that was default-exported:

```javascript
// maths.js
const a = 1;
export default a;
```

```javascript
// index.js
import a from "./maths.js";
console.log(a); // 1;
```

Named-exports must be imported with curly brackets:

```javascript
// maths.js
export const a = 1;
export const b = 2;
```

```javascript
// index.js
import { a } from "./maths.js";
console.log(a); // 1;
```

You can import as many named-exports as you like on the same line:

```javascript
import { a, b } from "./maths.js";
console.log(a, b); // 1 2
```

Import paths must be valid URIs. They can be local to your machine (`"./maths.js"`) or on the web (`"https://cdn.pika.dev/lower-case@^2.0.1"`). This means you **must include the file extension** for local files. Node lets you ignore this, but it is mandatory in the browser.

## Challenge

To get started download the starter files, `cd` into the directory, then run `npx servor workshop` to start a dev server. ES Modules require a server to work, so you can't just open the `index.html` file directly.

1. Split up the JS code in `workshop/index.js` into 3 files:
   * `math.js` containing the operator functions
   * `calculate.js` containing the `calculate` function
   * `index.js` containing the DOM event handlers
2. Change each file so they export and import everything they need to
3. Don't forget browsers only support imports inside a script tag with `type="module"`
