Getting Started with JavaScript Modules
Tags: javascript, webdev, 100daysofcode
Published: 2021-09-26 13:24:35

Hey All 👋 , 

This is my second article on JavaScript ES6 Concepts. If you have not read the first one yet, you can read it [here](https://dev.to/thecoollearner/getting-started-with-javascript-classes-33e8). In this article I'm going to talk about all you need to get started with JavaScript Modules.

---

#### Table Of Contents -

* History
* What are modules, and why do we need them?
* Intro to CommonJS Modules
* ES6 Modules 
* Import and Export
* Some important features of ES6 Modules

---

## History

Earlier back in the days' applications used to be simpler and small, and thus their code. When the Javascript code was smaller, it was no big deal to keep them in a single file, but as applications improved and grew big, the code grew too, making it challenging to manage them and keep them in a single file.

Thus the concept of modules came into existence. There were a variety of ways invented to implement this concept. AMD and UMD, to name a few.

But these are now a part of history and are no longer used now generally, but you can find them in some of the older applications.

Another module system invented was **CommonJS**, which was created for the Node.js server. We'll talk about the CommonJS module system later in this article.

The language-level module system came in 2015 and is generally called **ES6 Modules**. Also, now it is supported by all major browsers and Node.js, so we'll talk more about ES6 modules in this article.

But first, let's talk about what modules are.

## What are modules, and why do we need them?

Modules are simply the building blocks of data using which we can build a large application.

The basic idea behind modules is that we can export a part of the code, and then we can import that into other files to be used.

Using modules, we can break a large script into smaller modules, which can also be used in other files.

Let's understand this with the help of a picture -

![JS Modules](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w00s0b8cvb43qkgna1mg.jpg)

You can see that all functions or code is in one file in the first picture, thus making it large. Now imagine having such 20-30 functions along with other code; how large will this file get. It'll make it hard to understand and manage such a large file.

Thus we split the code into **modules**, as shown in the second picture. We have written the functions in separate modules and exported them. Now they can be imported by the index.js and also by other modules. As we can see, Modules A, B, and C are imported by index.js; also, Module A is imported by Module B. And now, our code is easy to understand and manage as functions are in different modules, and our index.js is small.

**Note:** JS modules can export variables, functions, objects, etc.

Let's have a look at some of the benefits of JS Modules -

> **Maintainability:** 

As we talked about, if our code will be split and well organized, it'll be easy to maintain it. Also, a module is always aimed to be made independent as much as possible so that it can grow and improve independently. And we don't have to change much in our codebase if we make changes in our modules.

> **Reusability:** 

With the help of modules, we can reuse our code again and again. All we have to do is to export it from a file, and all other files across the project can import and use it.

> **Shareability:** 

As modules aim to be made independent so we can also share them with other developers, they can import them into their project and use them. One of the biggest examples of this is npm. With the help of npm, we can import packages( contains all the files you need for a module ) shared by other developers and use them in our project.

---

## Intro to CommonJS Modules

The CommonJS module system is the standard used in **Node.js** for working with modules. 

CommonJS modules are loaded synchronously and processed in the order the JavaScript runtime finds them.

This system was invented keeping server-side JavaScript in mind and is not suitable for the client-side.

Also, the npm ecosystem is based on the CommonJS module system.

Let's see a small example of how to import and export in CommonJS -

We can export any function, class, variable, etc. by simply using the **exports** keyword :

```javascript
// 📂 func.js
 
exports.add = (a, b) => a + b;
```

Then any Javascript file can import it. The syntax for importing :

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

Using this syntax, we can import the module by using the **require** keyword: 

```javascript
// 📂 main.js
 
const addModule = require('./func.js')
addModule.add(2,4)
```

Before talking about ES6 modules, let's have a look at the main differences between the CommonJS module system and ES6 modules -

1) CommonJS module system is used for server-side Javascript, while ES6 modules are used for client-side Javascript.

2) CommonJS module system uses the **exports** keyword for exporting and the **require** keyword for importing, while ES6 modules use the **export** keyword for exporting and the **import** keyword for importing.

---

## ES6 Modules 

We've already talked about what modules are, So let's now talk about ES6 modules.

ES6 modules use:

**export:**  to export function,classes, etc.
**import:** it allows the modules to import exported modules.

Let's see an example - 

Here we have three files: **index.html**, **func.js**, and **main.js**

```html
<!-- 📂 index.html -->
 
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>modules</title>
    <script type="module" src="./main.js"></script>
  </head>
  <body></body>
</html>
```

```javascript
// 📂 func.js
 
export const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};

```

```javascript
// 📂 main.js
 
import { sayHi } from "./func.js";
 
sayHi("Alok"); // Hi!!! Alok
```

You can see the **func.js** file is exporting a function ( using export keyword ) named **sayHi()**, which just console.log out **`Hi !!! ${user}`**.

While the **main.js** is importing the same **sayHi()** function( using import keyword ) from the **func.js** file. After that, we have run that function with the input "Alok" which console.log out **" Hi !!! Alok "**.

We can see that we have not defined the **sayHi()** function in our main.js file, but still, we can access and use it as now it is imported in our main.js file from the func.js file.

**Note:** To use modules, we have to specify that our script is a module by using the attribute **<script type="module">** as we have done in our index.html above :

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

---

## Import and Export

There are different ways to import and export ES6 modules. You can use them as per your need.

Let's talk about them one by one :

> **Export before declarations** - 

