JavaScript Modules
Tags: webdev, beginners, javascript, codenewbie
Published: 2021-04-01 13:42:08

A module is a simple JavaScript file. As the application become bigger the code become complex and it might contain thousands of line, so maintaining the code become difficult. Modules helps in dividing the codes into multiple block of codes, which help to separate functionality into multiple files. Modules help to maintained code and help in code reusability. A module may contain a class, a functions or code that perform a specific task. Modules can communicate between each other like they are in one file if we wish to be like that. We can also specify what code should be visible to the outside. Module gives us more control to our code.  

Modules use *export* keyword to label variables or functionality that should be made available to the outside world. *Import* keywords are used to import variables or functionality to a module from other modules. 

Example
```javascript
Filename: Greet.js
export function greet(user){
    console.log(`Hello my dear ${user}`);
}
```
```javascript
FileName: Main.js
import {greet} from './Greet.js';
console.log(greet);

greet("kiran");           //Hello my dear kiran

//Output of console.log(greet);
//ƒ greet(user){ console.log(`Hello my dear ${user}`);}
 
``` 
In the above code snippet we export the greet function from Greet.js using export keyword and is imported to Main.js using import keyword.

Modules work in strict mode by default. Each module has it's own top level scope. In a module top level *this* is *undefined*.

Let's look at another example 
```javascript
Filename: module_exp.js
let name = {fname : "Kiran", lname: "raj", initials: "R"};
function dispName(name){
    console.log(`${name.fname} ${name.lname} ${name.initials}.`)
}
export{name, dispName};
```
```javascript
Filename: main.js
import {name, dispName} from './module_exp.js'
console.log(name);
dispName(name);

// Output {fname: "Kiran", lname: "raj", initials: "R"} 
          Kiran raj R.
```
If there are multiple variables(variable, functions, classes...) to export or import we can use `{}`. For example, to export variable a, b and c, we can write it as `export {a, b, c};`. Same can be done for import, `import {a, b, c} from 'file.js'`. 

We can use * to import everything that the file labeled to export, `import * from 'file.js'`. 

We can use *as* to import or export using alias name.
`import {displayName as n, printMessage as msg} from './file.js'`
`export {displayName as n, printMessage as msg} from './file.js'`

We can export variables using *export default* keyword, the variable exported with default keyword can be import without `{}`. Normally only one item can be exported as default. Default variable can be imported with any name.

```javascript
Filename: module_exp.js
export default function dispName(){
    console.log("kiran raj")
}

import disp from './module_exp.js'
```

### Summary

#### Export
`export variableA`                   // export single variable
`export {variableA, variableB, ...}`  // export multiple variables
`export variableA as a`               // export variable using alias 
`export default variableA`            // export variable as default

#### Import
`import { variableA} from "module"`    // import single variable
`import {varA, varB,..} from "module"` // import multiple variables

`import {variable as a} from "module"` //import variable using alias
`import * from "module"`               // import all variables from a module

### Dynamic import

```javascript
export function func1() {}
export default function dispName() {} 
export default const PI = 3.14;
export default 3.14;

import {fun1, fun2 } from './module.js';
import * from './module.js';
import {fun1 as f} from './module.js';
```

The above shown exports and imports are static, in static export / import the module path must be "primitive string". Static import syntax cause the module to be evaluated at the load time only. We can use dynamic import if we like to load a module on demand. The `import("moduleName")` will loads the module and return a promise. If the loading is successful then the promise returned will resolve to an object which have all the exports, else promise will provide an error reason that should be handled. The below example use a catch statement to do the error handling. Static import is the preferred one. Dynamic imports work like regular scripts ,type="module" is not required.

```JavaScript
import('/module.js')
    .then((mod) => {// code to execute})
    .catch((err) =>{// code to handle error})
``` 

### Re-exporting / Aggregating

Consider a situation were we have a large number of modules in an application and we want certain modules to be accessed by users but we don't want anyone from the outside to know what modules we have or our module structure. As we have large number of modules, maintaining will be a tedious task. An idea is to create a single point of entry for outsiders, a module that will import the necessary modules that are needed by the users and export those modules, so the user can access it. All the user required modules are available under one module. Re-export help in this, it will import the modules and immediately export those modules.The module in which re-exports occur does not have access to the modules that was re-exported.

Syntax : `export <module,...> from "module"`

```javascript
export {fun1, fun2 } from 'module.js';

// The above code is equivalent to

import { fun1, fun2 } from 'module.js';
export { fun1, fun2 };
```

The default exports need to be handled separately. 

```javascript
export { default as fun1, fun2 } from 'module.js';
                    //or
export { default, fun2 } from 'module.js';

//The above code is equivalent to

import { default as fun1, fun2 } from 'module.js';
export { fun1 as default, fun2 };
```
An example of dynamic loading using async await
```javascript
//File name : module_imp.js
async function getModule() {
    let modules = await import('./module_exp.js');
    modules.dispName(modules.name); //Kiran raj R.
    modules.default();              //Success
}
getModule();

//File name : module_exp.js
export let name = {fname : "Kiran", lname: "raj", initials: "R"};
export function dispName(name){
    console.log(`${name.fname} ${name.lname} ${name.initials}.`)
}

export default function(){
    console.log("Success");
}

// Output
Kiran raj r
Success
```
Another example of dynamic import
```javascript
// File name : module_exp.js
export let name = {fname : "Kiran", lname: "raj", initials: "R"};
export default function dispName(name){
    console.log(`${name.fname} ${name.lname} ${name.initials}.`)
}

// Filename : module_imp.js
import ( './module_exp.js').then((result)=> {
    console.log("Module loaded");
    let name = result.name;
    console.log(name.lname, name.fname);
    result.default(name)
});

// Output
Module loaded
raj Kiran
Kiran raj R.
```