npm, yarn 둘다 node 환경에서 패키지를 관리해주는 도구 입니다.
주로 yarn을 사용했었는데 어떤 차이점이 있는지 알아보려 합니다.
속도
npm은 의존성 파일을 순차적으로 설치합니다. 이전파일이 설치되고 다음파일을 설치합니다.
a를 설치하고 b를 설치하고 c를 설치하는 형식입니다.
yarn은 의존성 파일들을 병렬적으로 설치합니다. a, b, c를 병렬로 설치합니다.
yarn은 다운받은 패키지들을 캐시에 저장합니다. 중복된 패키지를 설치해야 할 경우 캐시에 저장되어 있다면 캐시를 활용합니다.
캐시를 사용하기 때문에 npm에 비해 디스크의 사용이 더 큽니다
보안성
npm은 의존 관계를 가지는 다른 패키지를 즉시 포함합니다. 편하다는 장점이 있습니다. 하지만 보안문제에서 취약점을 불러올 수 있습니다.
yarn은 yarn.lock이나 package.json 파일에 명시된 것들만 설치를 합니다.
이러한 보안성은 모든 디바이스에 같은 버전의 패키지들이 설치되는 것을 보장하고 버전의 차이로 인한 버그를 방지해줍니다.
- 2010년 : npm이 등장하였습니다.
- 2016년 : yarn이 등장합니다.
npm보다 더 좋은 성능을 보여주었고 패키지들의 버전에 대한 정보를 가진 yarn.lock 파일이 자동으로 생성됩니다.
npm에서는 npm shrinkwrap을 통해 직접 생성해주어야 했습니다. - 2017년 : npm 5 가 등장합니다.
package-lock.json 파일을 자동으로 생성해주고 이전 버전에 비해 속도가 월등히 빨라졌습니다.
이때부터 yarn과 npm의 패키지 설치 속도는 크게 차이가 나지 않게 되었습니다. - 2018년 : npm 6가 등장합니다.
이 버전에서는 보안성이 강화되었습니다.
이제 npm에서 의존성이 설치되기 전에 보안 취약성을 검사하여 설치합니다.(npm audit) - 2020년 : yarn2, npm 7 이 등장합니다.
yarn2 에서는 pnp(plug and play)라는 개념이 도입됩니다. (pnp는 즉시시작이라는 뜻입니다.) - 2021년 : yarn3가 등장하였습니다.
npm 등장
2010년 이전에는 프로젝트의 의존성은 직접 다운로드하고 관리하여야 했습니다.
이러한 불편함에 node js를 개발한 ryan dhar과 함께 npm이 등장합니다.
npm의 방향은 아래와 같습니다.
* 여러 버전의 동일한 패키지를 한 프로젝트에서 사용할 수 있게 하자
* 설치 방식을 통일하자
* 패키지 관련 정보가 들어있는 메타 데이터를 간소화 하자
* 누구나 배포할 수 있도록 하자
npm v3
package hoisting이 등장하게 됩니다.
패키지 의존성 트리에서 공통으로 설치되는 패키지들은 hoisting하여 tree를 flatten하게 만들어 줍니다.
하지만 이런 과정에서 유령 의존성(phantom dependency)가 발생하게 됩니다.
또한 여전히 패키지 트리를 flatten 하게 만드는 알고리즘은 너무 어렵습니다.
위의 사진을 보면 A(1.0), B(1.0) 버전의 패키지는 중복됩니다.
이러한 경우 상단으로 끌어올려 패키지의 중복 설치를 방지합니다.
하지만 package-1에서 B(1.0)를 직접 import 하게 되었습니다.
이러한 현상을 유령 의존성이라 합니다.
yarn
npm의 단점을 보완하기 위해 등장하였습니다.
* lock 파일을 매번 수동으로 생성해주어야 함
* 의존성 트리가 달라질 수 있음
* 느린 설치 속도
yarn은 yarn.lock을 자동으로 생성해 줍니다.
npm에서는 패키지의 설치 순서에 따라 의존성 트리의 변형이 생길수 있었습니다.
yarn에서는 특별한 선택 알고리즘을 도입하여 의존성 트리가 변형되지 않도록 하였습니다.
yarn에서는 설치한 모든 것들을 캐시에 저장합니다.
yarn의 캐시를 확인하려면 /Users/<user>/Library/Caches/yarn의 경로로 이동하면 확인할 수 있습니다.
그래서 npm에 비해 디스크 용량이 요구됩니다.
하지만 캐시를 사용하기에 이미 설치된 패키지들은 다시 설치하지 않아 설치가 더 빠릅니다.
yarn은 설치된 패키지들이 실행되기 전에 checksum을 사용하여 보안을 강화하였습니다.
특징
Offline Mode : 이전에 설치했었던 패키지 들은 다시 설치할때는 offline에서도 설치가 가능합니다.
Deterministic : 설치 순서에 상관없이 같은 의존성 트리가 생성됩니다.
Network Performance : 네트워크 활용을 극도로 하여 큐를 사용하여 네트워크 요청을 효율적으로 관리합니다.
Network Resilience : 하나의 요청이 실패해도 전체 설치과정이 실패하지 않습니다. 실패 이후에 재요청 됩니다.
Flat Mode : 패키지의 중복 생성을 방지하기 위해 서로 다른 버전의 종속성을 단일 버전으로 해결하였습니다.
장점이 많아보이는 yarn에서 등장한 단점은 아래와 같습니다.
yarn install을 하게 되면 아래와 같은 과정을 거치게 됩니다
1. 명시된 버전에서 설치할 의존성 버전이 결정됩니다(semantic version 내에서는 의존성 버전의 범위를 지정할 수 있습니다 ^, ~등 사용)
2. 패키지들의 각 버전이 source로 부터 다운 받아지고 offline mirror에 저장됩니다(offline mirror는 내부의 buffer정도로 이해하였습니다.)
3. offline mirror에서 캐시에 unpacked 됩니다(위에서 언급한 캐시 경로)
4. 캐시에서 node_modules 폴더로 복사됩니다.
-> 4번의 과정은 무거운 I/O 작업입니다. 이러한 작업으로 속도의 저하가 발생할 수 있습니다.
node.js에서는 어떤 모듈을 사용하고자 하면 모듈을 찾기 위해 부모 ~ 루트 까지 node_modules 폴더를 찾는 방식을 사용합니다.
repl 에서 require.resolve.paths('react') 명령어를 사용하게 되면
부모 ~ 루트 까지 node_modules 찾는 경로를 보여줍니다.
패키지를 찾으려고 readdir 같은 느린 I/O 호출이 반복되게 됩니다.
-> 런타임에서 이러한 과정은 속도의 저하를 발생시킵니다.
npm v5
package.lock 파일이 자동으로 생성되게 되었습니다.
이전에는 npm shrinkwrap 명령어를 통해 직접 생성해주어야 하였습니다.
5 버전부터 yarn과의 패키지 설치 속도 차이가 거의 나지 않게 되었습니다.
npm v6
npm은 설치 중간에 패키지들의 보안 취약성을 검사하고 취약성이 발견되면 사용자에게 알려줍니다.
npm audit 명령어를 통해 직접 확인할 수도 있습니다.
만약에 취약성이 발견되면 어떠한 행동을 취해야 하는지 알려주기도 합니다.
yarn berry
yarn version 2가 등장합니다.
위에서 등장한 yarn의 단점을 해결하고자 .pnp.cjs라는 파일을 생성합니다.
.pnp.cjs 파일은 정적인 정보들을 제공해 줍니다.
- 의존성 트리에서 어떤 패키지들이 사용 가능한지
- 패키지들이 어떻게 연결되어 있는지
- 디스크 어디에 위치하여 있는지
yarn berry는 node_modules 폴더를 생성하지 않습니다. 대신 yarn 폴더 아래에 cache 폴더가 생성됩니다.
이곳에 npm registry에서 설치한 파일이 zip 형태로 압축되어 저장됩니다.
.pnp.cjs에서는 이 경로를 가리킵니다.
- cache 파일내의 파일들은 압축되어 저장되므로 기존의 node_modules 폴더보다 훨씬 작은 크기를 가지게 되었습니다.
- yarn/cache에서 copy와 같은 무거운 I/O 작업을 수행하지 않아도 됩니다.
- yarn berry 에서는 cache폴더를 git에 직접 업로드 하기를 추천합니다.
패키지를 설치없이 프로젝트를 동작하게 하기 위함입니다.
설치없이 동작하게 하기 위한 개념을 zero-install이라 합니다. - 모든 의존성 트리는 flatten 되어 집니다. 그리고 의존성 관계는 설치된 hard link로 연결됩니다 (바로가기와 같이)
1 depth로 모든 패키지를 설치하고 .pnp.cjs에서 의존성에 따라 link만 명시해주면 됩니다.
따라서 유령의존성이 해결되었습니다. - 패키지 파일이 어디에 위치하여있는지도 같이 명시가 되어있습니다. 더이상 node에서는 부모 ~ 루트의 node_modules를 탐색하지 않아도 됩니다.
yarn set version berry 명령어를 통해 버전 설정이 가능합니다.
프로젝트의 root directory에서 yarn의 버전을 명시하면 됩니다.
yarn berry가 만능처럼 보이지만 아직 여러 패키지들과의 호환성 문제와 같은 이슈들이 존재한다고 합니다.
이는 이제껏 새로 나오는 패키지들이 그랬듯 언젠가 해결될 문제일것 같습니다.
요번에 npm, yarn 개념을 알아보면서 꽤나 멀리까지 갔는데 yarn berry를 개인 프로젝트에 틈틈이 적용해봐야 겠습니다.
출처: https://medium.com/wantedjobs/yarn-berry-%EC%A0%81%EC%9A%A9%EA%B8%B0-1-e4347be5987
https://www.cleancoder.dev/package-manager-history/
https://www.sitepoint.com/yarn-vs-npm/
https://seogeurim.tistory.com/12?category=981579
https://github.com/yarnpkg/yarn
https://github.com/yarnpkg/rfcs/blob/master/accepted/0000-plug-an-play.md
https://toss.tech/article/node-modules-and-yarn-berry
https://yarnpkg.com/features/pnp
'Frontend > Javascript' 카테고리의 다른 글
React-query 🌱 (1) | 2022.04.09 |
---|---|
Javascript 실행 컨텍스트(Execution Context) (0) | 2022.04.03 |
Javascript custom array 🌹 (0) | 2022.04.02 |
Javascript createObjectURL, revokeObjectURL 🤥 (0) | 2022.04.01 |
Javascript custom event 🐕 (0) | 2022.04.01 |