メインコンテンツまでスキップ
Version: 7.x

よくある質問 (FAQ)

なぜ、 node_modules フォルダは、パッケージがグローバルストアに保存されている場合にディスク容量を使用するのですか?

pnpm は、 ハードリンク を、グローバルストアからプロジェクトの node_modules フォルダーに作成します。 ハードリンクは、元の ファイルがあるディスク上の同じ場所を指します。 例えば、1MBを占める foo を依存に持つプロジェクトでは、そのプロジェクト配下の node_modules フォルダが、リンク元のグローバルストアと同じ 1MB を消費しているように見えます。 ただし、2つの異なるリンクが示す、占有されている 1MB はディスク上の 同じ位置 にあります。 そのため、全体で foo は 2MB ではなく 1MB のみ占有しています。

このテーマの詳細について:

Windowsで動作しますか?

簡単な答え:はい。 詳細な答え: Windows 上でシンボリックリンクを使用することに関しては少なくとも問題はありますが、しかし、pnpm には回避策があります。 Windows では、代わりに ジャンクション を使用します。

しかし、ネストされた node_modules アプローチは Windows と互換性がありますか?

npmの初期のバージョンでは、すべての node_module をネストするため、問題がありました。(こちらの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は複数のドライブまたはファイルシステムをまたいで機能しますか?

パッケージストアは、インストール先と同じドライブおよびファイルシステム上にある必要があります そうでない場合、パッケージはリンクされずにコピーされます。 これは、あるファイルシステム上のファイルは、他のファイルシステム上の場所を扱うことができないというハードリンクの仕組みによる制限です。 詳細については、Issue #712 を参照してください。

pnpmは、以下の2つの場合で異なる動作をします:

ストアのパスが指定された場合

ストアの設定でストアのパスが指定されると、違うディスクにあるストアとプロジェクトの間ではコピーが発生します。

ディスクApnpm install を実行する場合、pnpm ストアはディスクA にある必要があります。 もし pnpm ストアがディスクBにある場合、すべての必要なパッケージがプロジェクトにリンクされる代わりにコピーされます。 これは、pnpm のストレージとパフォーマンスに関する利点を阻害します。

ストアのパスが指定されていない場合

ストアのパスが指定されていない場合、一つのドライブやファイルシステムごとに、複数のストアが作成されます。

インストールがディスクA で実行された場合、ストアはA のファイルシステムのルートの .pnpm-store に作成されます。 その後、ディスクBでインストールが実行される場合、 B.pnpm-store に独立したストアが作成されます。 プロジェクトは引き続きpnpmの利点を維持しますが、各ドライブには重複したパッケージが含まれる場合があります。

pnpm は何の略ですか?

pnpmperformant npm の略です。 @rstacruz がこの名前を考案しました。

pnpm が私のプロジェクトでうまく動きません

ほとんどの場合、これは依存関係のどれかが、package.json で宣言されていないパッケージを使用していることを意味します。 これはフラットな node_modules によって引き起される一般的な誤ちの一つです。 これが発生した場合、これは依存パッケージの問題であり、依存パッケージを修正する必要があります。 ただし、これには時間がかかる場合があるため、pnpmには、バグのあるパッケージを機能させるための回避策があります。

解決策1

以下の例では、ある依存関係が iterall というモジュールをそのパッケージ自身の依存関係として持っていません

このようなバグのあるパッケージで依存関係が足りていないことを修正する最も簡単な方法は、 iterall パッケージをあなたのプロジェクトの package.json に追加することです。

pnpm add iterall を実行することであなたのプロジェクトの package.json に自動で追加され、これを行うことができます。

  "dependencies": {
...
"iterall": "^1.2.2",
...
}

解決策2

解決策の一つは、依存パッケージの package.json に足りていない依存関係を追加するために フック を利用することです。

例として、pnpm でうまく動作していなかった Webpack Dashboard があります。 その後、 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-traverseinspectpackpackage.json で指定されていなかったことがこの原因です。 これはフラットな node_modules を生成する npmyarn では動作し続けていました。

これの解決策は次のような .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 を削除する必要はありません。 そして依存関係を再ビルドすれば、うまく動くようになっているはずです。

解決策3

問題が多すぎる場合は、shamefully-hoist オプションを使うことができます。 このオプションを指定することで、npmyarn で生成されるのと似たフラットな構造の node_modules が作られますが、この構造を避けることがpnpmの node_modules 生成方法の主目的なので、これは推奨されません。

これを使うには、pnpm install --shamefully-hoist を実行してください。