여러분, 안녕하세요!
다양한 패키지 관리자를 사용하는 Node.js 프로젝트를 본 적이 있을 것입니다. 예:
나는 그것을 보고 위의 모든 작업을 수행했지만 항상 마음 속에 질문이 있었습니다. 사람들/팀이 npm 대신 Yan 또는 pnpm을 사용하도록 유도하는 이유는 무엇입니까? 장점은 무엇입니까? 단점이 있나요?
음… 알아봅시다!
나는 "속도" 측면에서 npm , Yarn 및 pnpm을 비교하기로 결정했습니다…
아래에 3가지 측정값이 표시됩니다.
캐시 없이 잠금 파일을 생성합니다.
캐시 없이 기존 잠금 파일에서 종속성을 설치합니다.
글로벌 캐시를 사용하여 기존 잠금 파일의 종속성을 설치합니다.
캐시에는 두 가지 유형이 있습니다.
글로벌.
일반적으로 사용자의 홈 디렉터리(fe, ~/.yarn/berry/cache
)에 저장됩니다.
현지의.
프로젝트 디렉터리(fe, <project-dir>/.yarn
)에 저장됩니다.
내 경험상 #2 와 #3이 가장 일반적인 사용 사례이지만, 만일을 대비해 #1도 사용했습니다(매우 드문 경우임에도 불구하고).
벤치마크의 예로 create-react-app 의 샘플 프로젝트를 사용했습니다.
Node.js 생태계의 기본 패키지 관리자입니다. 달리 무슨 말을 해야 할까요? 설치 패키지와 함께 제공되므로 컴퓨터에 Node.js를 설치할 때(또는 Node.js를 설정한 경우 CI 공급자에) 기본적으로 사용할 준비가 되어 있습니다.
제 생각에는 엄청난 "프로"입니다. 별도로 설치할 필요가 없습니다!
거기에는 뛰어난 것이 없습니다. 단지... 작동합니다! 그리고 지난 몇 년 동안 큰 버그를 본 적이 없습니다. 상당히 안정적이고 작업이 완료되는 것 같습니다.
지금까지 사용한 npm 의 기능은 다음과 같습니다.
npm은 프로젝트 루트의 node_modules
폴더에 종속성을 저장합니다. 꽤 직설적 인.
ℹ️ package-lock.json
나열된 패키지의 레지스트리에 대한 정보를 저장합니다. 단일 범위(예: @example-company
의 패키지가 다른 레지스트리(예: npm & GitHub 패키지 )에 있는 경우 매우 유용합니다.
이제 설치 속도 측면에서 어떤 성능을 발휘하는지 살펴보겠습니다.
걸렸다package-lock.json
생성하고 캐시 없이 종속성을 설치합니다.
사용된 명령:
npm i
걸렸다package-lock.json
의 종속성을 설치하려면 npm을 사용하세요.
사용된 명령:
npm ci
걸렸다package-lock.json
의 종속성을 설치합니다.
사용된 명령:
npm ci
작업공간을 생성하고 전체 작업공간에 대한 종속성을 한 번에 관리할 수 있었고, 특정 프로젝트에 대해서는 별도로 종속성을 관리할 수 있었습니다.
즉, 버그/문제 없이 작업을 완료하며 공식 문서는 매우 간단합니다.
지금까지 사용한 Workspace 기능:
솔직히 저는 실 기능 중 일부를 많이 시도하지 않았습니다. 내 말은, 일부 프로젝트에서 작업하는 동안 "종속성 설치"라는 측면에서 이를 많이 사용했다는 것입니다.
Yarn은 Node.js 설치 프로그램과 함께 제공되지 않으므로 별도로 설치해야 합니다. 이는 CI 파이프라인에 추가 단계가 있다는 것을 의미합니다. 즉, 프로젝트 종속성을 설치하기 전에 Yarn을 설정해야 합니다.
Yarn에는 종속성을 설치하는 두 가지 접근 방식이 있습니다.
" Zero Installs "(기본값) - .yarn
폴더를 생성하고 yarn.lock
및 .pnp.cjs
파일에 패키지를 나열합니다.
npm 과 유사한 일반 모듈은 종속성을 node_modules
에 저장하고 이를 yarn.lock
파일에 나열합니다.
ℹ️ 원사 잠금 파일은 이전(일반) 설치 접근 방식을 사용하는 경우 에만 나열된 모든 패키지의 레지스트리에 대한 정보를 저장합니다.
⚠️ " Zero Installs "는 패키지를 로컬 캐시에 저장하고 잠금 파일에 대한 링크를 제공하는 것처럼 보입니다.
하나의 정리된 환경에 종속성을 설치한 다음 이를 다른 환경으로 이동하려는 Dockerfile 또는 CI 파이프라인이 있는 경우 중요할 수 있습니다( .yarn
폴더와 로컬 캐시를 모두 복사해야 함).
이제 Yarn의 기본 접근 방식은 " Zero Installs "이고 이전 접근 방식보다 더 나은 성능을 제공하므로 이 접근 방식에 대해서만 벤치마크를 기록하겠습니다.
걸렸다yarn.lock
파일을 생성하고 캐시 없이 종속성을 설치합니다.
사용된 명령:
yarn install
걸렸다
사용된 명령:
yarn install --frozen-lockfile
걸렸다
사용된 명령:
yarn install --frozen-lockfile
작업공간을 생성하고 모든 프로젝트에 대한 종속성을 한 번에 관리할 수 있었고, 특정 프로젝트에 대해서는 별도로 종속성을 관리할 수 있었습니다.
지금까지 사용한 Workspace 기능:
문서는 훌륭하지만 명령 이름과 플래그가 다소 혼란스럽습니다.
예를 들어 루트 ( . ) 및 중첩된 b2b
프로젝트에서 test
스크립트를 실행하려면 다음을 실행해야 합니다.
yarn workspaces foreach -A --include '{.,b2b}' run test
npm 과 비교하면 다음과 같습니다.
npm run test --workspace=b2b --include-workspace-root
pnpm은 현재 많은 회사와 오픈 소스 프로젝트에서 사용하고 있습니다 .
Yarn 과 마찬가지로 pnpm에는 Node.js 설치 프로그램이 함께 제공되지 않으므로 별도로 설치해야 합니다. 이는 CI 파이프라인에 추가 단계가 있다는 의미입니다. 프로젝트 종속성을 설치하기 전에 pnpm을 설정해야 합니다.
pnpm은 " 빠르고 디스크 공간 효율적인 패키지 관리자 " 로 간주됩니다.
실제로 저는 종속성을 로컬로 관리한다는 측면에서 "디스크 공간 효율적"이라는 말에 동의합니다.
기본적으로 pnpm은 공유 종속성을 중복 제거합니다. pnpm은 여러 종속성에 사용되는 패키지에 대한 심볼릭 링크를 만듭니다. 즉, 패키지 a
와 b
패키지 c
종속성으로 사용하는 경우 pnpm 은 패키지 c
단일 복사본으로 저장하고 패키지 a
와 b
에 대한 심볼릭 링크를 생성합니다. 이렇게 하면 패키지 관리자가 하드 카피를 생성하지 않고 SSD/HDD에 메모리를 절약합니다.
ℹ️ pnpm-lock.yaml
나열된 패키지의 레지스트리에 대한 정보를 저장하지 않습니다.
⚠️ pnpm은 때때로 종속성을 프로젝트로 유지하는 대신 전역 캐시에 저장한다는 점을 명심하세요.
걸렸다pnpm-lock.yaml
생성하고 캐시 없이 종속성을 설치하려면
사용된 명령:
pnpm install
걸렸다pnpm-lock.yaml
의 종속성을 설치하려면
사용된 명령:
pnpm i --frozen-lockfile
걸렸다pnpm-lock.yaml
의 종속성을 설치하려면
사용된 명령:
pnpm i --frozen-lockfile
이제 상황이 정말 흥미로워집니다…
pnpm 에는 많은 구성 옵션이 있지만 일부 핵심 기능은 작동하지 않습니다!
제가 직면한 몇 가지 버그를 검토해 보겠습니다.
특정 프로젝트에 대해서만 종속성을 설치할 수 있다는 것이 중요합니다. 이는 작업 영역 내에서 특정 프로젝트와 관련된 파이프라인을 생성할 때 단일 저장소에 매우 유용합니다.
즉, 작업 공간에 다음이 있다고 상상해 보세요.
이들 모두는 별도의 npm 프로젝트이지만 동일한 저장소의 일부입니다 ☝️
이제 파이프라인에서 엔드투엔드 테스트만 실행하기를 원합니다. 따라서 엔드투엔드 테스트 종속성만 필요합니다. 그렇죠?
글쎄, 당신은 그렇게 할 수 없을 것입니다. pnpm은 전체 작업 공간에 대한 종속성을 설치하도록 강요합니다!
pnpm install --filter <project-name>
선택한 프로젝트에 대해서만 종속성을 설치해야 했지만 작동하지 않습니다.
1년 된 버그가 있는데 최근 작동하지 않는 수정으로 종료되었습니다.
pnpm install
실행하면 기본적으로 pnpm은 전체 작업 공간(모든 프로젝트)에 대한 종속성을 설치합니다.
작업공간 루트의 .npmrc
에서 recursive-install=false
설정하면 이 동작을 대체할 수 있습니다.
하지만 이미 거의 2년이 된 또 다른 버그가 발생했습니다 .
pnpm은 기본적으로 종속성 목록을 단일 잠금 파일에 저장합니다( npm 및 Yarn 과 동일).
작업공간 루트의 .npmrc
에서 shared-workspace-lockfile=false
설정한 경우에도 이 동작을 대체할 수 있습니다.
그러면 작업 공간 기능을 유지하고 --ignore-workspace
플래그를 사용하여 특정 프로젝트에 대한 종속성을 설치할 수 있습니다.
어쨌든 이 설정에는 몇 가지 문제가 더 발생합니다.
eslint
및 tsc --noEmit
GitHub Actions 파이프라인에서 "JavaScript Heap Out of Memory" 오류를 발생시킵니다.
일부 종속성은 전역 캐시에 저장되고 node_modules/.pnpm
에 심볼릭 링크됩니다.
# | npm | 실 | pnpm |
---|---|---|---|
잠금 파일 생성 | 60초 | 16.5초 | 31초 |
캐시 없이 종속성 설치 | 18초 | 11초 | 8초 |
글로벌 캐시를 사용하여 종속성 설치 | 8초 | 8초 | 5초 |
위 벤치마크에 따르면 npm은 가장 느린 패키지 관리자입니다 ☝️
어쨌든, 이 결과를 해석해 봅시다…
드문 경우입니다. 일반적으로 잠금 파일은 프로젝트 초기화 시 생성된 다음 패키지를 설치/업데이트할 때 확장됩니다.
이를 염두에 두고 패키지 관리자를 선택할 때 의존하는 것은 그다지 중요한 것 같지 않습니다.
대부분의 경우 프로젝트는 특정 종속성 목록을 유지하며 항목을 추가/제거하는 경우는 거의 없습니다.
아마도 때때로 패키지 버전을 변경하게 될 것입니다. 이러한 변경 사항은 작으며 캐시의 나머지 패키지를 재사용하게 됩니다.
즉, 일반적인 사용 사례는 패키지 레지스트리에서 새 패키지를 가져오고 나머지는 캐시에서 가져오는 것입니다.
pnpm (5-8초)은 중간에 원사 (8-11초)가 있는 npm (8-18초)보다 거의 두 배 빠릅니다.
패키지 관리자에 대한 요구 사항이 "종속성만 설치"만큼 간단하다면 pnpm이 가장 잘 작동한다고 생각합니다.
pnpm에는 기본적으로 Node.js 설치 프로그램이 제공되지 않지만 corepack 또는 기존 작업을 사용하여 CI 파이프라인에서 쉽게 설정할 수 있습니다.
나는 다음과 같은 이유로 npm 을 선호합니다:
package-lock.json
에 패키지 레지스트리를 저장하므로 다른 레지스트리의 단일 범위로 종속성을 설치할 수 있습니다.
이러한 장점은 내가 Yan 또는 pnpm 으로 절약하는 속도와 디스크 공간보다 더 중요합니다.
패키지 관리자를 선택하는 기준은 무엇입니까? 부끄러워하지 말고 아래 댓글 섹션에서 여러분의 생각을 알려주세요! 👇😊