🛠️

言語・ツール・環境変数・タスクランナーの全てを集約する開発環境ツール mise のご紹介

2024/04/09に公開

mise とは

Home | mise-en-place
mise (呼びはミーズ) は公式の説明によると開発環境のセットアップツールで以下の 3 つのカテゴリーに分類される機能があります。

  • プログラミング言語や開発ツールの管理
    • asdf 互換で asdf の plugin も利用できます
  • 開発用の環境変数の管理
    • 独自の機能に加えて dotenv ファイルも利用できます
  • タスクランナー
    • ファイルの変更を検知し自動実行する機能もあります

まだタスクランナー機能は experimental となっているのでこの機能を使うかは慎重に検討する必要がありますが、どの機能の設計も開発でまさに求めてたと言える良いものに感じました。今までは別々のツールで行っていた部分を統一したり、開発環境の初期セットアップはこの 1 ツールを起点に行えるようにする事も可能なように感じています。また、Rust 製な事とツール等の PATH を通すのに shims スクリプトを通さずに直接 PATH を書き換える形式により高速に動作する点もおすすめです。

Setup

Getting Started | mise-en-place
様々な環境向けのインストール方法が用意されていますが代表的な方法だけ記載しておきます。

brew install mise
cargo install mise
curl https://mise.run | sh

インストールしたら activate されるようシェルの設定ファイルに追記します。

.zshrc

if type mise &>/dev/null; then
  eval "$(mise activate zsh)"
  eval "$(mise activate --shims)"
fi

筆者がよくやるコマンドが存在する場合のみ有効化する形式にしています。
curl を使ったインストール方法の場合は ~/.local/bin/mise へ、zsh 以外のシェルを利用している方は公式ドキュメントを参考に自身のシェルのものへ置き換えて下さい。

IDE Integration | mise-en-place
mise activate --shims は PATH に shims を追加する為です。mise は PATH を動的に変更する形式な為、 mise activate zsh だけだとインストールした言語やツールをエディタ等の対話シェル以外からは利用できないので追加しています。上記のように設定すれば対話シェルでは mise の PATH 変更形式を利用しつつ、エディタ等でも利用できるようになります。

設定ファイル

Configuration | mise-en-place
mise 独自の .mise.tomlasdf 互換の .tool-versions が利用できます。これらの設定ファイルがあるディレクトリ以下では、設定ファイルに書かれた言語やツールが利用できるように有効化されます。

.tool-versions は言語やツールのバージョンしか設定できませんが、.mise.toml は環境変数の設定といった独自の機能や plugin にオプションを指定したりとより柔軟に設定できるので、基本的には .mise.toml の利用が推奨されています。

設定ファイルは階層構造になっており、複数の設定ファイルが存在する場合はカレントディレクトリの設定が親ディレクトリにある設定を上書きマージします。

mise 自体の設定も含めたグローバルな設定を行いたい時は ~/.config/mise/config.toml が利用できます。

Profiles | mise-en-place
開発プロジェクト用の .mise.toml は複数の場所に設置可能で、.mise.production.toml といった環境をわけたファイルも作成可能です。具体的なファイルの読み込まれる順は上記のドキュメントを参照下さい。

Legacy version files
mise.node-version.ruby-version といった各種言語向けのバージョン管理ツールの設定ファイルにも対応しているので、既存のツールからの移行をする際もスムーズですし、開発チームに特定のツールを強制せずに使うといった事も可能です。

言語やツールの管理

Commands | mise-en-place
利用頻度の高そうなコマンドだけリストアップします。

ツールのインストール及び使用

mise install [OPTIONS] [TOOL@VERSION]...
mise install は指定もしくは設定ファイルに書かれたバージョンのツールをインストールします。このコマンドはインストールだけなので設定ファイルに書かれていないツールは利用できません。尚、バージョン指定の解釈は他のコマンドでも同様なので以降では省略します。

