Contents
Outline
In this blog post, I will introduce how Hoisting
that occurs when adding dependencies (libraries) to each project when configuring a Monorepo using Yarn
’s Workspaces
.
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
NodeJS Module Resolution
When importing modules using import
in NodeJS
, it first checks the node_modules
of the root folder, and if the module is not found, it checks the parent’s node_modules
, and repeats this process until it checks the node_modules
of the top folder.
In this blog post, I will introduce the Hoisting
that uses the module loading process of NodeJS
.
Hoisting of Dependencies
In configuring a Monorepo using Yarn
’s Workspaces
, when adding dependencies to each project, the dependencies are hoisted
and installed in the top folder to efficiently manage dependencies.
The Hoisting
of dependencies in Yarn
’s Workspaces
has the following advantages.
- Dependencies that are commonly used in each project are installed only once to save memory.
- By separating dependencies of the same version and different versions, it prevents dependency version conflicts.
- When installing the same dependency, it is installed only once, so it can be installed quickly, and if the already installed dependency is used, it is not installed additionally, so caching effect can be obtained.
Example
Let’s create an example to check the Hoisting
of dependencies. First, create the folder and file structure as follows.
.
├── package.json
└── 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 package.json
of module-b
is as follows.
// src/module-b/package.json
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js"
}
And the index.js
of module-b
is as follows.
// src/module-b/index.js
console.log('module-b');
The index.js
of module-a
is as follows.
// src/module-a/index.js
console.log('module-a');
require('module-b');
Lastly, modify the package.json
file in the root folder as follows.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"]
}
}
You can see that the packages
is set to workspaces
in the package.json
to use Yarn
’s Workspaces
. For more information on Yarn
’s Workspaces
, please refer to the following blog post
Dependency Installation
Now, let’s install the dependencies.
yarn install
And then, you can see the Symlink
of module-a
and module-b
in the node_modules
as follows.
.
├── node_modules
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ │ ├── index.js
│ │ └── package.json
│ └── module-b
│ ├── index.js
│ └── package.json
└── yarn.lock
Adding Dependencies
Now, let’s add the dependency to module-a
to check Hoisting
. Open the package.json
file of module-a
in src/module-a/package.json
and modify it as follows.
{
"name": "module-a",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"lodash": "^3"
}
}
Then, run the following command to install the dependencies.
yarn install
Then, you can see that the lodash
is installed and Hoisted
in the node_modules
of the root folder.
.
├── node_modules
│ ├── lodash
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ └── module-b
└── yarn.lock
Using Hoisted Dependencies
To see if you can use the Hoisted
dependencies, open the src/module-a/index.js
file and modify it as follows.
const _ = require('lodash');
console.log('module-a');
require('module-b');
console.log(_.flatten([1, [2, 3, 4]]));
And then, run the following command to run module-a
.
node ./src/module-a
Then, you can see that lodash
is well imported as follows.
module-a
module-b
[ 1, 2, 3, 4 ]
By this, you see the Hoisted
dependencies can be used.
Dependency Version Conflict
Let’s see how it works when different versions of the same dependency are installed. Open the package.json
file of module-b
in src/module-b/package.json
and modify it as follows.
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"lodash": "^4"
}
}
And then, run the following command to install the dependencies.
yarn install
Then, you can see that conflicting version of the loadash
is installed in the node_modules
of the module folder.
.
├── node_modules
│ ├── lodash
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ │ ├── index.js
│ │ └── package.json
│ └── module-b
│ ├── index.js
│ ├── node_modules
│ │ └── lodash
│ └── package.json
└── yarn.lock
nohoist option
If you want to install dependencies in each project’s node_modules
without using the Hoisted
dependencies, you can use the nohoist
option. Open the package.json
file in the root folder and add the nohoist
option as follows.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"],
"nohoist": ["**/lodash"]
}
}
And then, delete the yarn.lock
file and run the following command to install the dependencies.
# rm yarn.lock
yarn install
Then, you can see that the different versions of the dependencies are installed in the node_modules
of each module folder.
.
├── node_modules
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ │ ├── index.js
│ │ ├── node_modules
│ │ │ └── lodash
│ │ └── package.json
│ └── module-b
│ ├── index.js
│ ├── node_modules
│ │ └── lodash
│ └── package.json
└── yarn.lock
Complete
Done! We’ve seen how Hoisting
works when adding dependencies to each project in configuring a Monorepo using Yarn
’s Workspaces
. We’ve also seen the nohoist
option to prevent dependencies from being Hoisted
.
I hope this post will help you understand how Hoisting
works when adding dependencies to each project in configuring a Monorepo using Yarn
’s Workspaces
. Also, I hope you can efficiently manage dependencies using Hoisting
and nohoist
in Yarn
’s Workspaces
.
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.