# Introduction to JavaScript Modules


Originally, Javascript was used as a tool to create beautiful animations and interactions on the web, they were there to make websites look attractive and eye catchy, and that was all. But then, Google Maps was introduced, and that period represented when innovations and technologies were built using Javascript.

It was a whole new era with its quirks and downsides. Initially, javascript code didn’t exceed two to four lines, but as the complexity of websites and apps increased, the amount of javascript code shipped to the browser skyrocketed. As a result, we now have millions of javascript code running in the browser, thanks to the frameworks and libraries we use for development.

Managing and maintaining that much code requires a much more efficient and productive method, hence the creation of **Javascript Modules**.

  
In this article, I’ll explain how we can utilize the power of javascript modules in our project and why it’s a good pattern when developing javascript applications.

## **Prerequisites**

1. [Node](https://nodejs.org/) installed on your local machine
    
2. [yarn](https://yarnpkg.com/) or [npm](https://www.npmjs.com/) installed on your local machine (npm comes pre-installed with node)
    
3. A text editor installed, e.g., VsCode.
    
4. Basic knowledge of HTML, CSS, Javascript, and the terminal (Check out this [article](https://youtu.be/kMT54MPz9oE) for a refresher on them)
    

## **What is a Module?**

A module is a self-contained javascript file containing variables, functions, or classes that can be available to other files across your project. Making a function or class available to other modules is called **export**. In contrast, using a function or class from another module is called **import.** Javascript Modules allow us to utilize this system of modules within our project, thereby enabling us to enjoy benefits like:

* Code maintainability
    
* Ease of code reusability
    
* Code scalability
    

Javascript Modules allow us to break down and split our code into multiple and self-contained chunks that can be easily well-maintained and scalable should there be any need for any addition in the future. This feature has been available in NodeJS and in popular frameworks and libraries within the Javascript ecosystem for a while now. However, it’s only recently that this feature became available natively within the browser.

Looking at the Browser Compatibility Specs on [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#a_background_on_modules), it’s now supported in most popular browsers used by everyone.

![](https://lh5.googleusercontent.com/vwl2Jr3fws_LS4J4naQl0XnBOmegZbq6q6TI7aokhzu39X1GHtIVe3c8Uy5zpUZCEjzWKUJOHcjgnn7OPeeNUHM6KHMKy7olvpSmDoPB5pl2gn4KqcCYIrfmtVyrogQXs921ue0CyJZFdhZvA5gjgyA align="left")

![](https://lh4.googleusercontent.com/Ic0NM29Y-HNnqAo2X2GEh0VPERruzyLSqVixU14t4BJxdzdYKw64Rg9QqWev_r_UigChd6fLdU83ai4G7cCPpJkZV2k5aoP1lReZ2C4PnlGMIxNo1OPN8XLVlX666EcaHMwq_8lOqMk9_oeXGMP9_sM align="left")

## **Using Modules in a Project**

To get started with modules in a project, your script tag in the HTML file needs to have the `type` attribute included, like the snippet below:

![](https://lh5.googleusercontent.com/DILLJRnPBaw_382EUddJBJ4I4iJa6LR6eLF8Dim-mQiQPp9MISkmxwiZ4lwW-0KU01f-3YJrTTi4YRXTCPLK8XccNgfOMJr_OfNtt5LfS2qOshcwXCvKg67Bv2LUGjzm-UqEtBAzdrGTq40iT8jb9vI align="left")

Open your terminal and paste in the command below to create a new folder, navigate into it and create an HTML file named `index.html`:

```
mkdir js-modules
cd js-modules
touch index.html
```

Open the folder in VsCode using the command below:

```
code .
```

Our project should look like this now:

![](https://lh3.googleusercontent.com/PSHIAfNeHnttbDll4z-EUlQcVdvmGvCnoP08LynbPG8Qc1pbqzwnayIfc26ptRsEJD13FRCxJ8G1LOiHCZFTSJcVUWLrZrxEFgNg0lRLJo4PF35tI1Q5qZnmytwzd2jeq3j6BTPfPMxngs9T0AZbIAA align="left")

Paste the starter code below in our `index.html` file and create a javascript file called `app.js`:

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>Hello World</h1>
  <script type="module" src="app.js"></script>
</body>
</html>
```

If you observe, the script tag in our HTML file has the `type` attribute with a value of `module`. This is because the `app.js` file we just created would be a module.

Also, when using javascript files that are modules, we need to serve our HTML file using a server cause opening the file directly would throw a [CORS error](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors) in the browser console due to our browser not identifying where the file is being served from. Not doing this would result in the error below:

![](https://lh4.googleusercontent.com/oDcrlZfM1jyotqjHGpgd2bNeI4JSgh8UjMBBsUNrnGNr2CLcM4ujgxIxOrt8XfQtx6YBMvZ79w-krVrx4KRsUVJoWZl2zq1G7iHIRkfQUd-LZKsraMWZ4C42Zxn4poEeF6I-Pn24-yGAR5rNxL2jprw align="left")

We'll use Live Server in this tutorial. See [this video](https://www.youtube.com/watch?v=2fhe0LLj3Rw) on how to install it in VsCode.

Now, create another javascript file named utils.js and paste in the following snippets below:

```
const users = [
  {
    firstName: "John",
    lastName: "Doe",
  },
  {
    firstName: "Evan",
    lastName: "Blacwk",
  },
  {
    firstName: "Julian",
    lastName: "Drey",
  },
];

/**
 * function to get all even numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of even numbers
 */
function getEvenNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 === 0);
}

/**
 * function to get all odd numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of odd numbers
 */
function getOddNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 !== 0);
}

/**
 * function to get all numbers greater than 5 in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]}
 */
function getNumbersLargerThanFive(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num > 5);
}

/**
 * function to combine firstName and  lastName into a fullname
 *
 * @param {string} firstName
 * @param {string} lastName
 * @return {string} FullName
 */
function combineNames(firstName, lastName) {
  return `${firstName} ${lastName}`;
}
```


## **Using the export and import keyword**

There are two main ways the **export/import** keyword can be used in a script, they are:

* Using as a Named Export/Import
    
* Using as a Default Export/Import
    

**Named Exports**

Let’s update the code snippet we pasted in our utils.js file by appending the export keyword before each function. Our code should look like this now:

```
export const users = [
  {
    firstName: "John",
    lastName: "Doe",
  },
  {
    firstName: "Evan",
    lastName: "Blacwk",
  },
  {
    firstName: "Julian",
    lastName: "Drey",
  },
];

export function getEvenNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 === 0);
}
export function getOddNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 !== 0);
}
export function getNumbersLargerThanFive(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num > 5);
}

