개요
이번 블로그 포스트에서는 Yarn
의 Workspaces
를 사용하여 모노레포를 구성하는 과정에서 각 프로젝트에 필요한 의존성(라이브러리)을 추가할 때, 의존성이 추가되는 과정에서 발생하는 Hoisting
에 대해서 알아보도록 하겠습니다.
블로그 시리즈
이 블로그는 시리즈로 제작되었습니다. 다음 링크를 통해 다른 블로그 포스트도 확인해 보시기 바랍니다.
- [프로젝트 관리] 리포지토리 전략
- [JavaScript] 모노레포(Monorepo)를 위한 도구들
- [Monoepo] NodeJS의 모듈 불러오기
- [Monorepo] Symlink
- [Monoepo] Yarn Workspaces
- [Monoepo] Yarn Workspaces의 Hoisting
- [Monoepo] Yarn Workspaces의 명령어
- [Monoepo] pnpm을 사용하여 모노레포 만들기
NodeJS의 모듈 불러오기
NodeJS
에서 import
를 사용하여 모듈을 불러올 때, NodeJS
는 우선 루트 폴더의 node_modules
를 확인하고 해당 모듈이 없는 경우, 부모의 node_modules
를 확인하고, 이를 반복하여 최상위 폴더의 node_modules
까지 확인합니다.
이번 블로그 포스트에서 소개할 Hoisting
은 NodeJS
의 모듈 불러오기 과정을 활용한 기능입니다.
의존성 Hoisting
Yarn
의 Workspaces
를 사용하여 모노레포를 구성하는 과정에서 각 프로젝트에 필요한 의존성을 추가하면, 효율적으로 의존성을 관리하기 위해 해당 의존성은 Hoisting
되어 최상위 폴더의 node_modules
에 설치됩니다.
의존성의 Hoisting
은 다음과 같은 장점을 가집니다.
- 각 프로젝트에서 공통으로 사용되는 의존성은 한번만 설치되어 메모리를 절약할 수 있습니다.
- 동일한 버전의 의존성과 다른 버전의 의존성을 분리하여 관리하기 때문에 의존성의 버전 충돌을 방지할 수 있습니다.
- 동일한 의존성을 설치하는 경우, 한번만 설치를 하므로 빠르게 설치가 가능하고 이미 설치된 의존성을 사용하는 경우 추가로 설치하지 않기 때문에 캐싱 효과를 얻을 수 있습니다.
예제
의존성의 Hoisting
을 확인하기 위해 예제를 만들어 봅시다. 우선, 다음과 같이 폴더와 파일 구조를 생성합니다.
.
├── package.json
└── src
├── module-a
│ ├── index.js
│ └── package.json
└── module-b
├── index.js
└── package.json
module-a
의 package.json
은 다음과 같습니다.
// src/module-a/package.json
{
"name": "module-a",
"version": "1.0.0",
"main": "index.js"
}
module-b
의 package.json
은 다음과 같습니다.
// src/module-b/package.json
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js"
}
그리고 module-b
의 index.js
는 다음과 같습니다.
// src/module-b/index.js
console.log('module-b');
module-a
의 index.js
는 다음과 같습니다.
// src/module-a/index.js
console.log('module-a');
require('module-b');
마지막으로 루트 폴더의 있는 package.json
파일을 다음과 같이 수정합니다.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"]
}
}
Yarn
의 Workspaces
를 사용하기 위해 package.json
의 wordspaces
에 packages
가 설정된 것을 확인할 수 있습니다. Yarn
의 Workspaces
에 대한 자세한 내용은 다음 블로그 포스트를 참고하시기 바랍니다.
의존성 설치
이제 다음 명령어를 실행하여 의존성을 설치합니다.
yarn install
그럼 다음과 같이 node_modules
에 module-a
와 module-b
의 Symlink
가 생성된 것을 확인할 수 있습니다.
.
├── 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
의존성 추가
이제 module-a
에 의존성을 추가하여 의존성이 Hoisting
되는지 확인해 봅시다. module-a
의 package.json
파일인 src/module-a/package.json
파일을 열고 다음과 같이 수정합니다.
{
"name": "module-a",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"lodash": "^3"
}
}
그런 다음 다음 명령어를 실행하여 의존성을 설치합니다.
yarn install
그럼 다음과 같이 루트 폴더의 node_modules
에 Hoisting
된 lodash
가 설치된 것을 확인할 수 있습니다.
.
├── node_modules
│ ├── lodash
│ ├── module-a -> ../src/module-a
│ └── module-b -> ../src/module-b
├── package.json
├── src
│ ├── module-a
│ └── module-b
└── yarn.lock
Hoisting된 의존성 사용
Hoisting
된 의존성을 사용할 수 있는지 알아보기 위해 src/module-a/index.js
파일을 열고 다음과 같이 수정합니다.
const _ = require('lodash');
console.log('module-a');
require('module-b');
console.log(_.flatten([1, [2, 3, 4]]));
그리고 다음 명령어를 실행하여 module-a
를 실행합니다.
node ./src/module-a
그럼 다음과 같이 lodash
가 잘 불러와지는 것을 확인할 수 있습니다.
module-a
module-b
[ 1, 2, 3, 4 ]
이를 통해 Hoisting
된 의존성을 사용할 수 있음을 확인할 수 있습니다.
의존성 버전 충돌
동일한 의존성의 다른 버전이 설치된 경우, 어떻게 동작하는지 확인해 봅시다. module-b
의 package.json
파일인 src/module-b/package.json
파일을 열고 다음과 같이 수정합니다.
{
"name": "module-b",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"lodash": "^4"
}
}
그런 다음, 다음 명령어를 실행하여 의존성을 설치합니다.
yarn install
그럼 다음과 같이 버전이 다른 의존성은 모듈 폴더안에 node_modules
에 설치되는 것을 확인할 수 있습니다.
.
├── 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 옵션
Hoisting
된 의존성을 사용하지 않고, 각 프로젝트의 node_modules
에 의존성을 설치하고 싶은 경우, nohoist
옵션을 사용할 수 있습니다. 루트 폴더의 package.json
파일을 열고 다음과 같이 nohoist
옵션을 추가합니다.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"],
"nohoist": ["**/lodash"]
}
}
그리고 yarn.lock
파일을 삭제한 다음, 다음 명령어를 실행하여 의존성을 설치합니다.
# rm yarn.lock
yarn install
그럼 다음과 같이 lodash
가 Hoisting
되지 않고 각 프로젝트의 node_modules
에 설치된 것을 확인할 수 있습니다.
.
├── 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
완료
이것으로 Yarn
의 Workspaces
를 사용하여 모노레포를 구성하는 과정에서 각 프로젝트에 필요한 의존성을 추가할 때, 의존성이 추가되는 과정에서 발생하는 Hoisting
에 대해서 알아보았습니다. 또한 의존성이 Hoisting
되는 것을 방지하기 위한 nohoist
옵션에 대해서도 알아보았습니다.
여러분도 Yarn
의 Workspaces
를 사용하여 모노레포를 구성하는 과정에서 의존성의 Hoisting
과 nohoist
을 활용하여 효율적으로 의존성을 관리해 보시기 바랍니다.
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku
가 개발한 앱을 한번 사용해보세요.Deku
가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.