コンテンツにスキップ
Zenn Dev Ryo Kawamata Articles 1ad6e51eed13ae

VanJS で素のDOM操作をリファクタしてみた

  • URL: https://zenn.dev/ryo_kawamata/articles/1ad6e51eed13ae
  • 日付: 2026-06-26
  • Tier: Tier 3
  • 要旨: Chrome拡張Sky Follower Bridgeのcontent scriptにおける素のDOM操作をVanJSでリファクタリングした事例。VanJSはgzip後0.9kbと超軽量でトランスパイル不要のReactive UIフレームワークであり、Chrome拡張のcontent scriptのようにReactやVueのフルフレームワークを持ち込みにくい文脈で有効な選択肢となる。リファクタリング前はinsertAdjacentHTMLとaddEventListenerのクラス付け変えによるイベント管理で可読性が低かったが、VanJSのvan.state/van.deriveによる状態管理とコンポーネント分割により、UIとイベントの関連が一目でわかる宣言的なコードになった。

詳細

VanJSの特徴

  • gzip圧縮後0.9kb、依存なし、トランスパイル不要
  • JSXを使わず関数ベースのAPIで宣言的なUI構築
  • van.state()で状態管理、van.derive()で状態から派生値を算出
  • van.add(element, component)でDOMにコンポーネントをマウント

リファクタリング前の問題(insertAdjacentHTML + addEventListener)

  • HTMLテンプレートリテラルでDOMを構築し、後からaddEventListenerを登録
  • ボタンの状態変化はclassList.add/remove/containsとtextContent書き換えで直接操作
  • UIとイベントロジックの対応関係が追いにくく可読性が低い

リファクタリング後の構造

  • BskyUserCell, ActionButton, Avatar の3コンポーネントに分割
  • ActionButtonはvan.state()で label, isStateOfBeing, isProcessing, isJustApplied の4状態を管理
  • van.derive()でCSSクラス名を状態から派生(beingClass, processingClass, justAppliedClass)
  • マウント処理: van.add(dom.parentElement, BskyUserCell({…})) の1行

適用場面

  • Chrome拡張のcontent scriptのような制約のある環境
  • 静的サイトにピンポイントでReactiveなUIを追加したいケース