pnpm の人気が高まるにつれ、皆さんもよく耳にするようになったと思いますが、今日は高く評価されているpnpmの魔法とは何かを一緒に学びましょう。
目次
1. npm/yarn install の原則
npm/yarn installするとどうなりますか? これは主に 2 つの部分に分けられます。1 つ目はパッケージが node_modules に到達する方法、2 つ目はnode_modules が内部で依存関係を管理する方法です。
コマンドが実行されると、依存関係ツリーが最初に構築され、次に各ノードの下のパッケージが 4 つのステップを経ます。
- 依存パッケージのバージョン間隔を特定のバージョン番号に解析します
- 対応する依存 tar パッケージをローカルのオフライン ミラーにダウンロードします。
- オフライン ミラーからローカル キャッシュへの依存関係を解凍する
- 依存関係をキャッシュから現在のディレクトリの node_modules ディレクトリにコピーします
次に、対応するパッケージがproject のnode_modulesに到着します。
それで、node_modulesのこれらの依存関係はどのようなディレクトリ構造ですか? つまり、上で入力した依存関係ツリーはどのように見えるでしょうか? これは、以下の詳細な説明に依存し、バージョンごとに異なります。
二、npm
npmパッケージ管理ツールの開発履歴に従って、 npm2から始めます。
ノードバージョン管理ツール を使用してノードバージョンを4に減らすと、npmバージョンは2.xになります。
次に、新しいデモを作成し、npm init -yを実行して、すぐにpackage.jsonを作成します。
次にnpm install expressを実行すると、express パッケージとその依存関係がダウンロードされます。
Express を展開します。node_modules もあります
さらにいくつかのレイヤーを展開すると、各依存関係に独自のnode_modules があることがわかります
つまり、npm2 の node_modules はネストされています。
node_modules
└─ express
├─ index.js
├─ package.json
└─ node_modules
└─ 受け入れる
├─ index.js
└─ package.jsonこの構造は、上記の依存関係ツリーと呼ばれるものです!
現在、受け入れ間に依存関係があり、ネストが続行されます。そのようなデザインの何が問題なのか想像してみてください。
- 依存レベルが深すぎるため、Windowsファイル パスが 260 文字までであるため、ネストによってWindowsパスの長さ制限を超えるという致命的な問題が発生します。
- 多数の重複パッケージがインストールされており、ファイル サイズが非常に大きくなっています。たとえば、expressの統計ディレクトリにfooがあり、両方が同じバージョンのLodashに依存している場合、Lodash は2 つのnode_modulesにインストールされます。つまり、インストールを繰り返すと、比較的大きなディスク領域が占有されます。 .
- モジュール インスタンスは共有できません。たとえば、React にはいくつかの内部変数がありますが、2 つの異なるパッケージで導入された React は同じモジュール インスタンスではないため、内部変数を共有できず、予期しないバグが発生します。
当時、 npmはまだ解決していませんでしたが、コミュニティはyarnという新しい解決策を考え出しました:↓
三、糸
yarn は、繰り返される依存関係と長いネストされたパスの問題をどのように解決しますか?
フラット化、つまり、すべての依存関係がレイヤーごとにネストされるのではなく、すべて同じレイヤー上にあるため、依存関係が繰り返される問題や、パスが長すぎるという問題がなくなります。
node_modulesを削除し、yarnで再インストールし、 yarn add expressを実行しました。
この時点でnode_modules は次のようになります。
すべてが 1 階に配置されており、次のパッケージのほとんどには 2 番目のレベルのnode_modulesがありません。
node_modules
すべての依存関係はディレクトリにフラット化され 、深いネスト関係はなくなりました。このように、新しいパッケージをインストールする場合、ノードのrequireメカニズムに従って、 node_modules
上位レベルでパッケージを探し続け、同じバージョンのパッケージが見つかった場合は再インストールされないため、再インストールが繰り返される問題が解決されます。多数のパッケージをインストールしても、依存関係レベルは変更されません。
しかし、さらにいくつかの依存パッケージを展開すると、まだ入れ子になっている理由がわかりますか?
パッケージには複数のバージョンがある場合があるため、アップグレードできるのは 1 つだけです。そのため、後で同じパッケージの異なるバージョンに遭遇した場合でも、ネスト方法が使用されます。
npmが後で3にアップグレードされた、この paving スキームも採用されました。これはyarnと非常によく似ていもちろん、 yarn はバージョンをロックするyarn.lockも実装しており、この機能もnpmによって実装されています
しかし、 yarnも npm も paved ソリューションを採用しているので、このソリューションで問題ないのでしょうか?
いいえ、まだ多くの問題があります。整理しましょう。
- 構造の不確実性によります。
- 平坦化アルゴリズム自体は非常に複雑で、長い時間がかかります。
- ゴーストの依存関係(平たく言うと、依存関係を宣言していないパッケージには不正にアクセスできます)
後で、どちらもわかりやすいのですが、最初の点の不確実性を どのように理解すればよいでしょうか。
プロジェクトが Barry と Lishen の 2 つのパッケージに依存している場合、これら 2 つのパッケージの依存関係は次のようになります。
では、npm / yarn install の場合、flatten 後はどのような感じでしょうか?
そうですか?
それともこんな感じですか?
答えは次のとおりです: package.json内のBarryとLishenの位置に応じて、どちらも可能です。 Barry が最初に宣言されている場合は前の構造であり、そうでない場合は後者の構造です。これが、依存関係が依存構造の「不確実性」、これが前述のロック ファイルが生まれた理由であり、それがpackage-lock.json (npm 5.X 以降で使用可能、つまり npm3 ) またはyarn.lock 、インストール後に特定のnode_modules構造が生成されるようにすることがすべてです。
では、pnpm はこれら 2 つの問題をどのように解決するのでしょうか?
4.pnpm
npm3とyarn がnode_modules を平坦化する必要がある理由を思い出してください。同じ依存関係が何度もコピーされてしまい、パスが長すぎてwindows下に問題があるのではないでしょうか?
リンクなどを介してコピーしないとどうなりますか。
まず,リンク, つまりソフト リンクとハード リンクを紹介しましょう. これはオペレーティング システムによって提供されるメカニズムです.ハード リンクは同じファイルへの異なる参照であり,ソフト リンクは新しいファイルを作成するためのものであり,ファイルの内容別のパスを指します。もちろん、これら 2 つのリンクの使い方は似ています。
ファイルをコピーせずに、npm パッケージのコンテンツのコピーをグローバル ウェアハウスに保存し、残りの場所をリンクするとどうなるでしょうか?
このように、複数回コピーするためにディスク容量が無駄になることはなく、パスが長すぎるという問題も発生しません。パスが長すぎるという制限は基本的に、ディレクトリ階層が深すぎてはならないということであり、現在は同じディレクトリではなく、さまざまな場所にあるディレクトリへのリンクであるため、長さの制限はありません。
そうです、pnpmはこのアイデアによって実装されています。
node_modules を再度削除してからpnpmで再インストールし、pnpm install を実行します。
次の文が出力されることがわかります。
パッケージは、グローバル ストアから仮想ストア (仮想ストアはnode_modules/.pnpm )に配線されます。
node_modules を開いて見てみましょう。
それは確かにもはやフラットではありません. Express が依存している場合、node_modules の下には Express のみがあり、ゴースト依存関係はありません.
.pnpm を展開して表示します。
すべての依存関係はここに埋め込まれ、グローバル ストアからすべてハード リンクされます。次に、パッケージとパッケージ間の依存関係がソフト リンクによって整理されます。.pnpm/node_modules の下に表示されます。これらはソフト リンクです。
つまり、すべての依存関係はグローバル ストアから.pnpm/node_modulesにハード リンクされ、ソフト リンクを介して相互に依存します。
公式が模式図を出してくれたので、それを見れば理解できます:pnpm公式アドレス
これがpnpm の仕組みです。
振り返ってみると、なぜpnpmは優れているのでしょうか?
まず第一に, 最大の利点はディスク容量を節約することです. パッケージのコピーは1つだけグローバルに保存され、残りはソフト接続とハード接続です. どのくらいのディスク容量が節約されますか.
2 つ目は、コピーではなくリンクを使用することで自然に高速になるため、高速です。
5.実用性の向上
pnpm
ここまで言うと、かなり複雑だと 思います 。
それどころか、pnpm は非常に使いやすく、npm/yarn の経験があれば、シームレスに pnpm に移行することもできます。
それだけですか?以下でより重要なことは、プロジェクト管理方法のサポートです
個人的な感想: pnpm は、次の理由により、Multirepo プロジェクトから Monorepo プロジェクトへの移行をより適切にサポートできます。
A が X に依存している場合、B は X に依存しており、X に依存していないがコード内で X を使用している C があります。依存関係の昇格の存在により、npm/yarn は X をルート ディレクトリの node_modules に配置し、C をローカルで実行できるようにします。これは、node のパッケージ ロード メカニズムに従って、monorepo プロジェクトの node_modules にロードできるためです。ルートディレクトリ X. しかし、C が個別にパッケージ化され、ユーザーが C を個別にインストールすると、X が見つからず、X を参照するコードが実行されるとエラーが直接報告されることを想像してみてください。
要約する
もちろん、今日は詳細な研究にすぎません.パッケージ管理方法は誰にとってもより適しています.それは私たち自身のプロジェクトに依存します.人によって、プロジェクトごとに、ビジネスごとに異なる場合があります~~~
みんなで議論し、一緒に勉強することを歓迎します~~~