# All about modules

### Two different standards

In the browser JavaScript ecosystem, JavaScript modules depends on `import` and `export` statements to load and export ES modules.

In addition, ES module is the official standard format to package JavaScript code for reuse.

On the other hand, Node.js, supports the CommonJS module format by default. CommonJS module load using `require()` and the variables and functions export from a CommonJS module with `module.exports`

Why the two different standards? Good question. CommonJS module is built into Node.js before ES module were introduced.

##### Node.js support ES module

There are two ways you can enable ES modules in Node.js.

##### First way

You can simply change the file extension from `.js` to `.mjs` to use ES module syntax to load and export modules:

```javascript
// util.mjd
export function add(a, b) {
	return a + b;
}
```

```javascript
// app.mjs
import {add} from './util.mjs'

console.log(add(1, 2)); // 3
```

##### Second way (better way)

You can add a `"type": "module"` field inside the nearest `package.json` file. By including that field, Node.js will treat all files inside the package as ES modules instead, so you wouldn't have to change to `.mjs` extensions.

##### How frameworks deal with this

You will be using `import/export` for frameworks like React and Vue.js, the framework themselves will use a transpiler to compile the `import/export` syntax down to `require` anyway.

### Module

What is a module? A module is just a file, one script is one module. Simple.

Modules can load each other using `export` and `import` directives to give and exchange functionality between different files.

- `export`: This keyword labels variables and functions that should be accessible from outside
- `import`: This keyword allows you to import functionality that are exported by other modules.

##### Example

```javascript
// sayHi.js
export function sayHi(user) {
	console.log("Hello " + user)
}
```

Another file can import it and use it

```javascript
// main.js
import {sayHi} from './sayHi.js'

console.log(sayHi); // function
sayHi("Ricky"); // Hello Ricky
```

##### Base modules

Any `import` statement must get either a relative or absolute URL. Modules without any path are called bare modules:

```javascript
import {sayHi} from 'sayaHi'
```

They are not allowed in browser, but Node.js or bundle tools allow such bare modules

##### Build tools

Using a build tool like Webpack will allow you to use bare modules. It also does code optimization and remove unreachable code.

### Export/import

Export and import directives have many syntax variants and we will go over them.

##### Export before declaration

Here is how you export along with the declaration of variables and functions:

```javascript
export let months = [1, 2, 3, 4]; // exporting an array

export const MODULE_CONST = 69; // exporting a const

// exporting a class
export class User {
	constructor(name) {
    	this.name = name;
	}
}

// exporting a function
export function foo() {
	console.log("fooing around");
}
```

##### Export after declaration

Here is how you export if you already have the declaration of variables and functions already:

```javascript
let x = 69;

function sayHi() {
	console.log("Hi");
}

function sayBye() {
	console.log("Bye");
}

export {x, sayHi, sayBye}; // you pass in a list of exported variables or functions
```

##### Export as

When you export a variable or function you can also choose a different name to export under, so that the modules that will be importing will use the name that you choose

```javascript
// say.js
export { sayHi as hi, sayBye as bye};

```

```javascript
// main.js
import {hi, bye} from './say.js'

hi();
bye();
```

##### Export default

Typically there is two types of modules

1. Module that contain a library like bunch of functions
2. Or modules that declare a single entity which exports say only a class for others to use

The second approach is mostly done. And to do it there is the syntax `export default` to export a default export, and there is only one default export per file, one thing that you can defaulty export per module.

```javascript
// user.js
export default class User {
	constructor(name) {
    	this.name = name;
	}
}

// or equivalent
class User {
  	constructor(name) {
      	this.name = name;
    }
}

export {User as default};
```

```javascript
import User from './user.js' // not {User} just User
import {default as User} from './user.js' // this is the second way

new User("ricky");
```

When you are importing the default export you do not need any curly braces and it looks nicer.

On the other hand, named exports needs curly braces, and default export do not need them

<p class="callout info">When you are using default exports, you always choose the name when you are importing, it doesn't matter what the name is. However, naming it different things might end up confusing some team members, so the best practice is to name the default export the same as the file names.</p>

```javascript
import User from './user.js'
import LogicForm from './logicForm.js'
import func from '/path/to/func.js'
```

##### Import  


Usually you can put a list of what you want to import in curly braces

```javascript
import { sayHi, sayBye, x} from './say.js'
```

##### Import \*

But if there is a lot to import you can import everything as an object using `import * as <obj>`

```javascript
import * as say from './say.js'

say.sayHi();
say.sayBye();
say.default; // to  access the default export if you export everything *
```

##### Import &lt;&gt; as

You can also pick an alias for the functions or variables that you have imported using `as`

```javascript
import {sayHi as hi, sayBye as bye} from './say.js'

hi();
bye();
```

##### Import default export along with name export

The `default` keyword is used to reference to the default export

```javascript
import {default as User, sayHi} from './user.js'
```

### Re-exporting

Re-exporting syntax `export ... from` allows you to import things and immediately export them like so:

```javascript
export {sayHi} from './say.js' // re-export sayHi

export {default as User} from './user.js' // re-export the default export under User name
```

Why would you do this? Well imagine you are writing a package: folder with lots of modules and some under a different folder because they are just helper functions. So your file structure could be like so:

```javascript
auth/
    index.js
    user.js
    helpers.js
    tests/
        login.js
    providers/
        github.js
        facebook.js
        ...
```

You would like to expose the package functionality via just a single entry point, i.e. if someone wants to use your package they can just import only from `auth/index.js`.

```javascript
import {login, logout} from 'auth/index.js'
```

Instead of doing it from the exact file that it was exported. We can just let the main file to export all the functionality that we want to provide in the package.

Other programmer who want to use the package shouldn't need to look into the internal structure, search for files inside the package folder for the exact one to import. They can just look at one main file to import from, while keeping the rest hidden.

This is where re-exporting can be used to do this

```javascript
// auth/index.js
// import login/logout and export them
import {login, logout} from './helpers.js'
export {login, logout}

// import default as User and then export it
import User from './user.js'
export {User}
```

Now user can just do `import {login} from 'auth/index.js'`

The syntax `export ... from ...` is just a shorter notation for such import-export:

```javascript
import {login, logout} from './helpers.js'
export {login, logout}

import User from './user.js'
export {User}

// Equivalent to
export {login, logout} from './helpers'.js'
export {default as User} from './user.js' // This is default re-exporting
```

If you are re-exporting a default export using the shorter notation, you must do it via `export {default} from './file.js'` and if you are planning to export other named exports from the same file you would have to do `export * from './file.js'`.

**Basically, for default exports you would have to handle it separately, you cannot just `export *`, it will only handle named exports and not default exports.**