TSKaigi 2026事後勉強会


Vite+を爆速で社内デザインシステムに導入してみた


ぶりお @burio_16

ぶりおの写真

自己紹介

  • ぶりお @burio_16
  • タコスとTottenham Hotspur FCが大好き
  • TSKaigiは初参加でした
  • VoidZeroのハァン

VoidZero のハァンです

ぶりおが @vitejs を GitHub Sponsors でスポンサーしたツイートTSKaigi 会場で「Vite+」と書かれた扇子を持つぶりおと VoidZero メンバーのツーショット

スポンサーするくらいには好き。会場では扇子にVite+と入れてもらってAlexとツーショ撮った。

そもそも Vite+ って?

Vite+ とは

  • test / lint / fmt / task / Nodevp ひとつに束ねる統合ツールチェイン
  • 中身は Vite / Vitest / Oxlint / Oxfmt / tsdown / Vite Task(VoidZero 製)
  • 2026/3/13 公開・まだ α 版

Vite+ が解決する課題

  • 他の言語:統合ツールチェインが 当たり前
  • JS:ツールの選択肢が多く、環境ごとにバラバラになりがち
  • → その課題を Vite+ が解決

設定ファイル、散らばりがち

text
Before: ツールごとに設定が散らばる
  turbo.json
  vitest.config.ts
  oxlint / oxfmt の設定
  lefthook.yml
  ...

After: vite.config.ts に寄せられた
  vite.config.ts  ← test / lint / fmt / build / task
  • test / lint / fmt / build / task / hooks が 別々の道具になりがち
  • Vite+ はこの散らばりを vite.config.ts に寄せる

どこに導入した?

社内デザインシステム

  • 社内で デザインシステム を開発中
  • 構成は Vite + Vitest + Oxlint + Oxfmt のモノレポ(タスクは Turborepo)
  • → Vite+ が束ねる範囲と ほぼ重なっていた

爆速(当社比)で移行

3/13 → 3/24

  • 公開から移行完了まで、わずか 10日ちょっと
  • α版をもう本番に投入

なぜ飛び込めた?

  • まだ 本格運用前(リプレイス後に使う想定)
  • 元から ツールがほぼ Vite+ の範囲内(Vite/Vitest/Oxlint/Oxfmt)
  • とはいえ α 版なので 最後の一歩は躊躇

マネージャー
ビルドできればいいんじゃない?

ほな導入したろか!

爆速!!(当社比)

Vite+ への移行 PR #135(Turborepo 廃止・ツールチェーン統合、25 commits を main にマージ)

移行 PR でやったこと

  • vp migrateVite / Vitest / Oxlint / Oxfmt / Turborepo を統合
  • turbo.json ほか各種設定ファイルを まとめて削除
  • テスト import を vitestvite-plus/test に変更
  • CI も voidzero-dev/setup-vp ベースに変更

実際どうだった?

良かった① vp migrate が最高

  • 既存プロジェクトを Vite+ に移行するための スタート地点
  • 依存関係・import・設定ファイル・scripts を まとめて更新
  • hooks・AI agent・エディタ設定のセットアップにも対応

良かった② 設定が一箇所に

ts
// vite.config.ts (実物)
export default defineConfig({
  test:   {  },  // Vitest
  staged: {  },  // git hooks(pre-commit)
  fmt:    {  },  // Oxfmt
  run:    {  },  // タスク実行(キャッシュ付き)
  lint:   {  },  // Oxlint
});
  • vite.config.tsdefineConfig設定が全部同居
  • test / staged / fmt / run / lint が 1ファイルで完結
  • vp lint だけで type linting(oxlint-tsgolint)まで実行

良かった③ Vite Task (vp run)

ts
// package.json
"build": "vp run -r build"
// -r = 全 workspace を依存順に実行(既定で最大4並列)

// vite.config.ts
run: {
  cache: { scripts: true }, // 使ったファイルを自動追跡してキャッシュ
}
  • -r全 workspace を依存順に実行
  • モノレポでも問題なく動作
  • Turborepo 的なタスク実行を Vite+ の中で完結

良かった③ キャッシュがあると爆速

