JavaScript Modules and how to effectively work with Export Import
Introduction
No one would like to work with the code having one gigantic JavaScript file with many unrelated functions. Moreover, when you need to use a few functions from that file, you end up loading all the others unnecessarily. AMD was a great way of achieving modularization in JavaScript. Node.js already supports the module system using CommonJS.
Javascript(ES6)'s inclusion of modules is a game-changer. We can take advantage of the module's functionality natively way. In this post, I introduce you to the JavaScript module concept and in-depth understanding of using the keywords export
and import
effectively. All the code snippets used in this post are in my gitHub repo.
- JavaScript Modules
- Basics of export and import
- Export Together and the Aliases
- Importing as a Namespace
- Default export and When not to use it
- Combine exports
- Wrapping Up
JavaScript Modules
Most simple way putting,
In JavaScript, one script is one module. A module is nothing but a JavaScript file.
We can use modules to keep the related area's code footprint smaller, concise, and independent. Using modules, we can create reusable functionalities that automatically bring down the code quantity.
Less Code means Less Bugs.
Basics of export and import
We can load modules into each other using the keywords export
and import
.
- export: Using the
export
keyword, we make the module features available to other modules. These features are usually the functions. However, it is not limited to it. We will be able to export variables, objects, classes, etc., from a module. - import: As the name suggests, the
import
keyword is used to import other modules' features.
Let us understand these with a simple example. Let us assume we have a JavaScript file(a module) called calc.js
. It exports two feature functions called sum
and sub
. It is no brainer what these functions do, and they do summation and subtraction, respectively.
// calc.js
export const sum = (a, b) => {
return a + b;
};
export const sub = (a,b) => {
return a - b;
};
As you noticed, the export
keyword is in front of each of the functions. The module exports these two functions so that other modules can import and make use of it. Now let's see the import part. We will be importing these functions to another module called index.js
.
// index.js
import { sum, sub } from './calc.js';
console.log('The Sum is', sum(2,3));
console.log('The Sub is', sub(5,3));
We first import both the functions with their names(sum and sub) from the module(JavaScript file), calc.js
.
Finally, we will be importing(or loading) the index.js
file to an HTML file, say, index.html
<html>
<head>
<title>js-modules</title>
</head>
<body>
<script type="module" src="./src/index.js"></script>
<h1>
See the Debugger Console...
</h1>
</body>
</html>
It is important to note that we use the type called module
in the script tag while loading the index.js
file. It is required. Specifying the type as module
causes the code to be treated as a JavaScript module.
💥 Two essential points to note here:
This way of exporting a module feature(functions, variables, classes, etc.) is called
Named Export
. With Named Export, import needs curly braces. Named Export also forces upon the fact, the import must use the same exported name of the function, variable, etc. For the above example, if we importsum
assum1
, we will get the following error:While importing the functions, the related module name in the import statement must have the
.js
extension.import { sum, sub } from './calc.js';
If you are familiar with modules from
node.js
or withreactjs
, you can import the same as,import { sum, sub } from './calc';
With Vanilla JavaScript, you will be getting this error, and we hope it gets supported sooner.
You can find the source code used in this post section from this branch.
Export Together and the Aliases
In the above example, we have seen how to export the functions individually. We may have situations where we need to export multiple things from a module. We can do all of them together.
const sum = (a, b) => {
return a + b;
};
const sub = (a,b) => {
return a - b;
};
export { sum, sub };
As we see in the code above, we are not using the export
keyword for each function. We are just exporting them together in the last line. With this, we can import
the functions as we have done before.
Aliases - While importing a function from a module, we can use an alias name instead. Consider the following example where we have used the alias
called add
for the imported function sum
.
import { sum as add, sub } from './calc.js';
console.log('The Sum is', add(2,3));
console.log('The Sub is', sub(5,3));
💥 Point to note here, once the alias
is used, you can not use the old name to call the module features like function, variable, etc. It is going to throw an error:
You can find the source code used in this post section from this branch.
Importing as a Namespace
At times, we may need to import a large number of functions from a module. It would be tedious and too much code to import them as comma-separated as we have seen so far. We can short-hand this by importing them together with a Namespace
. A namespace is nothing but a name of our choice. Let us take a look at this example:
import * as Calc from './calc.js';
console.log('The Sum is', Calc.sum(2,3));
console.log('The Sub is', Calc.sub(5,3));
As we see here, we are importing *
, which means all that is exported from, calc.js
module. A more important fact to point here is importing the features by a name(Namespace
) called Calc
. As we did that, we can access the function using that Namespace
.
You can find the source code used in this post section from this branch.
Default export and When not to use it
JavaScript modules provide a special keyword called default
with export to specify only one thing to export from a file. However, technically, we can export both Named Export
and Default Export
from a single file but, we shouldn't mix them. Use either Named or Default export.
// whoami.js
const sayMyName = () => {
return 'Tapas';
};
export default sayMyName;
As we see, the default
keyword with export is in the above code. We can import a default exported function in two ways.
- Using
default as
syntaximport { default as sayMyName } from './whoami.js';
- Without the curly braces ({ })
import sayMyName from './whoami.js';
💥 Few points to consider,
- Try not to mix the default export and named export together. Use default export when only one thing to export.
While importing a feature exported with 'default', it is not mandatory to use the same name. Here is an example of how we can import the
sayMyName
function,import { default as name } from './whoami.js';
or
import name from './whoami.js';
You can find the source code used in this post section from this branch.
Combine exports
We can combine the multiple exports from various modules and do a combined export from a single file. This is also called re-export or
aggregating`. Let us understand this with an example,
We first export
sum
andsub
as before from thecalc.js
module. Here we have opted for named export.// calc.js const sum = (a, b) => { return a + b; }; const sub = (a,b) => { return a - b; }; export { sum, sub };
Then, we export a function called
sayMyName
from another module calledwhoami.js
. This time, we have used default export.// whoami.js const sayMyName = () => { return 'Tapas'; }; export default sayMyName;
Now, we can combine the exports from both the modules into one module and export from there. Let us name the new module called
combine.js
.// combine.js export * as Calc from './calc.js'; export name from './whoami.js';
It is important to note the syntax here. It is almost like import, but we are actually re-exporting them. The advantage here is that we need to import only one file to access all these functions. Let us see, how are we going to do that,
Import the functions
import * as Combine from './combine.js'; console.log('The Sum is', Combine.Calc.sum(2,3)); console.log('The Sub is', Combine.Calc.sub(5,3)); console.log('The name is', Combine.name());
You can find the source code used in this post section from this branch.
Wrapping Up
Native support of modules
in JavaScript is a handy feature. We should be using more of export
and import
in vanilla JS than with Node.js
or any other library/frameworks like angular
, react
etc. Point to note here, the import mechanisms we got to see here are called static import
. Another import mechanism is called dynamic import
, which I will cover in my next post.
With ES6, JavaScript modules are supported by most of the browsers on desktop and mobile devices.
Here is one online resource I would recommend for a more in-depth understanding of modules:
That's all for now. I hope it was useful to you, and please like and share. 🍻🍻🍻