As we have seen in our previous example, all you have to do is place an **export** keyword before class, array, function, etc., whatever you want to export.

And then, you can import them by using the **import** keyword followed by a **list** of what you want to import in curly braces like **import {...}**.

Example -

```javascript
// 📂 func.js
 
//exporting a function
export const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
//exporting a variable
export let person = "Alok";
 
//exporting an array
export let personArray = ["Alok", "Aman", "Rajan"];
 
// All are valid
```

```javascript
// 📂 main.js
 
//importing using a list of what to import
import { sayHi,person,personArray } from "./func.js";
```

> **Export Separately** -

We can also use the **export** keyword separately and export using a **list of what to export**.

And then import them similarly as we have done before. 

Example -

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
let person = "Alok";
 
let personArray = ["Alok", "Aman", "Rajan"];
 
// exporting all using a list
export { sayHi, person, personArray };
```

```javascript
// 📂 main.js
 
//importing using a list of what to import
import { sayHi,person,personArray } from "./func.js";
```

> **Import \***

Till now, we have imported using a list of what to import, but if there's a lot to import, we can import everything as an object using -

import * as <obj>

Example -

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
let person = "Alok";
 
let personArray = ["Alok", "Aman"];
 
// exporting all using a list
export { sayHi, person, personArray };
```

```javascript
// 📂 main.js
 
//importing using import * as <obj>
import * as func from "./func.js";
 
//usage
func.sayHi("Alok");// Hi!!! Alok
console.log(func.person);// Alok
console.log(func.personArray);// ["Alok", "Aman”]
```

> **Import "as"** -

We can also import classes, variables, etc., using a different name. For example - we can import the person variable with another name ( user ) using the **as** keyword.

Example -

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
let person = "Alok";
 
let personArray = ["Alok", "Aman"];
 
// exporting all using a list
export { sayHi, person, personArray };
```

```javascript
// 📂 main.js
 
//importing using "as"
import { sayHi as Hi, person as user, personArray } from "./func.js";
 
//usage
Hi("Alok"); //Hi!!! Alok
console.log(user); //Alok
console.log(personArray); //["Alok", "Aman"]
```

> **Export "as"** -

Similarly, you can export with a different name using the **as** keyword.

Example -

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
let person = "Alok";
 
let personArray = ["Alok", "Aman"];
 
//exporting using "as"
export { sayHi as Hi, person as user, personArray };
```

```javascript
// 📂 main.js
 
//importing using a list
import { Hi, user, personArray } from "./func.js";
 
//usage
Hi("Alok"); //Hi!!! Alok
console.log(user); //Alok
console.log(personArray); //["Alok", "Aman"]
```

> **Export default** - 

We can make any export a default one by using the **default** keyword.

Generally, developers keep a single export in a module to keep the code clean, and in such a case, when we have a single export, we can use default export.

If we have a default export, then we can import it directly without using the curly braces **{ }**.

Example -

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
//exporting using default
export default sayHi;
```

```javascript
// 📂 main.js
 
//importing without { }
import sayHi from "./func.js";
 
sayHi("Alok"); // Hi!!! Alok
```

Notice while importing sayHi() we are directly using **sayHi**, not **{ sayHi }**.

**Note:** We can also mix default export with named export, but **a module can have only one default export** as shown :

```javascript
// 📂 func.js
 
const sayHi = (user) => {
  console.log(`Hi!!! ${user}`);
};
 
let person = "Alok";
 
let personArray = ["Alok", "Aman"];
 
//exporting using default
export default sayHi;
 
//exporting using list
export { person, personArray };
```

```javascript
// 📂 main.js
 
//importing without { }
import sayHi from "./func.js";
 
//importing using a list
import { person, personArray } from "./func.js";
 
//usage
sayHi("Alok"); //Hi!!! Alok
console.log(person); //Alok
console.log(personArray); //["Alok", "Aman"]
```

But as we talked about, developers generally keep only one export in a module and do not mix them to keep the code clean.

---

## Some important features of ES6 Modules

> **Always "use strict"**

Modules always use strict, by default.

Assigning to an undeclared variable will give an error.

Example -

```javascript
<script type="module">
  a = 5; {/* error */}
</script>
```
> **Module-level scope** 

A module can't access the top-level variables and functions of another module.

Example -

```javascript
<script type="module">
  {/* scope of person is only this module script */}
  let person = "Alok";
</script>
 
<script type="module">
   alert(person);{/* Error: person is not defined */}
</script>
```

> **A module code is executed only the first time imported**

If multiple modules are importing a module ( for example, func.js ), then only during the first time import it will be executed and given to all importers.

> **"this" is undefined**

In modules, top-level **this** is undefined. 

Example -

```javascript
<script>
  alert(this); {/* global object */}
</script>
 
<script type="module">
  alert(this); {/* undefined */}
</script>
```

---

**Note :** Thanks Seijinx for the info - "ES modules are not supported in IE11. You still need to rely on bundlers in that case." 

---

I have tried to keep it simple and precise, thanks for reading it till last, and if you find any typo/error please report it to me so that I can correct it 🙂

If you find this useful then you can share it with others :)

Feel free to drop a [Hi and let's chat 👋👋👋](https://twitter.com/thecoollearner)

---

Read other blogs in the series 

[👈Getting Started with JavaScript Classes](https://dev.to/thecoollearner/getting-started-with-javascript-classes-33e8)

&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;[Getting Started with JavaScript Promises 👉](https://dev.to/thecoollearner/getting-started-with-javascript-promises-e0)