개요
이번 블로그 포스트에서는 Yarn의 Workspaces를 사용하여 모노레포를 구성하는 방법에 대해서 알아보도록 하겠습니다.
블로그 시리즈
이 블로그는 시리즈로 제작되었습니다. 다음 링크를 통해 다른 블로그 포스트도 확인해 보시기 바랍니다.
- [프로젝트 관리] 리포지토리 전략
- [JavaScript] 모노레포(Monorepo)를 위한 도구들
- [Monorepo] NodeJS의 모듈 불러오기
- [Monorepo] Symlink
- [Monorepo] Yarn Workspaces
- [Monorepo] Yarn Workspaces의 Hoisting
- [Monorepo] Yarn Workspaces의 명령어
- [Monorepo] pnpm을 사용하여 모노레포 만들기
Yarn Workspaces
이전 블로그 포스트인 모노레포를 위한 도구에서 자바스크립트 패키지 매니저인 Yarn의 Workspaces를 소개하였습니다.
이번 블로그 포스트에서는 실제로 Yarn의 Workspaces 기능을 사용하여 모노레포를 구성하는 방법에 대해서 알아보도록 하겠습니다.
- 공식 문서: Workspaces
Yarn의 Workspaces는 이전 블로그 포스트에서 소개한 Symlink를 통해 여러 프로젝트를 단일 코드베이스에서 관리할 수 있게 해주는 기능입니다. 이 기능을 사용하면 쉽게 모노레포를 구성할 수 있습니다.
예제
yarn이 제공하는 Workspace 기능을 확인하기 위한 예제를 만들어 봅시다. 우선, 다음과 같이 폴더와 파일 구조를 생성합니다.
.
└── 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');
이렇게 파일을 구성한 후, 다음 명령어를 실행하여 모듈을 잘 불러오는지 확인합니다.
node src/module-a/index.js
그럼 다음과 같이 에러가 발생하는 것을 확인할 수 있습니다.
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' ]
}
Yarn Workspaces 설정
이제 Yarn의 Workspaces를 사용하여 module-a에서 module-b를 사용할 수 있게 만들어 보겠습니다. 우선 루트 폴더(/)에서 다음 명령어를 사용하여 Yarn의 Workspaces를 사용할 준비를 합니다.
yarn init -y
그럼 루트 폴더에 다음과 같은 내용을 포함한 package.json이 생성되는 것을 확인할 수 있습니다.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT"
}
Yarn의 Workspaces를 사용하기 위해서는 이 package.json 파일을 다음과 같이 수정해야 합니다.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/module-a", "src/module-b"]
}
}
모노레포는 여러 프로젝트를 가지고 있는 단일 코드베이스이기 때문에 npm 레지스트리와 같은 곳에 배포할 필요가 없습니다. 따라서 private을 true로 설정하여 모노레포가 배포되지 않도록 합니다. Yarn V1에서는 필수로 설정해야 하지만, Yarn V2부터는 설정하지 않아도 됩니다. 안전하게 관리하기 위해 private을 true로 설정하는 것을 권장합니다. 물론, 모노레포안에 있는 개별 프로젝트는 배포할 수 있으므로 각각의 프로젝트는 private을 설정하지 않아도 됩니다.
Workspaces는 배열([])이나 오브젝트({})를 설정할 수 있습니다. Yarn에서는 오브젝트 형식으로 작성하는 것을 권장하고 있습니다. Workspaces안에 packages라는 키로 배열을 만들고 각각의 모듈을 추가하였습니다. 이와 같이 각각 지정해도 되지만 다음과 같이 *을 사용하여 간단하게 모든 모듈을 지정할 수도 있습니다.
{
"name": "monorepo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"private": true,
"workspaces": {
"packages": ["src/*"]
}
}
Yarn Workspaces 확인
이것으로 Yarn의 Workspaces를 사용할 준비가 끝났습니다. 이제 다음 명령어를 실행하여 패키지를 설치합니다.
yarn install
그럼 다음과 같이 루트 폴더에 node_modules 폴더가 생기가 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에서 module-b를 사용할 수 있는지 확인해 보겠습니다.
node src/module-a/index.js
그럼 다음과 같이 문제없이 module-a가 실행되는 것을 확인할 수 있습니다.
module-a
module-b
물론 Symlink로 연결된 것이기 때문에 module-b의 코드를 수정하면 module-a에서도 수정된 코드를 사용할 수 있습니다. src/module-b/index.js 파일을 열고 다음과 같이 수정합니다.
console.log('module-b!!!');
그리고 다음 명령어를 실행하여 변경된 내용이 잘 표시되는 확인합니다.
node src/module-a/index.js
그럼 다음과 같이 변경된 내용이 잘 표시되는 것을 확인할 수 있습니다.
module-a
module-b!!!
.gitignore
Git으로 소스코드를 관리하고 있다면, .gitignore 파일을 만들고 다음과 같이 수정하여 node_modules 폴더를 Git에서 제외하도록 합니다.
# .gitignore
node_modules
완료
이것으로 모노레포를 사용하기 위해 Yarn의 Workspaces를 사용하는 방법에 대해서 알아보았습니다. Yarn의 Workspaces는 기본적으로 Symlink로 동작하므로 Symlink에 대해 이해하면 좋습니다. Symlink에 대해 자세히 알고 싶다면 이전 블로그 포스트를 참고해 주시기 바랍니다.
이제 여러분도 Yarn의 Workspaces를 사용하여 모노레포를 구성해 보시기 바랍니다.
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku가 개발한 앱을 한번 사용해보세요.Deku가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.














![[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통](https://img1c.coupangcdn.com/image/affiliate/banner/7cba8cb0601eebaf88a17a0c3cf65a63@2x.jpg)