
node_modules 없이 node를 사용할 수 있는 환경인 yarn berry를 알아보자.
npm, Yarn, pnpm 모두 역할은 대부분 동일하다.
따라서 설치 속도, 스토리지 사용량, 기존 워크플로우와 결합되는 방식 등을 고려해 패키지 매니저를 결정한다.
| Language | Package Manager | Software Repository |
|---|---|---|
| Python | pip | PyPI |
| PHP | Composer | Packagist |
| Node.js | npm, Yarn, pnpm | npm, Yarn, pnpm |
| Java | Maven, Gradle | Maven |
| Ruby | RubyGems, Bundler | RubyGems, Bundler |
node.js 환경의 패키지 매니저로 크게 npm과 yarn, pnpm이 존재하며,
패키지 매니저의 기능은 동일하나 내부적인 차이점이 존재한다.
npm, Yarn : node_modules 폴더에 dependency 설치pnpm : 중첩된 node_modlues 폴더에 dependency를 저장하는 방식을 개선하기 위한 개념 도입Yarn-berry : PnP(Plug'n'Play) 모드 (node_modules X)Yarn Berry는 Node.js를 위한 새로운 패키지 관리 시스템이다.
Yarn v1(Yarn classic)에서 2020.01.25 정식 버전 Yarn v2(Yarn Berry)가 출시되었으며,
현재 Yarn Berry는 Babel을 비롯한 큰 오픈소스 레포지토리에서도 채택되어 사용 중에 있다.
위와 같이 NPM은 Node.js를 설치할 경우 기본적으로 제공되는 패키지 매니저이지만 비효율적이거나, 깨져 있는 부분이 많다.
패키지가 중복으로 설치될 수 있다는 단점 존재
의존성 검색의 비효율성
- 느린 I/O 호출의 반복 → 경우에 따라 I/O 호출의 실패로 이어진다.
환경에 따라 달라지는 동작
- 상위 디렉토리 환경에 따라 의존성 호출의 변수 발생
비효율적인 설치
- 매우 큰 node_modules의 공간 차지
- node_modules디렉토리 구조 구축을 위한 큰 비용의 I/O 작업
유령 의존성
node_modules를 아끼기 위해 호이스팅 기법 사용 (NPM, Yarn v1)
require()할 수 있는 현상 : 유령 의존성package.json의 수정에 따라 의존성 관리 시스템이 혼란스러워질 가능성 ⬆️Yarn Berry는 위에서 언급한 NPM의 "깨져 있는" 패키지 관리 시스템을 개선하고자
적은 공간의 사용, 효율적인 의존성 검색을 목표로 출시되었다.
node_modules 폴더의 특정 패키지를 검색할 경우 모든 패키지를 순회하며 해당 패키지 존재 여부를 찾는 방법은 매우 비효율적이다.
1. Node가 패키지를 검색할 때 잘 찾을 수 있도록 도와주는 역할이 패키지 매니저의 일이라는 생각과
2. 패키지 매니저가 node_modules 디렉터리 구조를 만드는 것에 그치지 않고,
보다 근본적이며 안전한 방법으로 의존성을 관리하는 방법에 대해 고민한 결과
Plug'n'Play가 탄생했다.
Yarn Berry에서는 node_modules를 생성하는 대신 의존성 lookup 파일인 .pnp.cjs를 생성한다.
.pnp.cjs 파일의 포함 내용
- 관련된 패키지 이름
- 패키지 버전
- 디스크에서의 위치
- 의존성 리스트
- etc.
Plug'n'Play 켜기
NPM에서 최신 버전의 Yarn을 내려받은 뒤, 버전을 Berry로 설치해 Yarn Berry를 사용한다.
$ npm install -g yarn
$ cd ../path/to/some-package
$ yarn set version berry
Yarn Berry는 하위호환을 위해 패키지 단위로만 의존성 관리 시스템을 도입할 수 있다.
node_modules를 생성하지 않는 Yarn Berry는 의존성 정보를 .yarn/cache 폴더에 저장한다.
.pnp.cjs 파일에 의존성을 찾을 수 있는 정보가 기록되며, 해당 파일을 통해 Disk I/O 없이 어떤 패키지가 어떤 라이브러리에 의존하는지,
각 라이브러리가 어디에 위치하는지 바로 알 수 있다.
Yarn은 Node.js에서 제공하는 require()문의 동작을 덮어씀으로써 효율적으로 패키지를 검색할 수 있도록 한다.
PnP API를 이용해 의존성 관리를 하고 있을 경우 : yarn node명령어를 사용 (node 명령어 X) Node.js 앱을 실행 시 package.json의 scripts에 실행 스크립트를 등록해 사용한다.
Yarn으로 스크립트를 실행하면 PnP로 의존성을 자동으로 불러온다.
또한 Zip 아카이브로 의존성을 관리할 수 있는데 이를 사용할 경우,
없는 의존성이나 더 이상 필요없는 의존성을 쉽게 찾을 수 있다.
또한 Zip 파일의 내용이 변경될 경우 체크섬과 비교해 쉽게 변경 여부를 감지할 수 있다.
의존성 검색
- 의존성 검색 시 더 이상 node_modules 폴더의 순회가 필요 없다.
- .pnp.cjs파일이 제공하는 자료구조를 이용해 의존성의 위치를 바로 찾는다.
- require()에 걸리는 시간이 크게 단축된다.
재현 가능성
- 패키지의 모든 의존성이 .pnp.cjs 파일을 이용해 관리되기에 더 이상 외부 환경에 영향을 받지 않는다.
의존성을 설치할 때
- 설치를 위한 node_modules 디렉토리 생성이 필요없다.
- zero-install 사용 시 대부분의 라이브러리를 설치할 필요 없이 사용 가능하다.
- 같은 버전의 패키지가 여러번 복사될 필요가 없기에 설치 시간을 극단적으로 단축할 수 있다.
엄격한 의존성 관리
- node_modules와 같이 의존성을 끌어올리지 않는다.
- 각 패키지가 자신이 package.json에 기술하는 의존성에만 접근할 수 있다.
- 예기치 못한 버그를 일으키는 유령 의존성 현상을 막을 수 있다.
의존성 검증
- Yarn PnP에서 Zip파일을 이용해 패키지를 관리하므로 의존성 관리가 용이하다.
- 의존성이 잘못되었을 때 쉽게 바로잡을 수 있다.
Zero-Install
Zero-Install : Yarn Berry에서 의존성을 버전 관리에 포함하는 것Yarn PnP는 의존성을 압축 파일로 관리하므로 의존성 용량이 작다.Yarn install을 실행하지 않아도 된다.Zero-Install 사용 시 .gitignore 파일 설정.yarn/*
!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
여전히 PnP를 지원하지 않는 패키지 존재
프로젝트에 PnP를 지원하지 않는 패키지가 하나라도 존재한다면 PnP 방식일지라도 node_modules가 따라온다.
각 모듈이 PnP로 사용될 수 있기 위해서는 PnP 방식에 맞게 의존성 관리가 strict하게 셋팅되어야 한다.
PnP loose 모드를 통해 명시적으로 요구하는 디펜던시를 요구하지 않도록 할 수 있다.
// .yarnrc.yml
pnpMode: loose
우선 PnP를 적용해 기존 npm의 node_modules디렉토리의 설치가 필요 없이
패키지 환경을 구축할 수 있다는 점이 가장 큰 매력이라고 생각하였다.
매번 npm 또는 yarn으로 패키지 환경을 셋팅하면 git 상에서 clone을 받아 저장소의 코드를 사용할 때
npm install 및 yarn install명령어를 통해 의존성을 관리해주었어야 했는데,
공간 차지 및 설치의 번거로움이 해소되었다는 점이 정말 유익하다고 판단된다.
Yarn Berry를 아직 제대로 된 프로젝트에 도입해보지 않았기에, 관련된 단점을 구글링으로 찾을 수 밖에 없었는데
대부분의 단점 혹은 트러블슈팅은 아직 PnP를 지원하지 않는 패키지 또는 PnP-dependency와 관련된 부분이었다.
이러한 문제점은 직접 프로젝트를 통해 겪어보는 것이 어떤 방법 보다도 잘 이해할 수 있으리라는 생각이 들었고,
빠르게 Yarn Berry 셋팅을 해본 뒤 PnP를 적용해 본 패키지 매니저의 환경을 피부로 느껴보고자 한다.