[Monoepo] PnPM을 사용하여 모노레포 만들기

2024-04-13 hit count image

NodeJS의 패키지 매니저중 하나인 PnPM을 사용하여 모노레포를 만드는 방법에 대해서 알아봅시다.

개요

이번 블로그 포스트에서는 PnPM을 사용하여 모노레포를 만드는 방법에 대해서 알아보겠습니다.

블로그 시리즈

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

PnPM

PnPM은 NodeJS 패키지 매니저중 하나로, NPM, Yarn과 동일한 역할을 합니다. PnPM은 빠른 설치 속도와 공간 절약을 강조하며 다양한 프로젝트에서 사용되고 있습니다.

PnPM 설치

다음 명령어를 사용하여 PnPM이 설치되어 있는지 확인합니다.

pnpm -v

설치가 되어 있지 않다면 다음 명령어를 실행하여 PnPM을 설치합니다.

npm install -g pnpm

예제

PnPM을 설치하였다면, PnPM을 사용하여 모노레포를 구성해 봅시다. 모노레포를 구성하기 위해 다음과 같은 폴더와 파일 구조를 만듭니다.

.
├── package.json
└── 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",
  "scripts": {
    "start": "node index.js"
  }
}

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

// src/module-b/package.json
{
  "name": "module-b",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node 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' ]
}

pnpm-workspace.yaml

PnPM을 사용하여 모노레포를 구성하기 위해서는 pnpm-workspace.yaml 파일이 필요합니다. 루트 폴더에 pnpm-workspace.yaml 파일을 만들고 다음과 같이 수정합니다.

packages:
  - 'src/*'

의존성 설치

module-amodule-b를 사용하기 때문에, module-apackage.json 파일에 module-b를 의존성으로 추가해야 합니다. 의존성을 추가하기 위해 src/module-a/package.json 파일을 열고 다음과 같이 수정합니다.

{
  "name": "module-a",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "module-b": "workspace:*"
  }
}

파일을 수정하였다면, 루트 폴더에서 다음 명령어를 실행하여 의존성을 설치합니다.

pnpm install

그런 다음 폴더 구조를 확인해 보면 다음과 같이 module-a 폴더안 node_modulesmodule-bSymlink가 생성된 것을 확인할 수 있습니다.

.
├── node_modules
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── src
    ├── module-a
    │   ├── index.js
    │   ├── node_modules
    │   │   └── module-b -> ../../module-b
    │   └── package.json
    └── module-b
        ├── index.js
        └── package.json

Symlink에 관한 자세한 내용은 다음 링크를 참고하시기 바랍니다.

확인

이제 PnPM을 사용하여 모노레포를 사용할 준비가 끝났습니다. 다음 명령어를 실행하여 모듈을 잘 불러오는지 확인합니다.

pnpm module-a start

그럼 다음과 같이 실행이 잘 되는 것을 확인할 수 있습니다.

module-a
module-b

module-anode_modulesmodule-bSymlink가 생성되었기 때문에, 다음 명령어를 사용할 수 있습니다.

node ./src/module-a

module-b는 의존성이 없으므로, 다음 명령어를 실행하면 문제없이 실행 되는 것을 확인할 수 있습니다.

pnpm module-b start
# module-b
node ./src/module-b
# module-b

완료

이것으로 PnPM을 사용하여 모노레포를 구성하는 방법에 대해서 알아보았습니다. 여러분이 만약 Yarn을 사용하지 않고 PnPM을 사용하고 계신다면, 이 블로그 포스트를 참고하여 PnPM으로 모노레포를 구성해 보시기 바랍니다.

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

앱 홍보

책 홍보

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

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

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