Yarn 을 통한 workspace 구현하기

CUBE·2023년 10월 29일
0

Yarn workspace 필드를 사용해 간단히 모노레포를 구성할 수 있다.

yarn link 혹은 npm link 기능을 선언적으로 사용하는 것으로 node_modules 디렉터리에 workspace 에 대한 심볼릭 링크가 생성된다. 이를 통해 하나의 저장소에 있는 여러 프로젝트가 서로 쉽게 상호 참조 할 수 있다.

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

worktree 선언

  • worktree 를 구성하는 workspace 의 위치를 glob 패턴의 배열로 나타낸다. packages 폴더 내의 모든 폴더가 workspace 가 되도록하려면 다음과 같이 설정한다.

package.json

{
    "private": true,
    "workspaces": ["packages/*"]
}

Yarn 1.x 에서는 private: true 필드 값이 필수 이지만, 2.x 이상에서는 필수가 아니다.

workspace 추가

그림과 같이 client, server, common 세 개의 workspace 를 추가하고 루트 경로에서 yarn 명령을 실행하면 루트 경로에 node_modules 디렉터리에 workspace들에 대한 심볼릭 링크가 생성된다.

Untitled

workspace에 대한 명령 실행

yarn workspace

yarn workspace <WORKSPACE_NAME> <COMMAND_NAME>

workspace 를 의존성으로 추가

client 패키지가 common 패키지를 의존하게 하려면 package.json에 의존성을 명시하거나 바로 위에서 설명한 yarn workspace 명령을 이용하면 된다.

yarn workspace client add common@1.0.0

npm 레지스트리에 publish 된 common 이란 이름의 패키지가 있다 해도, 의존성 버전을 충복한다면 로컬에 존재하는 common workspace 를 우선하여 설치한다.

client에서 common 의존성을 잘 부르는지 확인하기 위해 다음 명령을 실행해 보면 common의 hello() 함수가 client 에서 호출되는 것을 확인할 수 있다.

yarn workspace client run start

Untitled

workspace 의존 관계 확인

yarn workspace info 명령을 실행해 workspace들의 의존 관계를 알아볼 수 있다.

Yarn 2.x 이후에는 yarn workpsaces list 를 사용한다.

yarn workspaces info

Untitled

모든 workspace에 대해 명령 실행

yarn workspaces run \를 사용하면 모든 workspace에 대해 명령을 실행할 수 있다.
다음 명령은 모든 workspace들을 순회하며 test 스크립트를 실행한다.

yarn workspaces run test 

Yarn 2.x 이후에는 yarn workspaces foreach \ 를 사용한다.

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

workspace가 아닌 루트 프로젝트에 의존성을 추가하려면 다음 명령을 실행한다.

yarn add <package_name> -w 

호이스팅(의존성 끌어올리기)

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

Untitled

모노레포에서의 구조는 다음과 같다.

Untitled

일부 모듈 로더는 심볼릭 링크를 지원하지 않기 때문에 B(2.0)을 탐색할 수 없다.
이 때는 nohoist 필드를 사용하면 된다.

{
    "workspaces": {
        "packages": ["packages/*"],
        "nohoist": [ "**/react-native" ]
    }
}

그 외의 Yarn 1.x에 대한 명령어는 CLI Introduction 에서 확인할 수 있다.

Yarn Berry (2.x, 3.x)

https://yarnpkg.com/cli

Yarn workspace를 도입하려고 할 때 성능면에서 Yarn Berry를 함께 검토해 볼 수 있다. Yarn Berry는 yarn의 두 번째 버전으로, 2018년 9월 yarn의 RFC 저장소에서 시작되었다. Yarn 1.x의 주요 개발자인 Mael Nison에 의해 TypeScript로 개발되었고 2020년 1월 25일 정식 버전이 출시되었다. Yarn 1.x는 v1.22.17에서 코드 프리징되었고 https://github.com/yarnpkg/berry 에서 2022.03.09 현재 v3.2.0이 출시되었다.

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를 찾지 못하는 오류가 발생한다.

!https://d2.naver.com/content/images/2022/04/0a710dbd-7f96-14ab-817f-aa4f08550681.png

Yarn Berry의 해결 방법 PnP

어떤 프로젝트를 구성하는 의존성은 결정적(deterministic)이다. Berry는 node_modules에 패키지 파일을 저장하는 대신 패키지의 압축 파일을 .yarn/cache 폴더에 수평적으로 저장하는 방식으로 위 문제를 해결했다. 이 방식을 Yarn은 Plug’n’Play(PnP)라고 부른다. 압축 파일은 ZipFS를 이용하며 해당 모듈 로드가 필요할 때 메모리에서 압축을 해제하여 접근한다.

PnP로 얻는 것

  • 빠른 의존성 검색 의존성이 .yarn/cache에 수평적으로 존재하므로 모든 패키지에 대한 접근 시간이 O(1)이 된다. 따라서 require()에 소요되는 시간이 크게 단축된다.
  • 빠른 설치 압축 파일 단위로 설치되기 때문에 의존성을 구성하는 파일의 수가 절대적으로 감소한다. 여기에 zero-install 전략을 사용하면 아예 설치 과정을 생략할 수 있다.
  • 유령 의존성 방지 호이스팅을 사용하지 않기 때문에 의도하지 않은 의존성이 발생하지 않는다.

    zero-install 전략

    https://github.com/yarnpkg/berry/tree/master/.yarn/cache !https://d2.naver.com/content/images/2022/04/0a710dbd-7f96-14ab-817f-aa4f85570687.png 하나의 압축 파일로 의존성을 관리하고 이 파일을 git으로 관리하면 설치 과정을 제거할 수 있는데 이와 같은 전략을 zero-install이라 한다. 이 전략의 장점은 다음과 같다.
profile
엄마이오빠이상해

0개의 댓글