모노레포 도구(yarn, lerna)

이명진·2022년 12월 10일
0

TIL

목록 보기
2/16
post-thumbnail

모노레포를 사용하기 위해 편리한 도구들이 있다.

Yarn , Learn ,Nx , Turborepo 등 많이 있지만 yarn과 learn에 대해서만 알아보려고 한다.
npm도 있다고는 들었다(?)
자료를 찾다가 읽었는데 yarn이 우선으로 가지고 있어서 yarn을 모노레포때문에 사용한다고 했다가 후발주자로 npm도 모노레포가 되도록 업데이트 했다고 읽었다.

일단 공부는 naver D2에서 정리된 개념으로 공부했다. 나중에 실제로 사용하게 되면
좀더 자세히 알아보고 오늘은 겉핡기식으로 정리해보려고 한다.

naver D2 모노레포 도구
나머지들은 위의 사이트에서 확인해보자.

yarn

Yarn 은 workspaces 필드를 사용해서 모노레포를 구성할수있다.

용어

  • project
    • = 저장소
    • 하나 이상의 worktree 포함
    • 최소 한 개의 workspace(즉, 루트 workspace) 존재
  • workspace
    • = 모노레포 패키지
  • worktree
    • 자식 workspace를 갖는 workspace

사용법

package.json 에 workspace root 라는 것을 설정해둔다.

{
  "private": true,
  "workspaces": ["workspace-a", "workspace-b"]
}

공식문서에서는 "workspace-a", "workspace-b" 이렇게 스페이스를 나눠놓았다.

이렇게 설정한다음 각각 "workspace-a", "workspace-b”폴더를 만들고
그 폴더 내부에 package.json 을 각각 만들어 준다.

workspace-a/package.json 
{
  "name": "workspace-a",
  "version": "1.0.0",

  "dependencies": {
    "cross-env": "5.0.5"
  }
}

예시는 workspace-a 만 설정한 것만 작성했다. Workspace-b 설정한 다음 yarn install 을 루트에서 실행하면 루트 경로 node_modules에 심볼릭 링크가 생긴다.

특정 workspace 실행

yarn workspace <WORKSPACE_NAME> <COMMAND_NAME>  

위의 명령어로 실행한다.

Yarn workspace  <WORKSPACE_NAME> run start 

실행하면 된다.

이렇게 되면 한쪽에서 모듈로 함수를 만들어서 export 하면
다른 레포지토리에서 모듈을 받아서 사용이 가능하다.

예) workspace-a 에서 module.exports = {hello () {console.log(‘hello’)}} 작성하고
workspace-b에서 const workspaceA = require(“workspace-a”)를 설정하고
객체의 함수, 변수 등을 꺼내서 사용할수 있다.


workspaceA.hello(); //‘hello’ 

명령어

Workspace 의존 관계 확인

yarn workspaces info 

루트 프로젝트에 의존성 추가

yarn add <PACKAGE_NAME> -W 

workspace를 의존성으로 추가

yarn workspace <WORKSPACE_NAME> add <WORKSPACE_NAME>

npm, yarn 등은 중복 의존성 설치를 방지하기 위해 호이스팅(hosting) 기법을 사용한다.

단점

node_modules의 문제점이 있다. 
  • 의존성 탐색 알고리즘의 비효율
node.js에서 require() 함수를 실행하면 모듈을 찾을 때까지 상위 node_modules 디렉터리를 순회한다. 이때 느린 디스크 I/O 동작이 경로의 깊이만큼 발생한다.
  • 저장 공간과 설치 시간
node_modules 디렉터리는 흔히 매우 큰 공간을 필요로 하고, 그만큼 설치에도 오랜 시간이 걸린다.
  • 유령 의존성(phantom dependency)
의존성 중복 방지를 위해 호이스팅 기법을 이용하는데 이것은 의도치 않은 side effect을 발생시킨다. 아래 그림에서 package-1은 B(1.0)을 설치한 적이 없지만 require('B')가 작동한다. require('B')를 사용하는 경우 B(1.0)을 의존하던 패키지를 제거하면 B를 찾지 못하는 오류가 발생한다.

그래서 yarn berry를 사용 하여 pnp로 해결한다.
Yarn berry 는 node_modules에 패키지 파일을 저장하는 대신 캐시 폴더에 수평적으로 저장하는 방법으로 문제를 해결했다고 한다.
Pnp ( plug’n’play) 라고 부른다.

PnP로 얻는 것

  • 빠른 의존성 검색
의존성이 .yarn/cache에 수평적으로 존재하므로 모든 패키지에 대한 접근 시간이 O(1)이 된다. 따라서 require()에 소요되는 시간이 크게 단축된다.
  • 빠른 설치
압축 파일 단위로 설치되기 때문에 의존성을 구성하는 파일의 수가 절대적으로 감소한다. 여기에 zero-install 전략을 사용하면 아예 설치 과정을 생략할 수 있다.
  • 유령 의존성 방지
호이스팅을 사용하지 않기 때문에 의도하지 않은 의존성이 발생하지 않는다.
# Lerna Lerna는 저수준의 Yarn, npm 위에 있는 고수준 레이어로 볼 수 있다. Yarn으로 모노레포를 구성할 수는 있지만 여러 workspace의 버전 관리, 테스트, 빌드, 배포, 게시 등의 작업은 일일이 구성해야 한다. Lerna는 이러한 작업을 최적화한다.

2022년 Nx의 개발사인 Nrwl이 프로젝트 관리 권한을 인수했다.

프로젝트 생성

npm install --global lerna

프로젝트를 lerna로 초기화한다.
cd path/to/your-project
lerna init

lerna.json

  • version: 각 workspace에 대한 버전을 관리할 수 있다. 개별로 관리하고자 할 때는 "independent"를 입력한다.
  • npmClient: "npm" 또는 "yarn"
  • useWorkspaces: npmClient의 workspace로 관리되도록 한다.

명령어

workspace 추가

lerna create <PACKAGE-NAME> 

패키지 추가
client workspace에 react 패키지를 추가한다.

lerna add react --scope=client 

 --scope 없이 사용하면 모든 workspace에 추가한다.
추가하려는 의존성이 workspace라면 해당 workspace를 제외한 모든 workspace에 추가된다.
client workspace에 common workspace를 추가한다.

lerna add common@0.0.0 --scope=client 

모든 workspace에 대해 npm 스크립트 실행

lerna run <COMMAND_NAME> -- [..args]

이외에도 다양한 명령어가 있는데 공식문서를 찾아보도록 하자.

마무리

오늘은 모노레포의 도구들에 대해서 간략하게 알아봤다.
직접 사용하게 된다면 더 공부해보고 정리를 추가로 해보도록 하겠다.

profile
프론트엔드 개발자 초보에서 고수까지!

0개의 댓글