ノベルチーム Webアプリケーションエンジニアの
id:polamjag です。
最近、ノベルチームの開発で使っているリポジトリにおいて、開発環境の起動をはじめとしたコマンド実行のためのタスクランナーとして、miseを使うようにしました。
miseはツールのバージョン管理ツール*1として導入しているケースは多いと思います。一方で、それ以外の機能がたくさん入っている便利ツールであることは知っていても、実際にはそこまでいろいろな機能は使っていない、という方もそれなりにおられるのではないかと思うので、事例として書いておこうということで筆を執った次第です。
結論
- もともとTaskを使っていたところから普通に移行でき、特に困らず暮らしています
- miseの多機能さから、リポジトリ全体で開発に必要なツールを減らせた
- Taskfile/foreman/*env を miseに一本化
- タスクランナーまでmiseに寄せたことで、手元環境で意識すべきツールが減り、構成を整理できた
- miseの多機能さから、リポジトリ全体で開発に必要なツールを減らせた
経緯
前史
さて、今回話題にするリポジトリにおいては、これまではタスクランナーとしてTask(Taskfile.yaml)を使っていました。TaskはGo製のOSSなコマンドラインツールで、タスクをYAMLでいい感じに定義できるというものです。さらにその前はmakeを使っていました。
Taskには特に不満もなく、便利に使っていました。ところがあるとき、手元の開発環境の構成を大きく変更する機会があり、そのときに複数のタスクを並列に実行するという設定が素直に書けず困る、ということがありました。このときは、一旦その部分だけProcfile+foremanを併用することにして凌ぐことにしました。
なぜこれが必要だったのかというと、手元においてDocker Composeだけですべてのサービスを起動していたのを、一部のサービスだけはマシン上でそのまま起動することにした結果、 docker compose up 的なコマンドと、別のサービス群の起動コマンドたちを並列に実行したくなった、というわけでした。
Taskfileにおいて、あるタスクの依存を表現する deps フィールドを使うと、その部分は並列で起動されるので、用途上は使えなくはありません。一方で、別に何かの依存というつもりはないのだが、というところが個人的に引っかかったこともあり、先に述べた構成を取ることにしました。
……といった経緯を書くために、あらためてTaskfileのドキュメントを見返していたところ、
You can also make the tasks given by the command line run in parallel by using the
--parallelflag (alias-p). Example:task --parallel js css.
という記載があることに今気づいてしまい、これで良かったのでは???
とはいえ、冒頭に結論で述べたようにmiseに統一できたメリットはあったので、その話を続けます。
ツール管理ツールとしてのmise導入
その後しばらくして、別件で手元環境のセットアップ手順のドキュメントを整理していました。そのドキュメントは「このステップ用のツールを brew install ... してね」という記載が点在しているのを、その都度コピペして実行するという構成になっていました。
ここで、miseを使えばNode.jsなどのランタイムと同時にそれらのツール群もまとめて mise install で済ませられるのでは?という話になり、実際に試してみたところ便利だったので導入に至りました。
ちなみに、miseではidiomatic filesとして .perl-version も認識するようになっています。…というpull requestをチームメイトの
id:ergofriend が出していました。
タスクランナーのmise化
その後、miseにはそういえばタスクランナーの機能もあったような…ということを思い出してドキュメントを眺めていたところ、miseのタスクランナー機能は並列に実行するタスクを明に定義することができるという記述を発見します。
[tasks.grouped] run = [ { task = "t1" }, # run t1 (with its dependencies) { task = "build", args = ["--release"], env = { RUSTFLAGS = "-C opt-level=3" } }, { tasks = ["t2", "t3"] }, # run t2 and t3 in parallel (with their dependencies) "echo end", # then run a script ]
そのときは上記のTaskの --parallel オプションに気づいていなかったので、foremanを併用する複雑な構成をなんとかできるかも、ということで移行を試してみました。
移行作業自体はClaude Codeに素朴なプロンプト*2を与えるだけで完了してしまったので、とくに書くべきことはなさそうです。YAMLからTOMLへの機械的な読み替えではあるので、てきとうなワンライナーなどでも移行できはしそうな気もします。
miseのタスクランナー機能には、私たちがTaskで使っていた機能が揃っていたので、何かしらを諦めつつ移行するということは特にありませんでした。
- CIで実行する用のタスクを定義しつつ、
mise tasksとかに出てくる必要はないので隠したいケース - makeのように、依存ファイルの更新がなければタスク実行をスキップしたいケース
- → sources や outputs で指定できる
- foo.cが更新されてなければfoo.oを生成し直す必要はない、というようなアレなわけですが、package.jsonとpnpm-lock.yamlが更新されていなければpnpm installし直す必要はない、というようなケースに使えることもある
- シェルスクリプトをそのままタスクとして登録できる
- → File Tasks機能
- Taskfileなどだと、適当な場所にシェルスクリプトを置き、それを呼び出すタスクの定義を追加する、という形になるところを、一撃で定義できる
また、比較的シンプルな構文であるProcfileよりは、miseのタスク定義のほうが明確に使いやすいとも感じます。Procfileは単にコマンドを書けるだけなので、リポジトリのルートではない別のディレクトリで、環境変数を指定しつつコマンドを実行したいとなると
foo_service: cd packages/foo; SOME_ENV=abc ANOTHER_ENV=xyz npm run dev bar_service: cd packages/bar; SOME_ENV=1234 ANOTHER_ENV=5678 npm run dev
というような記述になり、目が滑る感じになってしまいます。一方で、miseのタスク定義では作業ディレクトリや環境変数を構造的に指定できるので、このような問題はありません(これはTaskでもできます)。
補足
- リポジトリに mise.toml を追加する形になるため、初回は
mise trustが必要になります- miseというツールに乗り換えるので
brew install miseしたうえでmise trustも実行してください、とチーム内で適宜案内しました
- miseというツールに乗り換えるので
- CI上では jdx/mise-action を使ってセットアップしています
おわりに
ということで、miseをタスクランナーにも使うようにした話でした。このエントリの執筆にあたりTaskの --parallel の存在に途中で気づきはしたものの、複数のツールをmiseに集約できたというメリットは得られているので、結果オーライということにします。
みなさんはどのツールをどう使っていますか?miseのこの便利機能を使っているとか、このタスクランナーを使っている、というような話があればぜひ共有していただければ嬉しいです。