よくある質問
パッケージがグローバルストアに保存されている場合、なぜ node_modules
フォルダがディスク容量を使用するのですか?
pnpm は、グローバルストアからプロジェクトの node_modules
フォルダへのハードリンクを作成します。ハードリンクは、元のファイルが置かれているディスク上の同じ場所を指します。そのため、例えば、依存関係としてプロジェクトに foo
があり、それが 1MB の容量を占有している場合、プロジェクトの node_modules
フォルダとグローバルストアの両方で 1MB の容量を占有しているように見えます。しかし、その 1MB はディスク上の*同じ領域*であり、2 つの異なる場所から参照されています。そのため、合計で foo
は 1MB を占有し、2MB ではありません。
この件に関する詳細
Windows では動作しますか?
簡潔に言うと、はい。詳しく言うと、Windows でシンボリックリンクを使用することは控えめに言っても問題がありますが、pnpm には回避策があります。Windows の場合、代わりにジャンクションを使用します。
しかし、ネストされた node_modules
のアプローチは Windows と互換性がありませんか?
初期のバージョンの npm は、すべての node_modules
をネストしていたため問題が発生しました(この issue を参照)。ただし、pnpm は深いフォルダを作成せず、すべてのパッケージをフラットに保存し、シンボリックリンクを使用して依存関係ツリー構造を作成します。
循環シンボリックリンクはどうですか?
pnpm はリンクを使用して依存関係を node_modules
フォルダに配置しますが、親パッケージは依存関係と同じ node_modules
フォルダに配置されるため、循環シンボリックリンクは回避されます。そのため、foo
の依存関係は foo/node_modules
にはなく、foo
は独自の依存関係と共に node_modules
にあります。
なぜハードリンクが必要なのですか? なぜグローバルストアに直接シンボリックリンクしないのですか?
1 つのパッケージは、1 台のマシン上で異なる依存関係のセットを持つことができます。
プロジェクト **A** では、foo@1.0.0
は bar@1.0.0
に解決される依存関係を持つことができますが、プロジェクト **B** では、foo
の同じ依存関係が bar@1.1.0
に解決される場合があります。そのため、pnpm は foo@1.0.0
を使用されているすべてのプロジェクトにハードリンクして、異なる依存関係のセットを作成します。
グローバルストアへの直接シンボリックリンクは、Node の --preserve-symlinks
フラグで動作しますが、そのアプローチには多くの独自の問題が伴うため、ハードリンクを使用することにしました。この決定が行われた理由の詳細については、この issue を参照してください。
pnpm は 1 つの Btrfs パーティション内の異なるサブボリューム間で動作しますか?
Btrfs は単一パーティション内の異なるサブボリューム間でのクロスデバイスハードリンクを許可していませんが、リフリンクは許可しています。そのため、pnpm はリフリンクを利用してこれらのサブボリューム間でデータを共有します。
pnpm は複数のドライブまたはファイルシステム間で動作しますか?
パッケージストアは、インストールと同じドライブおよびファイルシステム上にある必要があります。そうでない場合、パッケージはリンクされずにコピーされます。これは、ハードリンクの仕組みの制限により、1 つのファイルシステム上のファイルが別のファイルシステム上の場所を参照できないためです。詳細については、Issue #712 を参照してください。
pnpm は以下の 2 つのケースで動作が異なります
ストアパスが指定されている場合
ストア設定を介してストアパスが指定されている場合、ストアと異なるディスク上にあるプロジェクト間でコピーが発生します。
ディスク A
で pnpm install
を実行する場合、pnpm ストアはディスク A
上にある必要があります。 pnpm ストアがディスク B
にある場合、必要なすべてのパッケージはリンクされずにプロジェクトの場所に直接コピーされます。これは、pnpm のストレージとパフォーマンスの利点を著しく阻害します。
ストアパスが指定されていない場合
ストアパスが設定されていない場合、複数のストアが作成されます(ドライブまたはファイルシステムごとに 1 つ)。
ディスク A
でインストールが実行された場合、ストアはファイルシステムルートの下の A
.pnpm-store
に作成されます。後でディスク B
でインストールが実行された場合、独立したストアが B
の .pnpm-store
に作成されます。プロジェクトは pnpm の利点を維持しますが、各ドライブに冗長なパッケージが存在する可能性があります。
pnpm
とは何の略ですか?
pnpm
は performant npm
の略です。 @rstacruz がこの名前を考案しました。
pnpm
は <YOUR-PROJECT-HERE> では動作しませんか?
ほとんどの場合、依存関係の 1 つが package.json
で宣言されていないパッケージを必要としていることを意味します。これは、フラットな node_modules
によって引き起こされる一般的なミスです。これが発生した場合、これは依存関係のエラーであり、依存関係を修正する必要があります。ただし、時間がかかる場合があるため、pnpm はバグのあるパッケージを動作させるための回避策をサポートしています。
解決策 1
問題が発生した場合は、node-linker=hoisted
設定を使用できます。これにより、npm
によって作成されたのと同様のフラットな node_modules
構造が作成されます。
解決策 2
次の例では、依存関係に独自の依存関係リストに iterall
モジュールがありません。
バグのあるパッケージの不足している依存関係を解決する最も簡単な解決策は、**プロジェクトの `package.json` に `iterall` を依存関係として追加することです**。
pnpm add iterall
を介してインストールすることで、プロジェクトの `package.json` に自動的に追加されます。
"dependencies": {
...
"iterall": "^1.2.2",
...
}
解決策 3
解決策の 1 つは、フックを使用して、不足している依存関係をパッケージの 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.cjs
を作成することでした
module.exports = {
hooks: {
readPackage: (pkg) => {
if (pkg.name === "inspectpack") {
pkg.dependencies['babel-traverse'] = '^6.26.0';
}
return pkg;
}
}
};
.pnpmfile.cjs
を作成した後、pnpm-lock.yaml
のみ削除します - pnpm フックはモジュール解決にのみ影響するため、node_modules
を削除する必要はありません。その後、依存関係を再構築すると、動作するはずです。