# 設定ファイル指定のものをインストール
mise install
# 設定ファイルがあれば指定のバージョン、なければ実行時点の最新版の node をインストール
mise install node
# 20 系の最新版をインストール
mise install node@20
# 指定バージョンをインストール
mise install node@20.0.0

mise use [OPTIONS] [TOOL@VERSION]...
ツールの有効化は mise use コマンドを利用します。このコマンドはプラグインやツールがインストールされていない場合はインストールも行ってくれます。また、有効化 = 設定ファイルにツール名とバージョンを記載という事になります。

# カレントディレクトリの .mise.toml へ
mise use node@20
# カレントディレクトリの .mise.local.toml へ
mise use --env local node@20
# グローバルの設定 .config/mise/config.toml へ
mise use -g node@20
# グローバルの設定に具体的なバージョンを記録
mise use -g --pin node@20

基本的には mise use でインストールと有効化を行い、既存の設定ファイルがある時に mise install を利用する形になると思います。

利用可能なツール及びバージョンの確認

mise plugins ls-remote [OPTIONS]
利用可能なツールを確認したい時はツール = プラグインなので、以下のコマンドでプラグインを一覧表示して確認します。

mise plugins ls-remote

mise ls-remote [OPTIONS] [TOOL@VERSION] [PREFIX]
実行時点でインストールできるツールのバージョンを一覧表示します。

mise ls-remote node
# インストール済みのプラグインを全て対象にする
mise ls-remote --all

mise latest [OPTIONS] TOOL@VERSION
指定したツールの最新バージョンのみを確認したい時は以下のコマンドが利用できます。

mise latest node@20

ツールのアンインストール

mise uninstall [OPTIONS] [TOOL@VERSION]...
不要なツールをアンインストールしたい時は mise uninstall で行います。

# ツールのアンインストール
mise uninstall node@20

ツールのアンインストールだけなので設定ファイルからの削除は手動で行う必要があります。

ツール情報の一覧表示

mise ls [OPTIONS] [PLUGIN]...
現在認識しているツールの情報を一覧表示します。システム自体にインストールされているものや設定ファイルに記載されていて認識しているがインストールはされていないものなども含めて表示されるので認識したという表現になっています。

mise ls
# 特定ツールのみ
mise ls node

プラグイン管理

Commands | mise-en-place
プラグインのインストールは mise usemise install 時にも行われるので利用するのは mise plugins ls-remote で利用可能なツールの確認とアップデートが主になると思います。

# 利用可能なプラグインを一覧表示
mise plugins ls-remote
# インストール済みのプラグインを一覧表示
mise plugins ls
# プラグインのインストール
mise plugins install terraform
# プラグインのアップデート
mise plugins update terraform
# プラグインのアンインストール
mise plugins uninstall terraform

他言語のツール

Backends | mise-en-place
experimental なので詳細には触れませんが mise install cargo:tool といった形式で別言語のパッケージマネージャーで提供されているツールを mise 介してインストール及び管理できる機能が開発中です。

環境変数の管理

Environments | mise-en-place
mise の環境変数の機能は .mise.toml[env] もしくは [[env]] セクションに記述する事で利用できます。[[env]] は配列にあたるもので後述する _.* ディレクティブを複数利用する為に使います。

[env]
NODE_ENV = 'production'
# 未定義状態にしたい時は false を設定する
CI = false

環境変数の設定は CLI のコマンドでも行えます。

# 環境変数の設定
mise set NODE_ENV=development
# 値の省略で設定値の確認
mise set NODE_ENV
# 引数なしで全ての環境変数を一覧表示
mise set
# 環境変数の削除
mise unset NODE_ENV

_.* ディレクティブ

_.* の形式でいくつかの機能を利用する事ができます。

dotenv ファイルの読み込み

[env]
_.file = '.env'

環境変数 PATH への追加

[env]
_.path = [
  '~/.local/bin',
  './node_modules/.bin',
]

