JavaScript Modules and how to effectively work with Export Import

JavaScript Modules and how to effectively work with Export Import

ยท

8 min read

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

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.

modules.png

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 import sum as sum1, we will get the following error:

    error_1.png

  • 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 with reactjs, 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.

    error_2.png

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:

error_3.png

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 syntax
    import { 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 oraggregating`. Let us understand this with an example,

  • We first export sum and sub as before from the calc.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 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.

import_export.png

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. ๐Ÿป๐Ÿป๐Ÿป

Did you find this article valuable?

Support Tapas Adhikary by becoming a sponsor. Any amount is appreciated!