export function combineNames(firstName, lastName) {
  return `${firstName} ${lastName}`;
}
```

The **export** keyword makes whichever variable, function, or class it’s appended to available to all other scripts in our project. If we have so many functions we want to export, adding the export keyword on each of them might be a task on its own, so there’s a much cleaner approach which is having a single export object at the end of the file as we have below:

```
const users = [
  {
    firstName: "John",
    lastName: "Doe",
  },
  {
    firstName: "Evan",
    lastName: "Blacwk",
  },
  {
    firstName: "Julian",
    lastName: "Drey",
  },
];

/**
 * function to get all even numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of even numbers
 */
function getEvenNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 === 0);
}

/**
 * function to get all odd numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of odd numbers
 */
function getOddNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 !== 0);
}

/**
 * function to get all numbers greater than 5 in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]}
 */
function getNumbersLargerThanFive(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num > 5);
}

/**
 * function to combine firstName and  lastName into a fullname
 *
 * @param {string} firstName
 * @param {string} lastName
 * @return {string} FullName
 */
function combineNames(firstName, lastName) {
  return `${firstName} ${lastName}`;
}

export {
  users,
  getEvenNumbers,
  getOddNumbers,
  getNumbersLargerThanFive,
  combineNames,
};
```


Having done this, we can now import any of these functions in `app.js` and make use of it below:

```
import {
  getEvenNumbers,
  getOddNumbers,
  getNumbersLargerThanFive,
  users,
  combineNames,
} from "./utils.js";

