yarn 2라고도 알려진 yarn의 새로운 버전이 2020년 세상에 나왔습니다.
node_modules 폴더에 특정 패키지를 찾을 때 모든 패키지를 돌아다니면서 해당 패키지가 있는지 찾아봐야 합니다. 이 방법은 다음과 같은 이유로 비효율적입니다.
- node_modules에 많은 파일이 있을 수 있습니다.
- node_modules는 패키지 설치 시에 비용이 큰 I/O작업을 발생시킵니다. 따라서 node_modules를 최적화에 집중하기 벅찹니다.
- Node는 패키지를 잘 알지 못하기 때문에 어떤 패키지에 접근해야 하는지 알 수 없습니다. package.json에 빠진 패키지의 경우 개발할 때에는 잘 동작하다가도 나중에 프로덕션에서 깨지는 경우가 발생합니다.
Node가 패키지를 찾을 때 잘 찾을 수 있도록 도와주는 것이 패키지 매니저의 일이 아닌가란 생각에서 Plug'n'Play
가 탄생했습니다.
Yarn berry는 node_modules
폴더 대신에 .pnp.cjs
파일을 만듭니다.
이 파일에는 관련된 패키지 이름과 버전, 디스크에서의 위치 그리고 의존성 리스트 등이 적혀있습니다. 여기 있는 내용을 통해 Yarn berry는 Node에게 '네가 찾는 패키지는 여기에 있어"라고 바로 알려줄 수 있습니다. 덕분에 설치가 매우 빨라집니다. Yarn berry는 수많은 파일을 설치하는 대신에 한 개의 텍스트 파일을 만들고 고치면 됩니다. 또한 Yarn berry에서는 패키지를 zip
형태로 .yarn/cache
에 저장합니다. 그래서 설치가 더 빨라집니다.
NPM에서 최신 버전의 Yarn을 내려받고, 버전을 Berry로 설정하면 Yarn Berry를 사용할 수 있습니다.
$ npm install -g yarn
$ cd ../path/to/some-package
$ yarn set version berry
Yarn Berry는 기존 Node.js 의존성 관리 시스템과 많이 다르기 때문에 하위호환을 위해 패키지 단위로만 도입할 수 있습니다.
.yarn/cache
폴더에 의존성의 정보가 저장되고 .pnp.cjs
파일에 의존성을 찾을 수 있는 정보가 기록됩니다. .pnp.cjs를 이용하면 디스크 I/O없이 어떤 패키지가 어떤 라이브러리에 의존하는지 각 라이브러리는 어디에 위치하는지를 바로 알 수 있습니다.
Yarn은 Node.js가 제공하는 require()
문의 동작을 덮어씀으로서 효율적으로 패키지를 찾을 수 있도록 합니다. 이 때문에 PnP API를 이용하여 의존성 관리를 하고 있을 때에는 node
명령어 대신 yarn node
명령어를 사용해야 합니다.
일반적으로 Node.js 앱을 실행할 때에는 package.json의 scripts에 실행 스크립트를 등록하여 사용하게 됩니다. 이때 Yarn v1에서 사용하던 것처럼 Yarn으로 스크립트를 실행하기만 하면 자동으로 PnP로 의존성을 불러옵니다.
Zip 아카이브로 의존성을 관리하면 다음과 같은 장점이 생깁니다.
더 이상 node_modules 디렉토리 구조를 생성할 필요가 없기 때문에 설치가 신속히 완료됩니다.
각 패키지는 버전마다 하나의 Zip 아카이브만을 가지기 때문에 중복해서 설치되지 않습니다. 각 Zip 아카이브가 압축되어 있음을 고려할 때, 스토리지 용량을 크게 아낄 수 있습니다.
의존성을 구성하는 파일의 수가 많지 않으므로, 변경 사항을 감지하거나 전체 의존성을 삭제하는 작업이 빠릅니다.
- 없는 의존성이나 더 이상 필요없는 의존성을 쉽게 찾을 수 있습니다.
- Zip 파일의 내용이 변경되었을 때에는 체크섬과 비교하여 쉽게 변경 여부를 감지할 수 있습니다.
의존성을 검색할 때, 더 이상 node_modules 폴더를 순회할 필요가 없습니다.
.pnp.cjs
파일이 제공하는 자료구조를 이용하여 바로 의존성의 위치를 찾기 때문입니다. 이로써 require()에 걸리는 시간이 크게 단축되었습니다.
패키지의 모든 의존성은 .pnp.cjs 파일을 이용하여 관리되기 때문에 더 이상 외부 환경에 영향받지 않습니다. 이로써 다양한 기기 및 CI 환경에서 require() 또는 import문의 동작이 동일할 것임을 보장할 수 있게 되었습니다.
더 이상 설치를 위해 깊은 node_modules 디렉토리를 생성하지 않아도 됩니다. 또 NPM이 설치하는 것처럼 같은 버전의 패키지가 여러 번 복사되어 설치되는 설치 시간을 극단적으로 단축할 수 있습니다. 이에 더해 Zero-install을 사용하면 대부분 라이브러리를 설치 없이 사용할 수 있습니다.
이를 이용하면 CI와 같이 반복적으로 의존성 설치 작업이 이루어지는 곳에서 시간을 크게 절약할 수 있습니다.
Yarn PnP는 node_modules에서와 같이 의존성을 끌어올리지 않습니다. 이로써 각 패키지들은 자신이 package.json에 기술하는 의존성에만 접근할 수 있습니다. 기존에 환경에 따라 우연히 작동할 수 있었던 코드들이 보다 엄격히 관리되는 것입니다. 이로써 예기치 못한 버그를 쉽게 일으키던 유령 의존성 현상을 근본적으로 막을 수 있었습니다.
node_modules를 사용하여 의존성을 관리했을 때에는 올바르게 의존성이 설치되지 못해서 의존성 폴더 전체를 지우고 다시 설치해야 하는 경우가 발생하고는 했습니다. node_modules 폴더를 검증하기 어려웠기 때문입니다. 전체 재설치를 수행할 때 node_modules 디렉토리 구조를 다시 만드느라 1분 이상의 시간이 허비되기도 했습니다.
Yarn PnP에서는 Zip 파일을 이용하여 패키지를 관리하기 때문에 빠진 의존성을 찾거나 의존성 파일이 변경되었음을 찾기 쉽습니다. 이로써 의존성이 잘못되었을 때 쉽게 바로잡을 수 있습니다. 이로써 올바르게 의존성이 설치되는 것을 100%에 가깝게 보장할 수 있습니다.
(Yarn Berry에서 의존성을 버전 관리에 포함하는 것)
Yarn Pnp은 의존성을 압축 파일로 관리하기 때문에 의존성의 용량이 작습니다. 따라서 Yarn Berry를 사용하면 의존성을 Git으로 관리할 수 있습니다. 그리고 이렇게 의존성의 버전을 관리할 때 더욱 큰 장점들을 발견할 수 있습니다.
새로 저장소를 복제하거나 브랜치를 바꾸었다고 해서 yarn install을 실행하지 않아도 된다. 또한 네트워크가 끊어진 곳에서는 오프라인 캐시 기능을 해주기도 한다.
CI에서 의존성 설치하는 시간을 크게 절약할 수 있습니다.
yarn init -2 yarn add [라이브러리명] --dev
출처: https://next.yarnpkg.com/advanced/pnpify
- eslint, typescript를 사용한다면 필수로 진행
yarn dlx @yarnpkg/sdks vscode
gitignore (Zero-Install 사용 ⭕️)
.yarn/* !.yarn/cache !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks !.yarn/versions
gitignore (Zero-Install 사용 ❌)
.yarn/* !.yarn/patches !.yarn/releases !.yarn/plugins !.yarn/sdks !.yarn/versions .pnp.*
node index.js
로 실행했다면 pnp에서는 yarn node index.js
로 실행.CMD ["node", "index.js"] => CMD["yarn", "node", "index.js"]