text
$ vp run -r build      # 2回目(変更なし)
  ~/packages/hoge$     vp pack  ◉ cache hit, replaying
  ~/packages/fuga$      tsc ...   ◉ cache hit, replaying
  ~/packages/piyo$ vp pack  ◉ cache hit, replaying
  ──────────────────────────────────────
  vp run: 4/5 cache hit (80%), 27.38s saved
  ↑ ui-preview(Astro) だけは入力を書き換えるので非キャッシュ
  • 使ったファイルを 自動追跡 → 変化なしなら 実行せずリプレイ
  • 実測で 4/5 cache hit・27.38s 短縮
  • 詳しくはこちらがとても参考になります
    • https://zenn.dev/herp_inc/articles/strange-task-runner

良かった⑤ ライブラリモード = vp pack

ts
// packages/hoge/vite.config.ts
pack: {
  entry: ["./src/index.ts"],
  format: ["esm", "cjs"],
  dts: true,        // 型定義も出力
  sourcemap: true,
  minify: true,
  deps: {
    // react 系は peer で external、それ以外はバンドル
    alwaysBundle: ["clsx", "tailwind-merge", "dayjs"],
  },
}
text
             Before              After
             vp build(Vite/lib)  vp pack(tsdown)
  ESM  gzip   117KB         →     36KB   (459KB→144KB)
  CJS  gzip   102KB         →     36KB   (340KB→148KB)
  build       ~1.59s        →     ~1.0s
  型定義      vite-plugin-dts →    tsdown 内蔵
  • dts: true の1行で型定義(vite-plugin-dts 不要)、React 系は external 扱い
  • rollup → tsdown で gzip ESM 117KB → 36KB(約1/3)

良かった⑥ 個別ツールが要らない

ts
// vite.config.ts ← lefthook.yml を置き換え
staged: {
  "*.{ts,tsx,js,jsx,mjs}": "vp lint --fix",
  "*.{ts,tsx,css,md,json,yml}": "vp fmt",
}

// vp config が hooks を生成 → .vite-hooks/pre-commit の中身は1行
vp staged
  • git hooks も vp 同梱staged に書くだけ)→ husky / lefthook 不要
  • 独自の pre-commit は .vite-hooks/ で対応
  • Node も .node-version だけ(今回の用途では mise / volta 不要)

もちろん辛みもあった

辛かった① lefthook使用時にmigrateされない

  • vp migrate 時、lefthook は自動移行されず警告のみ
  • 気づかず pre-commit が壊れていた → 設定を手動修正
  • 自動移行されたのは husky / lint-staged だけ

その後 → 実は仕様でした

  • バグだと思って issue 起票#1854
  • よく見ると 仕様だった(RFC に記載あり)
  • Migration Guide に追記する形で対応(PR #1901・マージ済み)

辛かった② Astro がよく壊れた

  • 直後に Astro 6 へ手動移行(#198)

  • core@0.1.14 で Astro 互換リグレッション → 0.1.15 で解消

  • overrides.vite が Astro 内部の Vite まで置換 → Release 失敗

    →AstroV7でVite8がデフォになったり、同じCloudflareになったことで上手いこと行くことに期待

気をつけた③ AI が vp を知らない

  • AI が Vite+ / vp を知らないことが多い
  • α版ゆえ学習データに無く、提案を外しがち
  • npx で実行しがち

AGENTS.md / CLAUDE.md / Cursor rules などに vp 前提の運用を書く

導入しやすい / 注意したい条件

  • 導入しやすい

    • Vite / Vitest / Oxlint / Oxfmt を すでに使っている
    • 新規リポジトリ、または本格運用前
  • 注意したい

  • framework 側の Vite 依存

  • α版の破壊的変更を追えない

余談:このスライドも Vite+ です

Next 製でも Vite+ に乗れる

mySlides を Vite+ へ移行した PR #220(build: Vite+ への移行・ツールチェーン統合、26 files・+10366 -285)
  • この LT スライド(mySlides)自体も Vite+ へ移行(PR #220
  • web は Next 製(OGP を opengraph-image.tsx で組みたくて採用)、ビルドは Next のまま
  • vplint / fmt / task / staged 担当 → 名前は Vite+ でも中身は バンドラ非依存

そして Vite+ の沼へ

まとめ

  • 設定を vite.config.ts 一つに集約できるのが最高
  • Vite / Vitest / Oxlint / Oxfmt を使っているなら、導入価値はかなり高い
  • 新規リポジトリや本格運用前なら、早めに試す価値あり
  • α 版なので注意は必要だが、今回の辛みは 改善・運用で吸収できる範囲

ご清聴ありがとうございました