npm vs yarn vs pnpm vs yarn2
pnpm은 정말로 탄소절감과 ssd수명에 도움을 줄까?
2020/12/19
서론
타입스크립트를 사용하면서 백엔드를 개발하면서 googleapis@39.2
를 사용하던 도중, 의존성으로 함께 설치되는 google-auth-library@3.0.0
의 타입을 가져오는데 의문을 가지게 되었다.
// npm 으로 설치해서 사용하는 상황
import { google } from 'googleapis';
import { OAuth2Client } from 'google-auth-library';
const auth: OAuth2Client = new google.auth.OAuth2();
의존성으로 가져오는 버전 말고 다른 버전을 별도로 설치하고 있었다면 어떻게 되는거지? 싶어서 google-auth-library
의 최신버전을(6.1.3) 추가로 설치해보았고, 역시나 아래와 같이 잘못된 버전의 타입을 가져오면서 TS2739 에러가 났다.
위의 에러를 해결하기 위해서는 어쩔 수 없이 googleapis/node_modules/google-auth-library
를 통해 접근해야 했다. (이게 맞는건가? 싶었다)
그러던 어느날 reason-seoul 레포에 다음과 같은 흥미로운 문구가 있어서 javascript의 패키지 매니징 도구들에 대해 알아보는 시간을 가지기로 했다.
저장소는 탄소를 절감하고 우리들의 SSD 수명을 조금 더 보존하기 위해 pnpm 패키지 매니져를 사용하고 있습니다 😉
비교
쉬운 비교를 위해 위에서 설명한 패키지를 다음과 같이 이름 지어서 설명하겠다.
foo@39
:googleapis@39
bar@3.0.0
:google-auth-library@3.0.0
(googleapis의 의존성)bar@6.1.3
:google-auth-library@6.1.3
npm
1. foo@39 설치
- node_modules 하위에
foo
,bar
가 flat하게 설치되었다.
2. bar@6.1.3 설치
- 기존
node_modules
/bar
폴더의 내용이foo
/node_modules
/bar
로 즉시 이동(mv)하는것이 아닌,bar@3.0.0
삭제 후 그 위치에 새로bar@6.1.3
을 설치하고,foo
/node_modules
/bar
경로에bar
가 새로 설치되었다. 단순히 mv가 아닌 삭제라고 결론내린 이유는,bar@6.1.3
설치 전에bar@3.0.0
하위에 새로운 파일을 생성해보고,bar@3.0.0
이 가지고있는 README.md 파일에 수정을 가한 뒤에bar@6.1.3
을 설치했기 때문이다.물론 git reset --hard 후에 이동시켰을 가능성도 없지는 않다.
3. bar@6.1.3 삭제
node_modules
/bar
폴더가 제거되었고,node_modules
/foo
/node_modules
/bar
가node_modules
/bar
로 돌아오지는 않았다.
4. bar@3.0.0을 수동으로 설치
node_modules
/bar
경로에bar@3.0.0
이 설치되었다.node_modules
/foo
/node_modules
/bar
에는 똑같은 버전의bar@3.0.0
이 남아있어서 같은 버전의 패키지가 중복으로 존재하게 된다.
뭔가 아래의 짤이 생각난다...
yarn (version 1을 다룹니다)
1. foo@39 설치
- npm과 마찬가지로 node_modules 하위에
foo
,bar
가 flat하게 설치되었다.
2. bar@6.1.3 설치
- npm으로 설치했을 때와 마찬가지로 동작하였다.
3. bar@6.1.3 삭제
node_modules
/bar
에 설치되어있던bar@6.1.3
이 삭제되고,node_modules
/foo
/node_modules
/bar
하위폴더에 있던bar@3.0.0
이 삭제되고, 처음 설치 위치인node_modules
/bar
에 다시 설치되어foo
와 flat한 위치에 존재하게 되었다.
4. foo@39가 의존성을 가지는 bar@3.0.0 수동으로 설치
node_modules
/bar
에 같은 버전이 존재하기 때문에 아무 일도 일어나지 않았다.
pnpm
1. foo@39 설치
foo@39
(정확히는googleapis@39.2.0
) 의 package.json에는bar@3.0.0
이 의존성으로 명시되었지만,^3.0.0
으로 명시되어있기 때문에3.0.0>=
<4.0.0
에 해당하는 버전중 최신버전인bar@3.1.2
가 설치되었다. caret ranges참고
node_modules
하위에foo
폴더가 생기고, 의존성을 가지는 패키지들은node_modules
/.pnpm
폴더안에 각각의 버전이 포함된 이름 폴더가 생성되었다.
.pnpm
/bar@3.1.2
/node_modules
/base64-js
폴더와 같은 내용이.pnpm
/base64-js@1.5.1
에 존재하는 것을 확인했는데,심볼릭 링크
인 것을 확인하였다.
- 사실
node_modules
하위에 있는 폴더들도.pnpm
에서 가져온 것들임을 확인할 수 있다.
(설치되는 모든 버전들은 .pnpm에 관리되고, 코드에서 사용할 것들만 node_modules에 심볼릭 링크 형태로 생성되는 것이다)
2. bar@6.1.3 설치
node_modules
/bar
폴더가 생성되었고,node_modules
/.pnpm
폴더에 새로 설치된bar@6.1.3
의 의존성 패키지가 추가되었다.
(이미 설치된 버전이 있다면, 새로 설치되지 않을 것으로 추측된다.)
3. bar@6.1.3 삭제
node_modules
/bar
폴더가 삭제되고,node_modules
/.pnpm
폴더에 설치되었던bar@6.1.3
의 의존성 패키지가 사라지며,.pnpm
에는 1번 과정에서 설치되었던 폴더만 남아있게 되었다.
4. foo@39의 의존성으로 설치된 bar@3.1.2 수동으로 설치
bar@3.1.2
를 수동으로 설치해본 결과,.pnpm
에 존재하던bar@3.1.2
의 심볼릭 링크가node_modules
/bar
로 생성되었다.
추가자료 (yarn 2)
![](https://user-images.githubusercontent.com/34048253/102710108-63930e00-42f3-11eb-8d20-cd806029f87c.png)
블로그 내용을 공유하던 도중 yarn 2의 정보를 알게 되었다.
yarn 2는 한 폴더에 패키지를 몰아넣을 뿐만 아니라 .yarn/cache
폴더에 zip파일 형태로 관리하고 .pnp.js
파일에 해당 패키지(또는 의존성 패키지)의 이름
, 버전
, 경로
등의 정보를 저장하여 node_modules에서 발생하던 문제 뿐만 아니라, 각 패키지별 폴더 조차 생성하지 않아서 pnpm보다 더 좋아보인다.
import error (TS2307)
의 해결방법은 잘 모르겠다
// .pnp.js 파일의 일부
function $$SETUP_STATE(hydrateRuntimeState, basePath) {
return hydrateRuntimeState({
"packageRegistryData": [
["google-auth-library", [
["npm:6.1.3", {
"packageLocation": "./.yarn/cache/google-auth-library-npm-6.1.3-ecb4934df9-ddf0289860.zip/node_modules/google-auth-library/",
"packageDependencies": [
["google-auth-library", "npm:6.1.3"],
...
["lru-cache", "npm:6.0.0"]
],
"linkType": "HARD",
}]
]],
["googleapis", [
["npm:66.0.0", {
"packageLocation": "./.yarn/cache/googleapis-npm-66.0.0-5fed4fcc24-b3d80d94e5.zip/node_modules/googleapis/",
"packageDependencies": [
["googleapis", "npm:66.0.0"],
["google-auth-library", "npm:6.1.3"],
["googleapis-common", "npm:4.4.3"]
],
"linkType": "HARD",
}]
]]
]
}, {basePath: basePath || __dirname});
}
결론
dependency를 한곳에서 관리하면서 동일 버전의 중복생성이나 같은 이름 다른버전의 dependency 생성시 패키지가 삭제되었다가 다른 위치에 새로 생성되는 등의 불필요한 I/O 과정을 없애는 것으로 pnpm의 장점을 확실히 알게 되었다.
이로써 reason-seoul 레포에서 설명한 탄소 절감 및 SSD의 수명을 위해서 pnpm을 사용한다는 이유도 충분히 납득이 되었다.
하지만 pnpm 사용시 dependency가 설치되어있는 node_modules에 접근이 불가능한 점이 있는데, 애초에 npm, yarn사용시 그러한 디렉토리 접근이 제대로된 방법인지 의심되는 상황이었기 때문에,
pnpm의 사용을 적극 권장하고싶다.
yarn2도 사용해보자!