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. 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 -
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 :
// π func.js
exports.add = (a, b) => a + b;
Then any Javascript file can import it. The syntax for importing :
const package = require('module-name')
Using this syntax, we can import the module by using the require keyword:
// π 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
<!-- π index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>modules</title>
<script type="module" src="./main.js"></script>
</head>
<body></body>
</html>
// π func.js
export const sayHi = (user) => {
console.log(`Hi!!! ${user}`);
};
// π 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 as we have done in our index.html above :
<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 -
// π 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
// π 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 -
// π 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 };
// π 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
Example -
// π 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 };
// π 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 -
// π 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 };
// π 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 -
// π 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 };
// π 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 -
// π func.js
const sayHi = (user) => {
console.log(`Hi!!! ${user}`);
};
//exporting using default
export default sayHi;
// π 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 :
// π 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 };
// π 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 -
<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 -
<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 -
<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 πππ
Read other blogs in the series
πGetting Started with JavaScript Classes
βββββββββββββGetting Started with JavaScript Promises π
Top comments (31)
Yes, really a great article. I appreciate your fully detailed explanation with excellent examples. I found here what I wanted to know. Really I appreciate it.
Thanks Rishikesh, I'm glad it was useful :)
Next is on JS Promises, and I'm also planning to compile all these ES6 concepts articles into an e-book, stay tuned π
Ok great, thanks!π
Thanks @thecoollearner for the clear and concise post.
Thanks Douglas :)
You can read the other articles in this series, I'm sure you'll like them too π
This helped solidify a concept that is new to me.
Thanks Kevin, I'm glad it was helpful :)
Thank you Alok for such a good blog. I used module in React but did not have understanding about it. Now I think I can use it in simple js files also.
Thanks for reading Ramesh, glad you liked it :)
Next blog is on JS Promises, stay tuned π
Thank you Alok. This really helped me understand this concept better. I use it often but have often wondered why sometimes I use {} in my imports and sometimes not. It all makes sense now!
Thanks candersson1 for reading :)
glad it helped, stay tuned for more such articles π
Great! Thank you.
Thanks for reading, Timothy :)
Nice article! Easy to understand with examples. :bd
Thanks Erikson :)
I'll sure come up with more such articles, stay tuned π
Module explained in a simplified manner !! Good .
Thanks Raman :)
awesome bro
Thanks silvesterwali :)
Great article!! Very useful.
It might be useful to add that, sadly (again!) ES modules are not supported in IE11. You still need to rely on bundlers in that case.
Thanks Seijinx π
I've added it as a note at last of the article :)