bash のスクリプトファイルの実行

[env]
_.source = './script.sh'

スクリプトファイルの shabang は無視されるので多言語は使えず bash で実行できるスクリプトファイルのみとなります。

これらのディレクティブは 1 つの [env] セクションに 1 つしき記述できないので複数利用したい場合は配列にあたる [[env]] セクションを利用します。

[[env]]
_.source = './script1.sh'
[[env]]
_.source = './script2.sh'

テンプレート機能

Templates | mise-en-place
他の環境変数やコマンドの実行結果などを利用して値を設定する事ができます。利用する際は {{ }} 内に下記の利用できる機能を記述します。

  • env.*
    • 環境変数の参照
  • config_root
    • .mise.toml ファイルのあるディレクトリのパス
  • exec(command: <cmd>)
    • <cmd> に指定したコマンドの実行結果の文字列
[env]
ENV_FILE = '.env.{{ env.NODE_ENV }}'
PROJECT_LIB = '{{ config_root }}/lib'
NODE_VERSION = "{{ exec(command='node --version') }}"

タスクランナー

Tasks | mise-en-place
mise のタスクランナーは .mise.toml に設定されたツールや環境変数が有効な状態でタスクを実行する事ができます。その他、以下の特徴や機能があります。

  • デフォルトで依存タスクは並列に扱われる
  • 少し設定すれば変更がない時はスキップされるタスクを定義できる
  • mise watch の機能によりファイルの変更を検知しての自動実行が行える
  • スクリプトファイル形式なら各種言語の開発ツールやシンタックスハイライトが利用できる

タスクの定義方法は以下の 2 種類の方法が利用できます。

  • .mise.toml[tasks.*] セクション
  • .mise/tasks ディレクトリに配置するスクリプトファイル

お手軽に利用できますしワンライナーに近いものであれば .mise.toml に定義する方法でも十分ですが、処理がある程度大きいものはスクリプトファイル形式がおすすめです。

タスクの設定方法の前にタスクに関連したコマンドの機能や利用方法を理解した方が設定パラメータと紐づけやすいと思うのでそちらを先に説明します。

タスクの実行

Running Tasks | mise-en-place

利用可能なタスクの一覧表示

mise tasks
# hide=true も含めて表示
mise tasks --hidden
# タスクの依存関係を表示
mise task deps

タスクの実行

タスクを複数指定時は並列に実行されます。また、この際のデフォルトの並列数は 4 でコマンド引数の --jobs、設定ファイルの jobs、環境変数の MISE_JOBS で変更できます。

mise task run build
# or
mise run build
# ワイルドカード指定
mise run lint:*
# 引数付き
mise run build --release
# 複数のタスクのそれぞれに引数を付与 ::: が区切り文字
mise run lint --fix ::: format --apply

ファイル監視による自動実行

mise watch コマンドを利用するとファイルの変更を検知して自動的にコマンドを再実行させる事ができます。基本的には後述する sources のオプションと併用するのですが、-g, --glog のコマンド引数で指定や上書きする事も可能です。

2024/04/05 時点では mise watch に必要なツールのインストールが必要です。

mise use -g watchexec@latest

実行例

mise watch -t build
mise watch -t build -g src/**/*.ts

TOML 形式

TOML-based Tasks | mise-en-place
.mise.toml[tasks.name] の形式でセクションを作りタスクを定義します。

  • description
    • タスクを一覧表示した時に表示される説明文です
  • run
    • シェルで実行するコマンドを指定する
    • 配列形式で複数のコマンドも設定可能です
    • 複数行リテラル文字列を使った簡易のスクリプトも記述できます
  • sources
    • タスクの依存ファイルを配列形式で指定します
    • 指定には glob パターンが利用できます
  • outputs
    • タスクの成果物となるファイルを配列形式で指定します
  • hide
    • true を設定すると一覧表示の対象から除外されます
    • 完全に見えないわけではなく --hidden のオプションで表示できます
  • depends
    • 依存タスク名を配列形式で指定します
    • 指定された依存タスクは先に実行されます
    • depends のみを定義したタスクも作成可能です
  • alias
    • タスクの別名を設定できます
  • dir
    • タスクを実行する際のディレクトリを指定します
    • デフォルトはプロジェクトのルートディレクトリです
  • env
    • そのタスクでのみ有効な環境変数を辞書形式で指定します
  • file
    • タスクと実行するスクリプトファイルを指定します
