npm-package-json-lint で package.json 内のバージョン指定を固定化する

Node.js では、package.json によって依存するパッケージを管理します。 package.json には各パッケージごとにバージョンを指定しますが、 チルダ記法キャレット記法のようにバージョンを範囲指定することもできます。

リリース済みのプロダクトの場合、package.json に指定するバージョンは、一般的には固定値で指定するのが良いでしょう。 バージョンを固定することで破壊的な変更が入ったアップデートを意図せずリリースしてしまうことを防ぐことができるからです。

しかし新しくパッケージをインストールした際、うっかりこのバージョンを固定することを(僕は)忘れることがあります。今回はこれを防ぐためのツールを紹介します。

npm-package-json-lint

package.json の linter としてnpm-package-json-lintがあります。 これは package.json の記法が指定したルールに則っているかどうかをチェックするツールです。

npm-package-json-lint には package.json の記法に関する様々なルールを指定できますが、今回はバージョン固定についてのみ紹介します。他のルールについては公式ドキュメントを参照してください。

設定

設定ファイルの構築方法にはいくつかパターンがありますが、今回は一番簡単なnpmpackagejsonlint.jsonを配置する方法を紹介します。

repository のルートに npmpackagejsonlint.json を配置し、以下のように設定します。

{
    "rules": {
        "prefer-absolute-version": "error",
        "prefer-absolute-version-devDependencies": "error"
    }
}

今回は以下2つの設定を行いました。

  • prefer-absolute-version は dependencies に指定されたパッケージのバージョンが固定になっているかをチェックします。
  • prefer-absolute-version-devDependencies は devDependencies に指定されたパッケージのバージョンが固定になっているかをチェックします。

npm-package-json-lint の実行

今回は以下のような package.json を用意しました。

{
    "dependencies": {
        "react": "^18.2.0",
        "react-dom": "^18.2.0"
    }
}

ここでは react, react-dom のバージョンがチルダ表記で指定されています。 この状態だと patch 以下のバージョンが固定化されておらず、パッケージのインストール時に意図しないバージョンがインストールされる可能性があります。

ではこの状態で lint を実行してみましょう。すると以下のようなエラーが表示されるはずです。

yarn npmPkgJsonLint .
✖ prefer-absolute-version-dependencies - node: dependencies - You are using an invalid version range. Please use absolute versions. Invalid dependencies include: react, react-dom
1 error
0 warnings

Totals
1 error
0 warnings
0 files ignored

エラーからはprefer-absolute-version というルールに違反していることがわかります。

それでは以下のようにバージョンを固定しましょう。

{
    "dependencies": {
        "react": "18.2.0",
        "react-dom": "18.2.0"
    }
}

これでエラーは解消されます。

yarn npmPkgJsonLint .
✨  Done in 0.87s. # エラーが出ない

CI での実行

これを GitHub Actions などのワークフローに組み込むことで、バージョンが固定されていないパッケージをリリース前に発見することができます。 以下は GitHub Actions の CI ワークフローに追加した例です。

name: CI
on: [push]
jobs:
    lint:
        name: lint
        runs-on: ubuntu-latest
        timeout-minutes: 20
        steps:
            - uses: actions/checkout@v3
            - uses: actions/setup-node@v3
              with:
                  node-version-file: "package.json"
                  cache: "yarn"
            - run: yarn install
            - run: yarn npmPkgJsonLint .

CI のステップ内でnpm-package-json-lintを実行することで、package.json のルールに違反しているパッケージがあればエラーが出力されます。

これでコードレビュー時にバージョンが固定されていないパッケージが追加されていないか確認する必要がなくなりました。