🧰

npm に無いツールを npm パッケージとして管理して renovate でバージョンの更新をする

2024/09/23に公開

はじめに

Web フロントエンドのリポジトリ内で typos を使いたいと考えた。

https://github.com/crate-ci/typos

typos は rust 製のツールで npm のパッケージとして公開されていない。したがって、このツールを利用したい場合は、システムにインストールする必要がある。

一方で、システムにインストールされているツールへの依存が増えると、複数人で開発を行う場合、利用者間のバージョンの違いなどが問題になる。

そのようなツールのバージョン管理の仕組みを導入すればこの問題は解決されるだろうが、できるだけ開発を簡単に始めたいので要求するツールは Node だけ (あるいは Node のバージョン管理ツール) にしたい。

ここでは、typos などの rust や go で実装され各プラットフォーム向けのバイナリが提供されているツールを Node のプロジェクトで管理する方法について記載する。
管理されたツールは継続的にバージョンアップを行いたいため renovate でバージョンの更新をできるようにする。

以下が実装例

https://github.com/sterashima78/rust-tool-use-with-npm-test

方針

  • monorepo 内のプライベートパッケージとして typos の実行ファイルを持つパッケージを持つ
  • typos のバージョンとプライベートパッケージのバージョンを一致させ、renovate でこのバージョンを更新させる

typos を プライベートパッケージとして管理する

typos は Release ページでバイナリを各プラットフォーム向けにダウンロードできる。

https://github.com/crate-ci/typos/releases

そのため、npm install をしたときにここから適切なファイルをインストールすれば良い。
これは postinstall フックで対象のファイルをダウンロードするようなスクリプトを実行すれば実現できる。

https://github.com/sterashima78/rust-tool-use-with-npm-test/blob/2bf550a1c55136671fb5cafa1e181679113812c1/packages/typos-cli/package.json#L6-L8

スクリプトの全体は以下。なお、構成の検証をすることが主目的だったのでスクリプトの大半は ChatGPT に書かせている。

https://github.com/sterashima78/rust-tool-use-with-npm-test/blob/2bf550a1c55136671fb5cafa1e181679113812c1/packages/typos-cli/install.js

以降で主要な部分の説明をする。

以下の情報があれば対象のファイルを選択できる

  • 利用者の環境の情報 (OS など)
  • バージョン

利用者の環境の情報は process.platformprocess.arch の情報で十分

https://github.com/sterashima78/rust-tool-use-with-npm-test/blob/2bf550a1c55136671fb5cafa1e181679113812c1/packages/typos-cli/install.js#L99-L100

この情報を元にファイル名を特定する

https://github.com/sterashima78/rust-tool-use-with-npm-test/blob/2bf550a1c55136671fb5cafa1e181679113812c1/packages/typos-cli/install.js#L21-L42

対象のバージョンは package.json の version フィールドに記載されているため、これを使えば対象の URL が特定できる。

あとは、ファイルをダウンロードして、適当な場所に展開すれば良い。
ここで、ダウンロード時、バージョン情報が記載されたファイルを配置することで、すでにインストールされているときに無駄な処理を行うことを回避できる。

renovate でバージョンの更新ができるようにする

renovate には regexManagers という機能があり、正規表現でファイルからバージョン情報を抜き出し、指定したソースに基づいてバージョンの更新ができる。

(今はドキュメントをみた感じだと customManeger の type regex を指定するのが正しそう https://docs.renovatebot.com/configuration-options/#custommanagers

ここでは、プライベートパッケージのバージョン情報を typos リポジトリの tag 情報で更新するように設定する。

具体的な設定は以下

https://github.com/sterashima78/rust-tool-use-with-npm-test/blob/2bf550a1c55136671fb5cafa1e181679113812c1/renovate.json

これで、プライベートパッケージの version を更新する PR が作成される。以下が具体例。

https://github.com/sterashima78/rust-tool-use-with-npm-test/pull/4

前述の通りダウンロードされる typos のバージョンはプライベートパッケージの version と一致しているので、これで最新のバージョンの typos が利用できる。

おわりに

monorepo のプライベートパッケージとして、npm に無いツールを管理する方法について記載した。

rust や go など、動作が速く、インストールするだけで動かせるバイナリを作れる言語がよく使われるようになったことで有用なツールが増えてきたが、これらをシステムにインストールして運用するとチームメンバー間でバージョン差異が発生する問題があった。

今回提案した方法を用いることで、この問題を解決し npm install をするだけでそのプロジェクトで使っているツールがインストールできるようになる。

余談だが、このようなケースやモジュールの切り出しを容易に行うために、基本的にアプリケーションを実装する際は monorepo の構成を取っておいたほうが良いと思っている。
monorepo ではない構成で、このようなことをやろうとすると、独自のルールなどに基づいた構成を取る必要なるためだ。

Discussion