[Monoepo] Yarn Workspaces

2024-04-12 hit count image

JavaScript로 개발할 프로젝트에서 모노레포(Monorepo)를 사용하기 위한 지식인 Yarn의 Workspaces에 대해서 알아도록 하겠습니다.

개요

이번 블로그 포스트에서는 YarnWorkspaces를 사용하여 모노레포를 구성하는 방법에 대해서 알아보도록 하겠습니다.

블로그 시리즈

이 블로그는 시리즈로 제작되었습니다. 다음 링크를 통해 다른 블로그 포스트도 확인해 보시기 바랍니다.

Yarn Workspaces

이전 블로그 포스트인 모노레포를 위한 도구에서 자바스크립트 패키지 매니저인 YarnWorkspaces를 소개하였습니다.

이번 블로그 포스트에서는 실제로 YarnWorkspaces 기능을 사용하여 모노레포를 구성하는 방법에 대해서 알아보도록 하겠습니다.

YarnWorkspaces는 이전 블로그 포스트에서 소개한 Symlink를 통해 여러 프로젝트를 단일 코드베이스에서 관리할 수 있게 해주는 기능입니다. 이 기능을 사용하면 쉽게 모노레포를 구성할 수 있습니다.

예제

yarn이 제공하는 Workspace 기능을 확인하기 위한 예제를 만들어 봅시다. 우선, 다음과 같이 폴더와 파일 구조를 생성합니다.

.
└── src/
    ├── module-a/
    │   ├── index.js
    │   └── package.json
    └── module-b/
        ├── index.js
        └── package.json

module-apackage.json은 다음과 같습니다.

// src/module-a/package.json
{
  "name": "module-a",
  "version": "1.0.0",
  "main": "index.js"
}

module-bpackage.json은 다음과 같습니다.

// src/module-b/package.json
{
  "name": "module-b",
  "version": "1.0.0",
  "main": "index.js"
}

그리고 module-bindex.js는 다음과 같습니다.

// src/module-b/index.js
console.log('module-b');

마지막으로 module-aindex.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 설정

이제 YarnWorkspaces를 사용하여 module-a에서 module-b를 사용할 수 있게 만들어 보겠습니다. 우선 루트 폴더(/)에서 다음 명령어를 사용하여 YarnWorkspaces를 사용할 준비를 합니다.

yarn init -y

그럼 루트 폴더에 다음과 같은 내용을 포함한 package.json이 생성되는 것을 확인할 수 있습니다.

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}

YarnWorkspaces를 사용하기 위해서는 이 package.json 파일을 다음과 같이 수정해야 합니다.

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": ["src/module-a", "src/module-b"]
  }
}

모노레포는 여러 프로젝트를 가지고 있는 단일 코드베이스이기 때문에 npm 레지스트리와 같은 곳에 배포할 필요가 없습니다. 따라서 privatetrue로 설정하여 모노레포가 배포되지 않도록 합니다. Yarn V1에서는 필수로 설정해야 하지만, Yarn V2부터는 설정하지 않아도 됩니다. 안전하게 관리하기 위해 privatetrue로 설정하는 것을 권장합니다. 물론, 모노레포안에 있는 개별 프로젝트는 배포할 수 있으므로 각각의 프로젝트는 private을 설정하지 않아도 됩니다.

Workspaces는 배열([])이나 오브젝트({})를 설정할 수 있습니다. Yarn에서는 오브젝트 형식으로 작성하는 것을 권장하고 있습니다. Workspaces안에 packages라는 키로 배열을 만들고 각각의 모듈을 추가하였습니다. 이와 같이 각각 지정해도 되지만 다음과 같이 *을 사용하여 간단하게 모든 모듈을 지정할 수도 있습니다.

{
  "name": "monorepo",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": ["src/*"]
  }
}

Yarn Workspaces 확인

이것으로 YarnWorkspaces를 사용할 준비가 끝났습니다. 이제 다음 명령어를 실행하여 패키지를 설치합니다.

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

완료

이것으로 모노레포를 사용하기 위해 YarnWorkspaces를 사용하는 방법에 대해서 알아보았습니다. YarnWorkspaces는 기본적으로 Symlink로 동작하므로 Symlink에 대해 이해하면 좋습니다. Symlink에 대해 자세히 알고 싶다면 이전 블로그 포스트를 참고해 주시기 바랍니다.

이제 여러분도 YarnWorkspaces를 사용하여 모노레포를 구성해 보시기 바랍니다.

제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!

앱 홍보

책 홍보

블로그를 운영하면서 좋은 기회가 생겨 책을 출판하게 되었습니다.

아래 링크를 통해 제가 쓴 책을 구매하실 수 있습니다.
많은 분들에게 도움이 되면 좋겠네요.

스무디 한 잔 마시며 끝내는 React Native, 비제이퍼블릭
스무디 한 잔 마시며 끝내는 리액트 + TDD, 비제이퍼블릭
[심통]현장에서 바로 써먹는 리액트 with 타입스크립트 : 리액트와 스토리북으로 배우는 컴포넌트 주도 개발, 심통
Posts