패키지 매니저의 진화
JavaScript 패키지 매니저
버전 문제를 해결해서 외부 의존성을 올바르게 참조할 수 있도록 도와주는 프로그램입니다. 코드에서는 절대/상대 경로로 import
, require
만 하고 있는데 버전별로 동작이나 구현이 다르기 때문에 package.json
에 버전을 명시합니다.
패키지 매니저의 동작
Resolution
라이브러리 버전 고정
react: "^18.1.0" // 18.1.0 <= version < 19.x.x 사이의 최신버전
라이브러리의 다른 의존성 확인
라이브러리의 다른 의존성 버전 고정
모든 기기에서 고정된 버전을 사용하게 하고 결과물을
yarn.lock
,package-lock.json
에 저장합니다.
Fetch
선택된 버전의 파일을 다운로드(일반적으로 npm registry)
Link
Resolution/Fetch된 라이브러리를 소스 코드에서 사용할 수 있는 환경 제공
npm Linker
node_modules 디렉토리에 package.json에 명시하는 의존성을 순서대로 쓰는 동작
pnpm Linker
npm linker의 중복되는 의존성으로 인한 디스크 용량 문제를 해결한 개선된 npm
alias를 사용하는 Hard link 방식을 사용하여 개선하여 디스크문제와 속도 개선
PnP(Plug`n Play) Linker
node_modules를 벗어나고 싶다는 생각으로 접근한 것
import할 때 어떤 파일에서 import하고 무엇을 import하는지 접근
node_module가 아니라 .pnp.cjs라는 파일에서 객체(JavaScript Map)로 처리(특정 디렉토리에서 react를 import하면 18.1.0을 제공하는 방식)
yarn.lock기반으로 .pnp.cjs 만들면 됩니다.
Node.js와 함께 기본적으로 설치되기 때문에 대표적이고 가장 점유율이 높다.
해결하고자 한 문제
외부 의존성의 버전 문제를 해결
한계
패키지들을 각각 별도로 설치하기 때문에 공유된 의존성이 중복으로 설치되고 디스크 공간을 많이 차지 할 수 있다.
의존성 트리가 깊어지면 설치 속도가 느려질 수 있다.
해결하고자 한 문제
alias를 이용한 Hard Link를 이용해서 중복설치를 피하여 npm의 의존성 문제(디스크 공간, 속도)를 해결
글로벌 저장소 → node_modules/.pnpm으로 하드링크
node_modules/.pnpm → node_modules으로 심볼릭링크
yarn과 npm의 공통적인 문제인 유령 의존성(직접 설치하지 않았는데 import 되는 것) 해결
로컬 디렉토리에 캐싱된 의존성이 있다면 symbolic link를 거는 방식을 이용해서 새로운 프로젝트에서도 빠른 속도
한계
zero install은 불가능합니다
Docker image에 pnpm 설치 필요(기본 제공 x)
해결하고자 한 문제
여러 패키지를 병렬로 설치할 수 있어서 npm보다 빠른 속도를 보장합니다.
한계
npm과 같은 호이스팅 문제(유령 의존성)
디스크 공간 중복 사용
복잡한 의존성 트리에서 느린 속도
Yarn의 새로운 버전으로 PnP, Zero-install을 지원합니다.
해결하고자 한 문제
PnP를 이용하여 node_modules를 벗어나
.pnp.cjs
로 빠른 속도
한계
PnP 모드에서 일부 도구 호환성 문제(IDE 확장 프로그램 설치)
Zero-install 사용 시
.yarn/cache
폴더(내부에 zip파일)가 Git에 포함되어 저장소 크기 증가
Corepack이 등장한 배경
Node.js 14+에서 제공
프로젝트마다 다른 패키지 매니저 사용 (npm, yarn, pnpm)
CI/CD과 팀원들의 로컬에서 패키지 매니저 버전 불일치로 인한 문제
Package Manager 버전 관리
package.json
의packageManager
필드로 버전 명시Corepack 활성화(
corepack enable
) 후 패키지 설치 시packageManager
기준으로 버전 관리
성능 비교
실무 팁
마이그레이션 고려사항
npm → yarn classic
package-lock.json
,node_modules
삭제 후yarn.lock
생성npm scripts는 그대로 사용 가능
호이스팅 차이로 인한 문제 체크
yarn audit npm ls --depth=0
npm → pnpm
유령 의존성 문제로 인한 에러 발생 가능
코드에서 없는 의존성인데 사용하는 케이스 존재할 수 있어서 pnpm에서는
package.json
에 누락된 의존성 추가 필요
package-lock.json
,node_modules
삭제 후pnpm-lock.json
생성스크립트 차이 (
npm run
vspnpm run
)
yarn classic → yarn berry
yarn set version berry
(version 변경)yarn config set nodeLinker pnp
(pnp 활성화해도되고 node_modules로 써도됩니다).yarnrc.yml
(Yarn Berry(v2+)의 설정 파일)파일 생성PnP 모드에서 IDE 설정 필요
yarn classic → pnpm
코드에서 없는 의존성인데 사용하는 케이스 존재할 수 있어서 pnpm에서는
package.json
에 누락된 의존성 추가 필요스크립트 실행 방식 차이 (
yarn run
vspnpm run
)
npm ci vs npm install
npm ci
프로덕션/CI 환경에서 주로 사용
package-lock.json
만 참조 (수정 없이 명시된 버전 설치)
npm install
개발 환경에서 주로 사용
package.json
과package-lock.json
모두 참조버전 범위 내에서 최신 버전 설치 가능
package-lock.json
업데이트 가능
peer dependencies 문제
npm@7부터는 peerDependencies가 기본으로 설치되고 버전이 맞지 않으면 에러
npm@3 ~ npm@6과 yarn에서는 warning
--legacy-peer-deps
: conflict에 대한 warning이 발생해도 일단 설치--strict-peer-deps
: strict하게 검사추가 옵션의 경우 .npmrc를 통해 설정 가능합니다.
JavaScript 표준으로 패키지를 관리
package.json가 없는 환경에서는 Import Map를 사용해서 패키지 매니저 없이 가져올 수 있습니다.
<script type="importmap">
{
"imports": {
"react": "<https://cdn.jsdelivr.net/npm/react@18/umd/react.development.js>"
}
}
</script>
<script type="module">
import React from 'react';
</script>
PnP vs. Zero-install
PnP(Plug and Play)는 Javascript Map 객체를 활용해 의존성을 관리하는 방식
Zero-install
PnP의 Javascript Map 객체와 Fetch된 의존성들까지 Git에 넣어서 관리하는 방식
npm의 node_modules를 Git에 넣어서 관리하는 방식
유용한 도구
https://www.npmjs.com/package/patch-package
pnpm patch, yarn patch에서는 자체 제공
Reference
Last updated