40. Yarn: A new package manager for JavaScript | Engineering Blog | Facebook Code
【所要時間】
1時間28分(2018年8月22日)
【概要】
Yarnについて
【要約・学んだこと】
JSコミュニティでは、エンジニアが基本的なコンポーネント、ライブラリ、フレームワークをリライトするのを避けるために、コードをシェアしている。それぞれのコードはパッケージマネージャによって管理される。npmがJSでは最も有名なパッケージマネージャだ。
長年Facebookでnpmを使ってきたたが、コードベースのサイズやエンジニアの数が増えたので、セキュリティ、一貫性、パフォーマンスに問題が出てきた。解決策として、Yarnと呼ばれる早く、信頼でき、安全なnpm clientの代替品がつくられた。
Yarnを使えば、npm registryには引き続きアクセス可能だが、パッケージをより高速にインストールでき、マシン間や安全なオフライン環境で一貫してdependencyを管理する。
初期の頃は、package.jsonをチェックし、エンジニアが手動でnpm installを実行するのがベストプラクティスだった。しかし、継続的な統合環境が壊れ、セキュリティや信頼性のためにインターネットからの切断を必要とした。
次の解決策は全てのnode_modulesをリポジトリにチェックすることだった。しかし、これはいくつかの簡単な操作を難しくしたため、変更を結合するのにエンジニアが丸一日費やすこともあった。React Native package.jsonは現在68のdependencyリストしかないが、npm installを実行した後、node_modules directoryは121358ものファイル数になった。
最後に試みたのは、npmクライアントを拡張することだった。node_modules folder全体をzipし、CDN内部にアップロードした。このおかげで、エンジニアと継続した統合システム両方が、ダウンロード可能で、一貫したファイルの抽出も可能だった。
これはソースコントロールから無数のファイルを削除することを可能としたが、pullするときだけでなく、buildする際にもインターネットを必要とした。
また、npmのshrinkwrap機能に関する問題を回避する必要もあった。shrinkwrapファイルはデフォルトで作られるのではなく、エンジニアが作り忘れるとシンクロに失敗する。そのため、shrinkwrapファイルのコンテンツがnode_modulesとマッチするかを認証するツールを書いた。これらのファイルが巨大なJSON blobsのソートされていないキーだったので、それらに変更を加えると、大きく見えにくいコミットを作成する。これを軽減するために、全てのエントリをソートする追加スクリプトが必要だった。
最後に、npmを使って単一のdependencyを更新すると、semantic version ruleに基づき、多くの無関係なものも更新される。これにより全ての変化が予想以上に大きくなった。そしてnode_modulesをコミットし、CDNにアップロードする必要があるので、このプロセスはエンジニアには理想的ではなかった。
Introducing Yarn
Yarnはnpmレジストリと互換性を保ちつつ、npmクライアントか他のパッケージマネージャの既存のワークフローを置き換える新しいパッケージマネージャだ。これはより早く、安全に、確実に動作し、既存のワークフローと同じ機能を持つ。
パッケージマネージャの主な機能はあるパッケージをインストールすることだ。それぞれのコードは特定の目的がある。それぞれのパッケージはおそらく他のパッケージを頼らない。典型的なプロジェクトはdependencyのツリーの中に無数のファイルを持つ。
これらのdependencyはバージョン管理され、semantic versioningを元にインストールされる。semberは、チェンジがAPIを破壊しようが、新しい特徴を加えたりバグをなおそうが、新しいバージョンごとに変化のタイプを反映させ、バージョンスキームを定義する。しかし、semverはパッケージディベロッパーのミスに依存するのではない。dependencyがロックダウンされていなければ、インストールされたdependencyの変更を破棄したり、新しいバグを発見するかもしれない。
Architecture
Nodeエコシステムでは、dependencyはプロジェクトのnode_modules ディレクトリ内に配置される。しかし、このファイルの構成は複製されたdependencyが一緒に統合されるので、実際のdependency treeとは異なる。
npmクライアントはnode_modules ディレクトリに非決定論的にdependencyをインストールする。これはorder dependencyがインストールされ、node_modules_ディレクトリの構造が人によって異なることを意味する。これらの違いは”自分のマシンでは動作する。”バグを引き起こす可能性がある。
Yarnはロックファイルと決定的で信頼できるインストールアルゴリズムを使って、これらのバージョン管理と非決定論に関する問題を解決する。これらのロックファイルは特定のバージョンにインストールされたdependencyをロックし、全てのマシンのnode_modulesのファイル構造が完全に同じという結果を全てのインストールで保証する。書かれたロックファイルは変更が最小で、レビューが簡単であることを保証するために、順序づけされたキーと簡潔なフォーマットを使う。
インストールプロセスは下記の3段階だ。
- Resolution:
Yarnはレジストリを要求し、それぞれのdependencyを再帰的に調べることで、dependencyを解決し始める。 - Fetching:
次にYarnは必要なパッケージがすでにダウンロードされているかどうかを確かめるため、global cache ディレクトリを見る。もしなければYarnはパッケージのtarballを呼びだし、global cacheに配置する。そのため、それはオフラインで動作し、何度もdependencyのダウンロードを必要としない。dependencyは完全なオフラインインストールのためのtarballとしてsource control に配置することもできる。 - Linking:
最後に、Yarnは必要なファイル全てをglobalキャッシュからローカル node_modulesディレクトリにコピーすることで、全てを一緒にリンクする。
Yarnは操作を並列化でき、リソースの使用率を最大化し、インストール処理を高速化する。Fecebookのプロジェクトによっては、Yarnはインストールプロセスを数分から数秒に減らした。Yarnはまた、複数の実行中のCLIインスタンスが互いに衝突したり、互いに汚染したりしないように、mutexを使用する。
全てのプロセスを通じて、Yarnはパッケージインストールに関して厳しい保証をする。どのパッケージがどのライフサイクルスクリプトが実行されるかコントロールできる。パッケージのチェックサムもまた、毎回同じパッケージを取得することを確実にするため、ロックファイルに格納される。
Features
Yarnはdependency管理を単純にするという特徴もある。
- npmとbower両方のワークフローと互換性があり、レジストリを混在できる。
- インストールされたモジュールライセンスと、ライセンス情報の出力手段を制限する能力があ。
- build toolを通じて抽象化されたloggingで、安定したパブリックJS APIを公開する。
- 読みやすく、最小限で、きれいなCLI出力。
【わからなかったこと】
特になし
【感想】
npmより新しいパッケージマネージャ。npmより優れている部分があって、npmとの互換性もあるということなので、yarnの方が良さそう。