그룹 프로젝트를 시작하면서 팀원들과 함께 패키지 매니저 선택에 대한 고민을 하게 되었다. 기존에 많이 사용되어 온 npm의 문제점을 개선한 다양한 모던 패키지 매니저가 등장했는데, 그 중 특히 주목받고 있는 pnpm 을 사용하기로 했다. 멘토님께서 yarn berry도 언급해 주셔서 pnpmyarn berry와 비교를 해본 뒤 패키지 매니저를 결정하기로 했다. (근데 사실 이미 pnpm을 사용하기로 이야기를 나눈 후에 yarn berry도 찾아보는 형식으로 이야기가 진행된 것이라 pnpm 걍 쓸 것 같다.)

이 글에서 npm의 문제점을 짚어보고, 이를 해결하려는 yarn berrypnpm에 대해 간략하게 정리했다.

기존 npm(또는 Yarn 1)의 문제점

유령 의존성 (Phantom Dependency)

https://classic.yarnpkg.com/blog/2018/02/15/nohoist/

https://classic.yarnpkg.com/blog/2018/02/15/nohoist/

기존 npm은 각 프로젝트마다 의존성 패키지를 node_modules 폴더에 설치한다. 이 방식은 간단하지만, 의존성 패키지가 중복 설치되는 문제가 생길 수 있다.

예를 들어 이미지의 왼쪽처럼 의존성 트리가 만들어진다고 가정하자. 여러 패키지가 AB에 의존할 때, 각각의 의존성에 따라node_modules 폴더에 중복으로 설치되어 디스크를 낭비하게 된다. 이를 보완하고자 npm(과 Yarn 1)은 이미지의 오른쪽처럼 중복되는 패키지를 끌어올리는(Hoisting) 방법을 사용했다.

예시로 express 패키지를 살펴보면 package.json에 다음과 같은 의존성 패키지가 명시되어 있다.

 "dependencies": {
    **"accepts": "~1.3.8",**
    "array-flatten": "1.1.1",
    "body-parser": "1.20.3",
    "content-disposition": "0.5.4",
    "content-type": "~1.0.4",
    "cookie": "0.6.0",
    "cookie-signature": "1.0.6",
    **"debug": "2.6.9",**
    ...
  },

중복되지 않는 패키지는 express 패키지 내부에 있는 node_modules 폴더에 존재한다. debug 패키지는 중복 사용되지 않는 패키지인 듯하다.

중복되지 않는 패키지는 express 패키지 내부에 있는 node_modules 폴더에 존재한다. debug 패키지는 중복 사용되지 않는 패키지인 듯하다.

accepts는 호이스팅된 것으로 보아 중복 사용되는 패키지인 것 같다.

accepts는 호이스팅된 것으로 보아 중복 사용되는 패키지인 것 같다.

하지만, 이렇게 끌어올리기를 하게 되면 직접 의존하지 않던 B 라이브러리를 불러올 수 있게 되는 문제점이 발생한다. 이를 유령 의존성이라고 부른다. 즉, package.json에 명시하지 않은 라이브러리를 몰래 사용하게 되면서 의존성 관리에 혼란을 야기할 수 있는 것이다.

이를 해결하는 Yarn Berry와 Pnpm

Yarn Berry와 Pnpm 모두 호이스팅 대신 각자의 방식을 채택해 유령 의존성 문제를 해결했다.

Yarn Berry의 해결 방법

Yarn Berry(Yarn 2)는 이러한 문제를 해결하기 위해 Plug'n'Play(PnP) 방식을 도입했다. (이름이 너무 복잡한데…) Yarn Berry는 node_modules 폴더 없이도 패키지를 관리할 수 있도록 설계되어, .yarn/cache 폴더에 패키지를 압축된 .zip 형태로 저장한다. 이를 통해 모든 의존성을 한 곳에서 직접 관리한다.

Pnpm의 해결 방법

pnpm은 위 문제를 해결하기 위해 프로젝트에서 사용하는 의존성 패키지(dependencies/devDependencies)는 node_modules 폴더 바로 아래에 해당 패키지의 심볼릭 링크를 만든다.

https://pnpm.io/motivation

https://pnpm.io/motivation

근데 node_modules 아래에 있는 express[email protected]의 심볼릭 링크가 아니라 [email protected]/node_modules/express 의 심볼릭 링크인 이유는 무엇일까? 왜 express 패키지가 express 안에 또 존재하는 것일까?

https://pnpm.io/motivation

https://pnpm.io/motivation