🙆‍♀️

yarn --frozen-lockfileで環境によるバージョン差異をなくそう

2024/07/05に公開

npmyarn を利用して複数人で作業をしているとnpm installyarn でパッケージを更新しただけでyarn.lockpackage-lock.json に更新が走る場合はあります。

いろいろなプロジェクトに関わっていると定期的にここではまる人が結構いるのでこの挙動と解決策を解説してみようと思います。

なぜyarn.lockpackage-lock.json に更新が走るのか

パッケージのインストール時にnpm installyarn を利用すると、package.json に記載された依存関係のバージョンを元に、実際にインストールするパッケージのバージョンが決定されます。

その際に生成されるのがnpmの場合はpackage-lock.json が、yarn の場合はyarn.lock が生成されます。

これらのファイルは現在インストールを行ったパッケージのバージョンが依存関係も含めて記述されています。

たとえば、yarn add exsample-package とパッケージをインストールした場合に以下のようなpackage.json が生成されたとします。

package.json
{
  "name": "example-project",
  "version": "1.0.0",
  "dependencies": {
    "exsample-package": "^1.2.3",
  }
}

実際にこのタイミングではexsample-package1.2.3 のものがインストールされており、yarn.lock にもその情報が記述されています。

数日後にyarn コマンドでパッケージの更新を行います。この際にインストールされるexsample-packageのバージョンは1.2.3とは限らず^1.2.3 の範囲つまりpackage.json のバージョン指定の冒頭にキャレット(^)があるため1.2.3 から 2.0.0までで最新のバージョンがインストールされます。

つまり、現在のexsample-packageの最新が1.3.5の場合は1.3.5がインストールされます。

yarn.lockpackage.json と違いバージョン指定が正確に記載されているので、インストールされたバージョンが異なる場合はバージョンが変更され差分が発生します。

人によって1.2.3がインストールされていたり1.3.5がインストールされていたりするということは人によって利用しているバージョンが異なるということになります。

こういったパッケージのバージョン違いによる挙動の差異が発生することがあります。

yarn --frozen-lockfileyarn.lock のバージョンをインストール

この挙動の差異をなくすために利用されるのがyarn --frozen-lockfile です。このコマンドでパッケージの更新を行うとyarn.lock に記載されているバージョンをもとに更新が行われるので環境によるバージョンの差異が発生しません。

CIなどでデプロイする際には未検証のバージョンが本番に混入しないために必須の設定となっています。

yarn ci

yarn --frozen-lockfileと打てばよいのがわかっても、
yarn --frozen-lockfile が長くて覚えにくくて打つのが面倒くさい問題というものが発生します。
その場合はpackage.jsonに以下の記述をしておきましょう。

package.json
  "scripts": {
    "ci": "yarn --frozen-lockfile",
  },

こうするとyarn ciと打つだけでyarn --frozen-lockfile と同じ更新方法が可能です。

ちなみにnpmの場合は同様の機能がnpm ci というコマンドで用意されているのでそこに準拠することで覚えやすいコマンド名になっています。

yarn.lock のバージョンを更新していく運用方法

上記のyarn.lockを更新せずに運用していくが割とディフェンシブな運用なのですが、yarn.lockを更新しながらオフェンシブに運用していく方法もあります。

この運用の場合はyarn などでyarn.lock に更新が走った場合に更新情報をGitpushしてプロジェクトで最新のバージョンを共有します。

このままでは人によってバージョンが違う問題が発生してしまいますが以下のように起動時に最新になるように設定をしておけば古いバージョンを使い続けるという現象を減らすことができます。

package.json
  "scripts": {
    "dev": "yarn && yarn start"
  }

ただ、package.json の指定内で最新バージョンを使い続けることができる反面、検証が薄いバージョンが本番環境にリリースされたり、Gitのコンフリクトが発生しやすい名でデメリットも多く熟練されたチーム以外だと生産制が落ちることがあるので導入は慎重にする必要があります。

折衷案として起動コードを以下のようにしてyarn.lock に更新頻度を下げるという方法もあります。

package.json
  "scripts": {
    "dev": "yarn --frozen-lockfile && yarn start"
  }

これらを知らなくても問題になることは少ないのですがyarnnpm installでパッケージを更新しているプロジェクトがあったら一度見直してみてよいかもしれませんね。

株式会社トゥーアール

Discussion