40. Yarn: A new package manager for JavaScript | Engineering Blog | Facebook Code

Tatsuya Asami
7 min readAug 22, 2018

--

【所要時間】

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段階だ。

  1. Resolution:
    Yarnはレジストリを要求し、それぞれのdependencyを再帰的に調べることで、dependencyを解決し始める。
  2. Fetching:
    次にYarnは必要なパッケージがすでにダウンロードされているかどうかを確かめるため、global cache ディレクトリを見る。もしなければYarnはパッケージのtarballを呼びだし、global cacheに配置する。そのため、それはオフラインで動作し、何度もdependencyのダウンロードを必要としない。dependencyは完全なオフラインインストールのためのtarballとしてsource control に配置することもできる。
  3. 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の方が良さそう。

--

--

Tatsuya Asami
Tatsuya Asami

Written by Tatsuya Asami

Front end engineer. React, TypeScript, Three.js

No responses yet