Understanding require function (Node.js)
Tags: javascript, node, programming, webdev
Published: 2023-10-03 02:27:27

_**require**_ is a function that uses CommonJS which is the way that Node.js uses to load a module, when we do require(‘my-file.js’) it executes the function only once and is cached in memory, if we call the same require in other files, isn’t loaded again but uses the one you loaded previously, which is why they are considered singleton each file.

By default, node wraps the code in a function, this allows all the variables that are defined in the file not to colliding with others in other files, unless one exports some.

```
(function(exports, require, module, __filename, __dirname) {
 // my code
});
```

This is similar to what was done before with Closure or IIFEE to prevent variables from colliding in js files on a web page.

A simple example to give context

Example _**index.html**_

```
<!DOCTYPE html>
<html lang=”en”>
 <head>
   <title>Simple example to check this problem</title>
 </head>
 <body>
   <script src=”script_1.js”></script>
   <script src=”script_2.js”></script>
 </body>
</html>
```

File _**script_1.js**_

```
const my_variable = “hello in script 1”;
console.log(my_variable);
```

File _**script_2.js**_

```
const my_variable = “hello in script 2”;
console.log(my_variable);
```

In this case there are 2 scripts, which both define the same variable “my_variable”, you can see how there is an error, due to a collision of a variable already declared.

> Uncaught SyntaxError: Identifier ‘my_variable’ has already been declared (at script_2.js:1:1)

How do you fix this before? similar to what the node wrapper does, creating a closure or an IIFE to encapsulate the variables so that there are no problems between the files.

File _**script_1.js**_

```
(() => {
 const my_variable = ‘hello in script 1’;
 console.log(my_variable);
})();
```

File _**script_2.js**_

```
(() => {
 const my_variable = ‘hello in script 2’;
 console.log(my_variable);
})();
```

With this change now in the console, we will see the 2 logs

- hello in script 1
- hello in script 2

Currently, as ES6 has existed for several years, you can do the same thing by adding only the {} between the code, this is because it is a block scope, the variables live in the scope of the curly braces “{}”

File _**script_1.js**_

```
{
 const my_variable = ‘hello in script 1’;
 console.log(my_variable);
}
```

File _**script_2.js**_

```
{
 const my_variable = ‘hello in script 2’;
 console.log(my_variable);
}
```

With this change, the same result is reached

- hello in script 1
- hello in script 2

_**require**_, being a function, allows you to perform dynamic requires, such as require(`/${locale}/translations.json`); where locale is a variable, it’s a good feature, however, it’s a disadvantage vs ESmodules, since being dynamic and sync, it is difficult to know in advance what is being requested, for frontend applications that have libraries with CommonJS such as final bundler, it does not allow three-shaking, which is to avoid loading code that is not used, dead code, for this reason the libs that use CommonJS are always heavier than those that use ES modules with import, since it allows you to use this feature, that promoted [Rollup](https://rollupjs.org/) at the time.

## Simple example to understand three-shaking

Suppose we have a util file, with 3 methods exposed

File _**utils.js**_

```
function track() {}
function trackingGTM() {}
function trackingPrivateSolution() {}

export { track, trackingGTM, trackingPrivateSolution };
```

We have another _**my-view.js**_ file that consumes this _**util.js**_, but it only uses one function only “track”, if it is configured correctly, it should add only the track util.

File _**my-view.js**_

```
import { track } from ‘./util’;

console.log(track());
```

## What happens when we require a module?

There are several steps

**Resolving**: It is responsible for resolving the path that one sends it, roughly speaking, if the path does not exist locally, it searches in “node_modules” and if not, it throws the module not found error, this can be validated using Node’s require.resolve function .js to validate if a module exists.

```
try {
 require.resolve(“fake_module”);
} catch (err) {
 if (err.code === “MODULE_NOT_FOUND”) {
   console.log(“The current module not exists”);
 }
}
```

**Loading**: Responsible for loading the module.

**Wrapping**: The step of wrapping the function to avoid collisions between files.

**Evaluating**: Performs the execution of the file, which is why we see errors when loading a file, for example from a non-existent path or an undefined variable, or some method that we load to warm up an object in memory.

**Caching**: If everything went ok, it remains in memory to avoid executing all the returned flow by requiring the same file elsewhere.