자주 묻는 질문
패키지가 global store에 저장되었는데도 node_modules가 디스크 공간을 사용하는 이유가 무엇인가요?#
pnpm은 global store에서 프로젝트의 node_modules 폴더로 hard links를 만듭니다. Hard links는 디스크상의 원본 파일이 있는 위치를 가리킵니다. 예를 들어, 프로젝트에 1MB를 잡아 먹는 foo 디펜던시가 있으면, 그게 프로젝트의 node_modules 폴더와 global store 안에서 각각 1MB을 차지하는 것으로 보입니다. 하지만, 그 1MB는 디스크 내에서 동일한 공간이며 서로 다른 두 곳에서 참조할 뿐입니다. 그래서 foo는 2MB가 아니라 총 1MB를 차지합니다.
이 주제에 대해 자세한 내용 (영어):
Windows에서 동작할까요?#
짧은 답: 네. 자세한 답변: Windows에서 심볼릭 링크를 사용하는 것은 때때로 문제가 될 수 있지만, pnpm에는 해결 방법이 있습니다. Windows에서 개발자 모드가 꺼져 있으면 대신 정션을 사용합니다.
하지만 중첩된 node_modules 방식은 Windows랑 안 맞지 않나요?#
초기 버전의 npm은 모든 node_modules를 중첩하는 방식 때문에 문제가 있었습니다(이 이슈 참조). 하지만, pnpm은 폴더를 깊이 생성하는 대신, 모든 패키지를 평평하게 저장하고 symbolic link를 사용해 종속성 트리 구조를 만듭니다.
순환 참조는 어떻습니까?#
pnpm은 링크를 사용하여 종속성을 node_modules 폴더에 넣지만 상위 패키지가 종속성이 있는 동일한 node_modules 폴더에 배치되기 때문에 순환 참조를 피할 수 있습니다. 따라서 foo의 디펜던시는 foo/node_modules에 있지 않고, foo 와 그 디펜던시와 node_modules에 함께 있습니다.
왜 하드 링크가 있습니까? 글로벌 스토어에 직접 심볼릭 링크하지 않는 이유는 무엇입니까?#
하나의 패키지는 하나의 시스템에 대해 서로 다른 의존성 집합을 가질 수 있습니다.
프로젝트 A foo@1.0.0 에서 의존성이 bar@1.0.0 으로 해결될 수 있지만 프로젝트 B 에서 foo 의 동일한 의존성은 bar@1.1.0 을 통해 해결될 수 있습니다. 따라서 pnpm은 foo@1.0.0 를 사용하는 모든 프로젝트에 하드 링크하여 서로 다른 의존성 세트를 생성합니다.
글로벌 스토어에 대한 직접적인 심볼릭 링크는 Node의 --preserve-symlinks 플래그와 함께 작동하지만 해당 접근 방식에는 자체 문제가 너무 많기 때문에 하드 링크를 사용하기로 결정했습니다. 이 결정이 내려진 이유에 대한 자세한 내용은 이 문제 를 참조하십시오
하나의 Btrfs 파티션 안의 서로 다른 서브볼륨 간에도 pnpm이 작동하나요?#
Btrfs는 단일 파티션 안의 서로 다른 서브볼륨 간에 장치 간 하드 링크를 허용하지 않지만, reflink는 허용합니다. 따라서 pnpm은 reflink를 사용하여 이러한 서브볼륨 간에 데이터를 공유합니다.
여러 드라이브나 파일 시스템에서도 pnpm이 작동하나요?#
패키지 스토어는 설치 위치와 같은 드라이브 및 파일 시스템에 있어야 합니다. 그렇지 않으면 패키지는 링크되지 않고 복사됩니다. 이는 하드 링크의 작동 방식에 따른 제한 때문으로, 한 파일 시스템의 파일은 다른 파일 시스템의 위치를 가리킬 수 없습니다. 자세한 내용은 Issue #712를 참고하세요.
pnpm은 아래 2가지 경우에 다르게 작동합니다:
저장 경로가 지정된 경우#
스토어 설정으로 스토어 경로를 지정한 경우, 스토어와 다른 디스크에 있는 프로젝트 사이에서 복사가 발생합니다.
디스크 A에서 pnpm install을 실행하는 경우, pnpm 스토어는 반드시 디스크 A에 있어야 합니다. 디스크 B에 pnpm 스토어가 있으면, 필요한 모든 패키지는 링크되지 않고 프로젝트 위치로 직접 복사됩니다. 이는 pnpm의 저장 공간 및 성능상 이점을 크게 저해합니다.
저장 경로가 지정되지 않은 경우#
스토어 경로를 설정하지 않으면 여러 개의 스토어가 생성됩니다(드라이브 또는 파일 시스템마다 하나씩).
디스크 A에서 설치를 실행하면 A의 파일 시스템 루트 아래에 .pnpm-store 스토어가 생성됩니다. 나중에 디스크 B에서 설치를 실행하면 B의 .pnpm-store에 독립적인 스토어가 생성됩니다. 프로젝트는 여전히 pnpm의 이점을 유지하지만, 각 드라이브에 중복된 패키지가 있을 수 있습니다.
pnpm 은 무슨 뜻인가요?#
pnpm은 performant npm의 줄임말입니다. @rstacruz 가 이 이름을 고안했습니다.
pnpm이 <YOUR-PROJECT-HERE>에서 작동하지 않나요?#
대부분의 경우 이는 종속성 중 하나가 package.json에 선언되지 않은 패키지를 필요로 한다는 의미입니다. 이는 평탄한 node_modules로 인해 흔히 발생하는 실수입니다. 이런 경우 이는 해당 종속성의 오류이며, 종속성이 수정되어야 합니다. 하지만 시간이 걸릴 수 있으므로, pnpm은 문제가 있는 패키지가 작동하도록 하는 해결 방법을 지원합니다.
해결 방법 1#
문제가 있는 경우 nodeLinker: hoisted 설정을 사용할 수 있습니다. 이렇게 하면 npm이 생성하는 것과 유사한 평탄한 node_modules 구조가 생성됩니다.
해결 방법 2#
다음 예시에서 한 종속성의 자체 종속성 목록에는 없는 iterall 모듈이 사용됩니다.
문제가 있는 패키지의 누락된 종속성을 해결하는 가장 쉬운 방법은 프로젝트의 package.json에 iterall을 종속성으로 추가하는 것입니다.
pnpm add iterall로 설치하면 프로젝트의 package.json에 자동으로 추가됩니다.
"dependencies": {
...
"iterall": "^1.2.2",
...
}
해결 방법 3#
해결 방법 중 하나는 훅을 사용하여 패키지의 package.json에 누락된 종속성을 추가하는 것입니다.
한 가지 예는 Webpack Dashboard로, pnpm에서 작동하지 않았습니다. 이 문제는 이후 해결되어 지금은 pnpm에서 작동합니다.
예전에는 다음과 같은 오류가 발생했습니다:
Error: Cannot find module 'babel-traverse'
at /node_modules/inspectpack@2.2.3/node_modules/inspectpack/lib/actions/parse
문제는 webpack-dashboard가 사용하는 inspectpack에서 babel-traverse를 사용했지만, babel-traverse가 inspectpack의 package.json에 지정되어 있지 않았다는 것이었습니다. npm과 yarn은 평탄한 node_modules를 생성하기 때문에 여전히 작동했습니다.
해결 방법은 다음 내용으로 .pnpmfile.mjs를 만드는 것이었습니다:
export const hooks = {
readPackage: (pkg) => {
if (pkg.name === "inspectpack") {
pkg.dependencies['babel-traverse'] = '^6.26.0';
}
return pkg;
}
}
.pnpmfile.mjs를 만든 후에는 pnpm-lock.yaml만 삭제하세요. pnpm 훅은 모듈 해석에만 영향을 주므로 node_modules를 삭제할 필요는 없습니다. 그런 다음 종속성을 다시 빌드하세요 & 그러면 작동할 것입니다.