Vite+: lint、フォーマット、テスト、タスク実行を vp コマンドに統合する

  • Vite+
  • TypeScript
  • ツールチェーン

TypeScript のリポジトリには、ESLint、Prettier、Vitest、lint-staged、Node.js のバージョン管理ツール、タスクランナーが、それぞれ別の設定ファイルを持って並ぶ。Vite+ では、これらが vp という 1 つのコマンドと vite.config.ts という 1 つの設定ファイルに統合される1。開発元は VoidZero で、MIT ライセンスで公開されている2。Vite の後継ではなく、Vite、Vitest、Oxc、Rolldown の各ツールを 1 つのコマンドから呼び出すための層である2。

コマンド内部で動くもの
vp dev、vp buildVite 8 と Rolldown
vp check、vp lint、vp fmtOxlint と Oxfmt
vp testVitest
vp packtsdown
vp runVite Task
vp install、vp add、vp pm検出されたパッケージマネージャー
vp envNode.js とパッケージマネージャーの版管理
vp hooks、vp stagedGit hooks

設定は vite.config.ts に集約される

defineConfig を vite-plus から import すると、Vite の server や build と同じファイルに lint、fmt、test、run、staged のキーを書ける3。.eslintrc、.prettierrc、vitest.config.ts、.lintstagedrc は不要になる。

import { defineConfig } from "vite-plus";

export default defineConfig({
  fmt: { ignorePatterns: ["out/**"] },
  lint: {
    ignorePatterns: ["out/**"],
    rules: { "no-debugger": "error", "typescript/no-explicit-any": "error", eqeqeq: "error" },
  },
  staged: { "*": "vp check --fix" },
  run: {
    tasks: {
      gen: { command: "node gen.mjs", cache: { output: ["out/**"] } },
      report: { command: "node report.mjs", dependsOn: ["gen"] },
    },
  },
});

lint

vp lint の実体は Oxlint で、ルールは ESLint 互換の名前で指定する。

// src/bad.ts
export const f = (x: any) => {
  debugger;
  return x == null;
};
$ vp lint
src/bad.ts:1:22: error typescript(no-explicit-any): Unexpected `any`. Specify a different type.
src/bad.ts:2:3: error eslint(no-debugger): `debugger` statement is not allowed
src/bad.ts:3:12: error eslint(eqeqeq): Expected === and instead saw ==

lint.options の typeAware と typeCheck を有効にすると型情報を使う検査に切り替わる。ファイルごとの例外は lint.overrides に書く4。

Vite Task

vp run <name> では、package.json の scripts と run.tasks に定義したタスクのどちらも実行できる。違いはキャッシュの有無で、run.tasks のタスクは既定でキャッシュされ、scripts は --cache を付けた場合だけキャッシュされる5。

上の設定では、gen が src/words.txt を読んで out/count.json を書き、report がそれを読む。1 回目は両方が実行される。

$ vp run report
$ node gen.mjs
counted 3 words

$ node report.mjs
report: {"count":3}

vp run: 0/2 cache hit (0%), 2/2 successful.

何も変えずにもう一度実行すると、コマンドは実行されず、保存されていた出力が再生される。

$ vp run report
$ node gen.mjs ◉ cache hit, replaying
counted 3 words

$ node report.mjs ◉ cache hit, replaying
report: {"count":3}

vp run: 2/2 cache hit (100%), 2/2 successful, 88ms saved.

src/words.txt に 1 行追加すると、どのファイルの変更でキャッシュが無効になったかが理由つきで表示される。

$ vp run report
$ node gen.mjs ○ cache miss: 'src/words.txt' modified, executing
counted 4 words

$ node report.mjs ○ cache miss: 'out/count.json' modified, executing
report: {"count":4}

設定には src/words.txt を入力として書いていない。タスクの実行中に読まれたファイル、存在確認されたパス、一覧されたディレクトリが記録され、次回のキャッシュ判定に使われるためである6。cache.output に書いた out/** はキャッシュヒット時に復元されるので、report は gen の成果物を読める。

環境変数の読み取りだけは実行から記録できないので、キャッシュキーに含めたいものを cache.env に、タスクには渡したいがキーには含めたくないものを cache.untrackedEnv に書く6。dependsOn では package#task の形で他のパッケージのタスクも指定でき、vp run -r <task> でワークスペース全体を依存順に実行できる5。

Node.js とパッケージマネージャーの版管理

vp env では Node.js の runtime とパッケージマネージャーの版を管理する。Node.js の版は、近いディレクトリから順に .node-version、devEngines.runtime、engines.node、.nvmrc を探して決定される。nodejs.org から取得したアーカイブは PGP 署名と SHA-256 で検証される7。パッケージマネージャーは packageManager、devEngines.packageManager、lockfile の順で検出され、どれも無ければ pnpm になる8。vp install や vp add は検出されたパッケージマネージャーのコマンドに変換されるため、pnpm のリポジトリでも npm のリポジトリでも、打つコマンドは同じになる。

Git hooks

vp config を実行すると Git hook のディスパッチャがインストールされる。.vite-hooks/pre-commit のようなスクリプトはリポジトリにコミットし、生成物は .vite-hooks/_ の下に置かれて ignore の対象になる9。vp staged には lint-staged 17 が同梱されていて、設定の staged キーに従って staged なファイルだけが検査される9。

# .vite-hooks/pre-commit
vp staged

clone ごとに vp hooks disable で無効化でき、VP_GIT_HOOKS=0 を設定すると一時的にすべての hook が止まる9。

出典

  1. Vite+ Guide - Getting Started. https://viteplus.dev/guide/ ↩

  2. Announcing Vite+ 1.0. https://voidzero.dev/posts/announcing-vite-plus-1-0 ↩ ↩2

  3. Vite+ - Configuring Vite+. https://viteplus.dev/config ↩

  4. Vite+ - Lint config. https://viteplus.dev/config/lint ↩

  5. Vite+ - Run. https://viteplus.dev/guide/run ↩ ↩2

  6. Vite+ - Task Caching. https://viteplus.dev/guide/cache ↩ ↩2

  7. Vite+ - Environment. https://viteplus.dev/guide/env ↩

  8. Vite+ - Package Management. https://viteplus.dev/guide/package-management ↩

  9. Vite+ - Commit Hooks. https://viteplus.dev/guide/commit-hooks ↩ ↩2 ↩3