자주 묻는 질문
패키지가 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에서 symbolic link을 다루는 게 아무래도 문제가 되긴 하는데, pnpm은 해결 방법이 있긴 합니다. Windows에선 junctions을 대신 사용하고 있습니다.
하지만 중첩된 node_modules
방식은 Windows랑 안 맞지 않나요?
npm의 초기 버전은 node_modules
을 모두 중첩하는 것에 문제가 있었습니다. (see this issue). 하지만, 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
플래그와 함께 작동하지만 해당 접근 방식에는 자체 문제가 너무 많기 때문에 하드 링크를 사용하기로 결정했습니다. 이 결정이 내려진 이유에 대한 자세한 내용은 이 문제 를 참조하십시오
pnpm이 여러 저장장치나 파일 시스템 위에서 동작할 수 있나요?
패키지 저장소는 설치와 동일한 드라이브 및 파일 시스템에 있어야 합니다. 그렇지 않으면 패키지가 링크되지 않고 복사됩니다. 이것은 한 파일 시스템의 파일이 다른 파일 시스템의 위치를 지정할 수 없다는 점에서 하드 링크가 작동하는 방식의 한계에 기인합니다. 자세한 내용은 Issue #712 을 참조하십시오.
pnpm은 아래 두 가지 경우에서 다르게 작동합니다.
저장 경로가 지정된 경우
저장소 경로가 store config 를 통해 지정되면, 저장소와 다른 디스크에 있는 프로젝트 간에 복사 가 발생합니다.
디스크 A
에서 pnpm install
을 실행하는 경우, pnpm 저장소는 디스크 A
에 있어야 합니다. pnpm 저장소가 디스크 B
에 있는 경우 필요한 모든 패키지가 링크되는 대신 프로젝트 위치에 직접 복사됩니다. 이것은 심각하게 pnpm의 저장 및 성능 이점을 저해합니다.
저장 경로가 지정되지 않은 경우
저장소 경로가 설정되지 않은 경우 여러 저장소가 생성됩니다 (드라이브 또는 파일 시스템 당 하나).
설치가 디스크 A
에서 실행되는 경우, 저장소는 파일 시스템 루트 아래의 A
.pnpm-store
에 생성됩니다. 나중에 디스크 B
에서 설치가 진행되면, B
위의 .pnpm-store
에 독립적인 저장소가 생성됩니다. 프로젝트는 여전히 pnpm의 이점을 누리지만, 각 드라이브에는 중복된 패키지가 있을 수 있습니다.
pnpm
은 무엇의 줄임말인가요?
pnpm
은 performant npm
의 줄임말입니다. @rstacruz가 이름을 지었습니다.
pnpm
이 <여러분의 프로젝트>에서 작동하지 않습니까?
대부분의 경우 의존성 중 하나에서 package.json
에 선언되지 않은 패키지가 필요하다는 의미입니다. 이는 평탄한 node_modules
로 인해 발생하는 일반적인 실수입니다. 이 경우 의존성 오류이며 그 의존성을 수정해야 합니다. 하지만 이는 시간이 걸릴 수 있으므로, pnpm은 버그가 있는 패키지가 작동하도록 여러 해결 방법을 지원합니다.
해결 방법 1
In case there are issues, you can use the node-linker=hoisted
setting. This creates a flat node_modules
structure similar to the one created by npm
.
해결 방법 2
In the following example, a dependency does not have the iterall
module in its own list of deps.
The easiest solution to resolve missing dependencies of the buggy packages is to add iterall
as a dependency to our project's package.json
.
You can do so, by installing it via pnpm add iterall
, and will be automatically added to your project's package.json
.
"dependencies": {
...
"iterall": "^1.2.2",
...
}
해결 방법 3
One of the solutions is to use hooks for adding the missing dependencies to the package's package.json
.
An example was Webpack Dashboard which wasn't working with pnpm
. It has since been resolved such that it works with pnpm
now.
It used to throw an error:
Error: Cannot find module 'babel-traverse'
at /node_modules/inspectpack@2.2.3/node_modules/inspectpack/lib/actions/parse
The problem was that babel-traverse
was used in inspectpack
which was used by webpack-dashboard
, but babel-traverse
wasn't specified in inspectpack
's package.json
. It still worked with npm
and yarn
because they create flat node_modules
.
The solution was to create a .pnpmfile.cjs
with the following contents:
module.exports = {
hooks: {
readPackage: (pkg) => {
if (pkg.name === "inspectpack") {
pkg.dependencies['babel-traverse'] = '^6.26.0';
}
return pkg;
}
}
};
After creating a .pnpmfile.cjs
, delete pnpm-lock.yaml
only - there is no need to delete node_modules
, as pnpm hooks only affect module resolution. Then, rebuild the dependencies & it should be working.