console.log(getEvenNumbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [2, 4, 6, 8, 10]
console.log(getOddNumbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [1, 3, 5, 7, 9]
console.log(getNumbersLargerThanFive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [6, 7, 8, 9, 10]
console.log(users.map((user) => combineNames(user.firstName, user.lastName))); // Prints ['John Doe', 'Evan Blacwk', 'Julian Drey']
```

We should get the output below in our console when we open our `index.html` file in the browser:

![](https://lh4.googleusercontent.com/v6lVX_5EbdxXzYbu-nifOUvMrcbPaiMaRJsztbf4J0ATSOl7EJljZHKb641VpkEgcY7VjoFAv1Y7pkyLZYNjs_9WWCnuy96ubbLt-v1Ngh2oRaFlHiVhfQeGLFdSDrYR6d4rrAFSxJt1oaE5Iscrhfg align="left")

  
**NB:** Since the curly braces for the `export/import` looks like an object, we have the option of being able to rename a variable or function in an `export/import` statement using the `as` keyword like this:

```
// For export
export {
  users as userList,
  getEvenNumbers as extractNumbersDivisibleByTwo,
  getOddNumbers as extractOddNumbers,
  getNumbersLargerThanFive,
  combineNames,
};
// For import
import {
  extractNumbersDivisibleByTwo as evenNumbersFunc,
  getOddNumbers as oddNumbersFunc,
  getNumbersLargerThanFive,
  usersList,
  combineNames,
} from "./utils.js";
```

One other advantage of named import is the fact that we can import everything exported from the `utils.js` file into a module object which we can then be accessed using the dot notation like this:

```
import * as utils from './utils.js';

console.log(utils.getEvenNumbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [2, 4, 6, 8, 10]
console.log(utils.getOddNumbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [1, 3, 5, 7, 9]
console.log(utils.getNumbersLargerThanFive([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // Prints [6, 7, 8, 9, 10]
```

This is very useful for situations where our `utils.js` file might be used in multiple files. That way, the variables or functions can be named according to the file where it’s being used.

**Default Exports**

In a situation where we would like to have a default variable or function exported, we can include `default` alongside the `export` keyword prefixing the variable or function to be exported. Also, there can only be one default statement in a module. For example, let’s export our `users` array as a default export below:

```
const users = [
  {
    firstName: "John",
    lastName: "Doe",
  },
  {
    firstName: "Evan",
    lastName: "Blacwk",
  },
  {
    firstName: "Julian",
    lastName: "Drey",
  },
];

/**
 * function to get all even numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of even numbers
 */
function getEvenNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 === 0);
}

/**
 * function to get all odd numbers in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]} Array of odd numbers
 */
function getOddNumbers(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num % 2 !== 0);
}

/**
 * function to get all numbers greater than 5 in an array of numbers
 *
 * @param {number[]} nums
 * @return {number[]}
 */
function getNumbersLargerThanFive(nums) {
  if (nums.length === 0) return;
  return nums.filter((num) => num > 5);
}

/**
 * function to combine firstName and  lastName into a fullname
 *
 * @param {string} firstName
 * @param {string} lastName
 * @return {string} FullName
 */
function combineNames(firstName, lastName) {
  return `${firstName} ${lastName}`;
}

export {
  getEvenNumbers,
  getOddNumbers,
  getNumbersLargerThanFive,
  combineNames,
};

export default users;
```


In our `app.js` file, we can import the `users` variable individually without having the curly braces as we had from the earlier examples. This is because our `users` array is the default variable exported from `utils.js`.

```
import {
  getEvenNumbers,
  getOddNumbers,
  getNumbersLargerThanFive,
  combineNames,
} from "./utils.js";
import users from './utils.js';

// The rest of the code
...
```

Or we could have it like this:

```
import users, {
  getEvenNumbers,
  getOddNumbers,
  getNumbersLargerThanFive,
  combineNames,
} from "./utils.js";
```

## **Conclusion**

This article introduced you to Javascript Modules and how to utilize them in your project. I hope you’ve found it helpful. 

If you have any questions or suggestions for me, feel free to drop a comment below. And if you are looking for additional resources, I’d recommend these ones:

* [Javascript Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), MDN Docs
    
* [Modules Introduction](https://javascript.info/modules-intro), Javascript Info
    
* [ES6 In Depth: Modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/), Mozilla Hacks