[tasks.clean]
run = 'rm -rf build'
hide = true

[tasks.build]
description = 'Build the app'
run = 'pnpm build'
alias = 'b'

[tasks.test]
env = { NODE_ENV = 'test' }
run = [
  'pnpm check-types',
  'pnpm lint',
  'pnpm test',
]
dir = '{{ cwd }}'

[tasks.name]
run = """
#!/usr/bin/env zx
await $`cat package.json | grep name`
"""

[tasks.ci]
depends = ['test', 'build']

[tasks.release]
file = 'scripts/release.sh'

ファイルの変更検知

成果物が存在しない時やファイルに変更がある時のみタスクを実行したい時は sourcesoutputs のオプションをタスクに設定する事で行えます。2024/04/05 時点ではファイルのタイムスタンプによる判定のみとなっています。

[tasks.build]
run = 'pnpm build'
sources = ['tsconfig.json', 'src/**/*.{ts,tsx}']
outputs = ['build/index.js']

タスクのグルーピングと利用方法

タスクは : を区切り文字としてグルーピングする事ができます。グルーピングしたタスクはタスク実行時や depends で指定する際に以下のワイルドカードパターンが利用できます。

  • ?
    • 任意の 1 文字
  • *
    • 任意の 0 以上の文字
  • **
    • 0 以上のグループ
    • 複数ネストしたグループなどに利用
  • {glob1,glob2,...}
    • {} 内に指定した , 区切りの glob パターンのいずれか
  • [abc,...]
    • [] に指定した文字のいずれか
    • [a-z] の範囲指定も可能
    • [!abc] と先頭に ! を付与時は一致しない文字が対象となる
mise run generate:{completions,docs:*}
[tasks."lint:eslint"]
run = 'eslint .'
[tasks."lint:type"]
run = 'tsc --noEmit'
[tasks.lint]
depends = ['lint:*']

スクリプト形式

Script Tasks | mise-en-place
.mise/tasks/:task_name の形式でスクリプトファイルを作成すると mise がタスクとして自動的に認識してくれます。ファイルに実行権限がないと認識しませんので必ず付与して下さい。

タスクをグルーピングしたい時はサブディレクトリを作り、そこにスクリプトファイルを配置すればディレクトリ名をグループ名としてグルーピングされます。例えば、.mise/tasks/test ディレクトリに unitintegration のファイルがあれば、それぞれ test:unittest:integration というタスクになります。

スクリプトファイルの作成や編集は mise の CLI を経由して行う事も可能です。mise task edit <taskname> のコマンドを実行するとファイルがない場合は作られ、EDITOR 環境変数に設定されたエディタでファイルが開きます。

スクリプトは shabang が有効なのでシェルスクリプト以外の言語を使って作成する事も可能です。以下のサンプルは TOML 形式と同様のオプションの設定方法も含めたものです。

#!/usr/bin/env bash
# mise description="Build the server"
# mise alias="b"
# mise sources=["tsconfig.json", "src/**/*.{ts,tsx}"]
# mise outputs=["build/server.js"]
# mise env={NODE_ENV = "production"}
# mise depends=["lint", "test"]
# mise hide=true
pnpm build

その他

省略したり等で説明できていない機能や設定のうち、特に参考になりそうな公式ドキュメントのページだけ紹介しておきます。

Discussion