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 few of the 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 was a game changer. We are able to take advantage of the modules functionality native way. In this post, I would like to introduce you to the JavaScript module concept and in-depth understanding of using the keywords export
and import
effectively. All the code snippet 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.
Modules can be used to keep the code footprint for a related area smaller, concise and as an independent unit. Using modules we can create reusable functionalities that automatically bring down the code quantity.
Less Code means Less Bugs, isn't it?
Basics of export and import
Modules can be loaded into each other by 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 as well. - import: As the name suggests, the
import
keyword used to import the features from other modules.
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 brainier what these functions do, 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 lets see the import part. We will be importing these function 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));
Note, 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 a 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>
Important to note that, we use the type called, module
in the script tag while loading the index.js
file. This is absolutely required. Specifying the type as module
causes the code to be treated as a JavaScript module.
💥 Two very important points to note here:
This way of exporting a module feature(functions, variables, classes etc) 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 above example if we importsum
assum1
, we will get 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 section of the post from this branch .
Export Together and the Aliases
In the above example we have seen, how to export the functions individually. We may have the 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 of the functions. We are just exporting them together in the last line. With this, we can just import
the functions as we have done before.
Aliases - While importing a function from a module, we can chose to 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 error:
You can find the source code used in this section of the post from this branch .
Importing as a Namespace
At times, we may have a need of importing a large number of functions from a module. It would be tedious and too much of 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
. Namespace is nothing but a name of our choice. Let us take a look into 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 are exported from, calc.js
module. More important fact to point here is, we are 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 section of the post 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 in above code. A default exported function can be imported 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 that is exported with 'default', it is not mandatory to use the same name. Here is an example of how the
sayMyName
function can be imported,import { default as name } from './whoami.js';
or
import name from './whoami.js';
You can find the source code used in this section of the post 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 fromcalc.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 called,whoami.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, we just need to import only one file to get access to 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 section of the post from this branch .
Wrapping Up
Native support of modules
in JavaScript is an extremely useful feature. We should be using more of export
and import
in vanilla JS as we do 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
. There is another import mechanism called, dynamic import
which I am going to 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 more in-depth understanding of modules:
That's all for now. Hope it was useful to you and please like and share. 🍻🍻🍻
Comments (1)