npm
-> Yarn Berry
Yarn Berry
로 변경하였습니다. 이번 시간에는 Yarn Berry
에 대해 알아보면서 Yarn Berry
를 사용하면서 느낀 장단점을 공유하고자 합니다.Yarn Berry
의 사용방법을 정리한 글이 아닌 Yarn Berry
를 사용하면서 느낀 장단점을 공유하는 글입니다.Yarn Berry
를 사용하실 계획이라면 한 번쯤 읽어 보시는 것을 추천드립니다.Yarn Berry
란 2020년 1월에 출시된 Yarn Classic
의 업그레이드 버전입니다. yarn 팀에서는 본질먹인 새로운 코드 베이스와 새로운 원칙을 가진 완전리 새로운 패키지 매니저라는 것을 분명하게 하기 위해 Yarn Berry
라고 이름을 붙였습니다.Yarn Berry
나 yarn classic
, npm
, pnpm
등 모든 패키지 매니저의 역할은 동일합니다. 매키지 매니저의 역할은 다음과 같습니다.npm
의 문제점Yarn Berry
를 사용했을까요?npm
의 문제점을 알아보겠습니다.미처버린 node_modules...
npm
이 관리하는 node_modules
는 비효율적이고 무겁습니다.npm
의 비효율적인 의존성 탐색에 있습니다.npm
은 의존성을 탐색할 때, node_modules
를 탐색하고, 없으면 상위 디렉토리로 올라가서 다시 node_modules
를 탐색합니다.node_modules
를 찾지 못하고 프로젝트의 루트 디렉토리까지 올라가게 됩니다.npm
은 중복해서 설치되는 node_modules
를 아끼기 위해 호이스팅 기법을 사용합니다.중복 모듈 A(1.0)과 B(1.0)을 root node_modules에 호출
B(1.0)
이 root node_modules
에 설치됩니다.B(1.0)
은 require 할 수 없어야 하지만 의존성 탐색을 통해 설치되지 않은 B(1.0)
을 root node_modules
에서 찾아서 사용할 수 있습니다.저또한 lodash 라이브러리를 설치하지 않고 사용한 경험이 있습니다.
이는 `npm`의 호이스팅 기법으로 인해 발생한 문제였습니다.
PnP
(plug n play)Yarn Berry
는 위에 언급한 문제를 해결하기 위해 PnP
라는 새로운 패러다임을 도입했습니다.PnP
는 node_modules
를 사용하지 않고, 패키지의 종속성을 프로젝트 단일 디렉토리 트리(.yarn/cache
)에 직접 설치합니다..pnp.cjs
파일에 저장되며 이를 통해 디스크 I/O 없이 어떤 패키지가 어떤 라이브러리에 의존하는지, 각 라이브러리는 어디에 위치하는지 바로 알 수 있습니다.react@18.2.0
을 설치한다면 .pnp.cjs
파일에 다음과 같이 저장됩니다.1 // react 패키지 중에서
2 ["react", [
3 // npm:18.2.0 버전을 설치하고
4 ["npm:18.2.0", {
5 // 해당 위치에 존재하며
6 "packageLocation": "./.yarn/cache/react-npm-18.2.0-1eae08fee2-88e38092da.zip/node_modules/react/",
7 // 해당 패키지의 의존성은 다음과 같다.
8 "packageDependencies": [
9 ["react", "npm:18.2.0"],
10 ["loose-envify", "npm:1.4.0"]
11 ],
12 "linkType": "HARD"
13 }]
14 ]],
PnP
시스템에서 각 의존성은 Zip 아카이브로 관리됩니다.React@18.2.0
을 설치하면 다음과 같은 압축파일로 관리됩니다.1.yarn/cache/react-npm-18.2.0-1eae08fee2-88e38092da.zip
.pnp.cjs
파일이 지정하는 바에 따라 동적으로 Zip 아카이브의 내용이 참조됩니다.PnP
는 다음과 같은 장점을 가집니다.node_modules
를 사용하지 않기 때문에 설치가 빠르게 완료됩니다.Yarn Berry
를 도입하면서 얼마나 성능이 향상되었는지 npm
과 비교해보겠습니다.node_modules
vs .yarn
npm
을 사용할 때는 node_modules
를 사용하기 때문에 자연스럽게 프로젝트의 용량이 커졌습니다.node_modules
의 용량은 다음과 같습니다.1# client
2$ du -sh node_modules
3614M node_modules
4
5# server
6$ du -sh node_modules
7465M node_modules
Yarn Berry
를 사용하면서 생성된 .yarn
디렉토리의 용량을 확인해 보겠습니다.1# client
2$ du -sh node_modules
3324M .yarn
4
5# server
6$ du -sh node_modules
768M .yarn
분류 | npm | Yarn Berry | 증감(%) |
---|---|---|---|
클라이언트 | 614MB | 324MB | 약 48% |
서버 | 465MB | 68MB | 약 86% |
npm
을 사용할 때와 Yarn Berry
를 사용할 때의 docker image
빌드 시간/용량을 비교해 보겠습니다.npm
을 사용할 때의 docker image
빌드 시간은 다음과 같습니다.1# client
2$ docker build --no-cache -t prev_front .
3[+] Building 191.8s (12/12) FINISHED
4
5# server
6$ docker build --no-cache -t prev_back .
7[+] Building 88.8s (12/12) FINISHED
Yarn Berry
를 사용할 때의 docker image
빌드 시간을 확인해 보겠습니다.1# client
2$ docker build --no-cache -t front .
3[+] Building 132.1s (22/22) FINISHED
4
5# server
6$ docker build --no-cache -t back .
7[+] Building 32.2s (26/26) FINISHED
npm
을 사용할 때의 docker image
용량은 다음과 같습니다.1# client
2$ docker images -f "reference=prev_front"
3REPOSITORY TAG IMAGE ID CREATED SIZE
4prev_front latest 40b0156a361d About a minute ago 742MB
5
6# server
7$ docker images -f "reference=prev_back"
8REPOSITORY TAG IMAGE ID CREATED SIZE
9prev_back latest 48dae3e2081c About a minute ago 453MB
Yarn Berry
를 사용할 때의 docker image
용량을 확인해 보겠습니다.1# client
2$ docker images -f "reference=front"
3REPOSITORY TAG IMAGE ID CREATED SIZE
4front latest 43ef86c4c320 About a minute ago 591MB
5
6# server
7$ docker images -f "reference=back"
8REPOSITORY TAG IMAGE ID CREATED SIZE
9back latest cff45f3475a6 About a minute ago 188MB
npm
을 사용할 때의 docker image
용량에 비해 상당히 줄어든 것을 확인할 수 있습니다.분류 | npm | Yarn Berry | 증감(%) |
---|---|---|---|
클라이언트 | 742MB (191.8s) | 591MB (132.1s) | 약 20% |
서버 | 453MB (88.8s) | 188MB (32.2s) | 약 58% |
github action
을 통해 CI/CD를 진행할 때의 빌드 시간을 비교해 보겠습니다.npm
을 사용할 때의 빌드 시간은 다음과 같습니다.Dockerfile
을 제외하고 동일하기 때문에 jobs
의 build step
만 비교하겠습니다.deploy.yml
파일이 궁금하신 분들은 다음 링크를 참고해주세요.steps | npm | Yarn Berry | 증감(%) |
---|---|---|---|
Install the project dependencies | 43s | 55s | 약 127% |
Docker build & push to push | 6m 40s | 3m 26s | 약 48% |
Yarn Berry
가 약 27% 더 느렸습니다.steps | npm | Yarn Berry | 증감(%) |
---|---|---|---|
Install the project dependencies | 19s | 6s | 약 68% |
Docker build & push to push | 1m 47s | 1m 11s | 약 33% |
분류 | npm | Yarn Berry | 증감(%) |
---|---|---|---|
클라이언트 | 8m 19s | 5m 44s | 약 31% |
서버 | 3m 4s | 2m 4s | 약 32% |
Yarn Berry
는 무조건 좋을까요? 글쎄요... 다음으론 제가 사용하면서 느낀 단점을 정리해보겠습니다.Yarn Berry
를 사용한다면 초기 설정을 진행해야 합니다. 이때 초기에 많이 해매는 부분이 있었는데 바로 typescript sdk
, eslint
, prettier
설정이었습니다.Yarn Berry
를 우아한테크캠프를 진행하면서 알게 되었습니다. 일주일이라는 짧은 시간안에 해당 기술을 녹여내야했기 때문에 초기설정에 많은 시간을 할애할 수 없었습니다.Yarn Berry
는 초기 설정해야되는 부분이 많았고 vscode를 사용한다면 typescript sdk
설정을 진행해야하는 점, sdk 설정이전 eslint
와 prettier
를 install하고 sdk를 설정해야했으며 이를 위해 각 워크스페이스의 typescript
, eslint
, prettier
버전을 맞춰줘야 했습니다.Yarn Berry
를 처음 사용한다면 겪을 수 있는 문제라고 생갹하여 단점으로 정리했습니다. 만약 Yarn Berry
를 사용하신다면 사용 이전에 충분히 설치 방법, 동작 등을 숙지하시고 진행하는 것을 추천드립니다..git
이 무거워요...Yarn Berry
의 단점을 설명하는데 뜬금없이 .git
에 대한 얘기가 나왔습니다. 해당 부분은 아래 이미지를 확인하시면 이해가 되실 것 같습니다.왼쪽: 이전 프로젝트 / 오른쪽: 현재 프로젝트
.git
디렉토리보다 현재 프로젝트의 .git
디렉토리가 무거워진 것을 확인할 수 있습니다. (심지어 왼쪽은 client, server의 커밋 내역까지 포함되어 있습니다.).yarn/cache
디렉토리에 대한 변경사항이 커밋내역으로 존재하기 때문에 발생하는 문제입니다.Yarn Berry
를 사용하는 궁극적인 이유는 성능적인 이점을 가져가기 위함이여서 이러한 단점을 크게 신경쓰지 않았지만 의존성 버전 업데이트 등 Dependency Tree에 변경사항이 생길때마다 change 파일의 개수가 급격하게 증가했습니다.eslint
, prettier
가 적용되는 과정에서 추가적인 시간이 소요되는 등의 문제가 발생하기도 했습니다..yarn/cache 삭제시 1583개의 file change가 발생합니다
Yarn Berry
는 .yarn/cache
디렉토리에 의존성 정보를 담고 있습니다. github repository를 clone할 경우 이미 .yarn/cache
디렉토리에 의존성 정보가 존재하기 때문에 yarn install
을 진행하지 않아도 프로젝트를 실행할 수 있다고 설명했습니다.Pnp
를 지원하지 않거나 현재 환경에 대한 바이너리 정보를 가지고 동작해야하는 Dependency들(파일 쓰기, 스크립트 실행 등)은 install시 .yarn/cache
디렉토리에 zip파일 형태로 저장되는 것이 아닌 .yarn/unplugged
디렉토리에 별도의 바이너리 파일로 관리됩니다..yarnrc.yml
파일에 enableScripts: false
로 설정해주는 방법입니다. (물론 PnP
자체를 지원하지 않는 라이브러리들은 .yarn/unplugged
에 생성됩니다.)github action
에서의 성능 비교 부분에서 client 측 install time이 이전 프로젝트보다 현재 프로젝트가 약 27% 더 느렸습니다. 이는 github 상에 존재하지 않는 .yarn/unplugged
패키지 들을 install 하기 위함이었습니다.겨우 3개의 파일을 설치하는데 46초라는 시간이 걸렸네요..
.yarn/unplugged
가 필요 없어지는 경우도 있고 현재 저의 블로그 또한 .yarn/unplugged
가 없더라도 정상적으로 동작합니다. 하지만 sharp
라이브러리를 통해 이미지를 최적화하기 위해서 .yarn/unplugged
를 사용하였습니다.1$ du -hs unplugged
2241.7M unplugged
.yarn/unplugged
디렉토리 용량입니다. 이는 현재 프로젝트의 .yarn/cache
디렉토리 용량의 약 50%에 해당합니다. 프로젝트가 리눅스 환경에서 동작하보니 .yarn/unplugged
디렉토리의 용량이 굉장히 크게 증가한 모습입니다. (local에서 생성된 디렉토리보다 약 50% 정도 증가했습니다.)npm
을 사용할 때는 클라이언트, 서버를 빌드할 경우 해당 빌드파일을 그대로 사용 가능했습니다.tsc
를 통해 빌드된 js
파일을 실행하기만 하면 되었습니다.Yarn Berry
를 사용하면서 클라이언트, 서버를 빌드할 경우 .pnp.cjs
에 저장된 의존성 트리를 통해 라이브러리를 참조하기 때문에 .yarn/cache
디렉토리 등 추가적인 파일들을 COPY 함으로써 이미지 용량이 증가하였습니다.npm
을 사용하여 docker image를 재생성한다면 image size를 절반 이하로 줄일 자신이 있기 때문에 Yarn Berry
를 사용한 image size와 관련해선 크게 이점을 가졌다고 생각하지 않습니다. (서버 측은 제외입니다.)Yarn Berry
를 도입하면서 성능적인 이점을 굉장히 많이 봤다고 생각합니다. Zero Install을 통해 가장 중점적으로 생각했던 build time을 크게 줄일 수 있었었고 새로운 기술을 도입하면서 개발 능력 또한 향상시킬 수 있었습니다. (서버 측이 굉장히 큰 성능적 이점을 가질 수 있었습니다.)Yarn Berry
는 Zero Install을 제외하고도 굉장히 많은 기능이 존재하며 효율적으로 프로젝트를 관리할 수 있습니다. Yarn
에서 제공하는 플러그인, workspace 등의 수많은 기능들을 통해 앞으로 개발에 있어 밑바탕이 될 것이라고 생각합니다.Yarn Berry
에 대한 사용후기는 여기까지 하겠습니다. 감사합니다.