Contents
Outline
In this blog post, I will explain how NodeJS
loads modules as basic knowledge to understand Monorepo.
Blog series
This blog is a series. Please check other blog posts through the following links.
- [Project Management] Repository Strategy
- [JavaScript] Tools for Monorepo
- [Monorepo] Node JS module resolution
- [Monorepo] Symlink
- [Monoepo] Yarn Workspaces
- [Monoepo] Dependency Hoisting of Yarn Workspaces
- [Monoepo] Command of Yarn Workspaces
- [Monoepo] Creating a Monorepo with PnpM
Module
In JavaScript, modules are features used to organize and separate code into reusable units. Modules make it easier to maintain and extend code. A module system that was originally not in JavaScript was introduced from ECMAScript 2015(ES6).
Modules encapsulate code at the file level and allow you to import the required functionality from other files. Modules prevent conflicts in the global scope and allow you to clearly manage code dependencies.
To use modules in JavaScript, you can use the following keywords.
import
: Imports features exported from other modules into the current module.export
: Specifies functions, variables, classes, etc. to be exported from the current module to the outside.
You can create modules in JavaScript as follows.
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
Modules created in this way can be used as follows.
// main.js
import { add, subtract } from './math';
console.log(add(5, 3)); // 8
console.log(subtract(7, 2)); // 5
Loading modules
There are two ways to load modules in JavaScript.
- Using
File path
- Using
Package name
File path
When adding a module using File path
, you can use relative path or absolute path as follows.
// Relative path
import { add, subtract } from '../some/file/path/math';
// Absolute path
import { add, subtract } from '/src/math';
Package name
Modules in the node_modules
folder can be loaded using Package name
.
// react module exists in node_modules
import React from 'react';
Module resolution priority
When NodeJS
loads a module, first it checks if the module exists in the same folder, and then checks if the module exists in the node_modules
in the same folder. If it does not exist in the same folder, it checks the node_modules
folder int the parent folder, and if it does not exist in the parent folder, it checks the node_modules
in the parnet folder of the parent folder.
Example
To check how NodeJS
loads modules, let’s create the following folder structure.
.
└── src/
├── module-a/
│ ├── index.js
│ └── package.json
└── module-b/
├── index.js
└── package.json
The package.json
of module-a
is as follows.
// src/module-a/package.json
{
"name": "module-a",
"version": "1.0.0",
"main": "index.js"
}
The index.js
of module-b
is as follows.
// src/module-b/package.json
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js"
}
The index.js
of module-a
is as follows.
// src/module-b/index.js
console.log('module-b');
Lastly, the index.js
of module-a
is as follows.
// src/module-a/index.js
console.log('module-a');
require('module-b');
After configuring the files like this, run the following command to check if the module is loaded well.
node src/module-a/index.js
Then, you can see the following error.
module-a
node:internal/modules/cjs/loader:1073
throw err;
^
Error: Cannot find module 'module-b'
Require stack:
- /Users/deku/temp/temp/src/module-a/index.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1070:15)
at Module._load (node:internal/modules/cjs/loader:923:27)
at Module.require (node:internal/modules/cjs/loader:1137:19)
at require (node:internal/modules/helpers:121:18)
at Object.<anonymous> (/Users/deku/temp/temp/src/module-a/index.js:3:1)
at Module._compile (node:internal/modules/cjs/loader:1255:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1309:10)
at Module.load (node:internal/modules/cjs/loader:1113:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) {
code: 'MODULE_NOT_FOUND',
requireStack: [ '/Users/deku/temp/temp/src/module-a/index.js' ]
}
Next, change the folder name src
to node_modules
and run it again.
node node_modules/module-a/index.js
Then, you can see that it runs without any problems as follows.
module-a
module-b
In the case that the folder name is src
, when module-a
loads module-b
by require('module-b');
, it can not load the file path, so it looks for module-b
in the node_modules
of the same folder. Since node_modules
does not exist in the current folder, it checks the node_modules
in the parent folder. Since there is no node_modules
in the parent folder, the MODULE_NOT_FOUND
error occurs.
In the case that the folder name is node_modules
, when module-a
loads module-b
by require('module-b');
, it can not load the file path, so it looks for module-b
in the node_modules
of the same folder. Since node_modules
does not exist in the current folder, it checks the node_modules
in the parent folder. In the parent folder, there is a node_modules
folder that we’ve changed the name, and the module-b
exists in the node_modules
folder, so it can be loaded without any problems.
Completed
Done! we’ve senn how NodeJS
loads modules. How NodeJS
loads modules is knowledge that helps to configure a project as a Monorepo, so I introduced it in this blog post. I hope you take this opportunity to understand how NodeJS
loads modules again.
Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!
App promotion
Deku
.Deku
created the applications with Flutter.If you have interested, please try to download them for free.