Modern Web Guidance がコードベースをモダナイズする仕組みと、それを行うべき理由

ほとんどのウェブ開発はゼロから行われるわけではありません。これは、長年にわたって蓄積されたレガシーな回避策、ポリフィル、JavaScript ユーティリティ(自動サイズ調整、カスタム チェックボックス スタイルのハック、scrollHeight リスナー)が、ブラウザでネイティブに処理されるようになった既存のコードベースで発生します。しかし、問題は、古いコードが壊れないことです。動作するため、誰もバグを報告しません。また、動作しているコードをリファクタリングするには、たとえ古いコードであっても信頼が必要であるため、デベロッパーが躊躇するのも無理はありません。

一方、最新のウェブ機能を使用するように古いコードをリファクタリングしないと、バンドルサイズ、ページの応答性、ユーザー補助に静かに影響します。さらに悪いことに、これらのプロジェクトでコーディング エージェントを使用すると、2015 年の規則とトレーニング データの古いパターンがコピーされます。

新しいものを構築する際、Modern Web Guidance はエージェントを最新の Baseline 機能に誘導します。既存のコードに対して、Modern Web Guidance 1.0 は、プロジェクトをスキャンしてレガシー パターンを検出し、エージェントがそれらをアップグレードできるようにするモダナイゼーション ワークフローを追加します。

モダナイゼーション ワークフローの機能

エージェントにプロジェクトのモダナイズを依頼すると(または legacy-scan コマンドを直接実行すると)、次のように動作します。

  • 決定論的なローカル スキャン: HTML、CSS、JavaScript/TypeScript、フレームワーク固有のコンポーネント、package.json ファイルは、抽象構文木(AST)、DOM、CSS パーサーを使用してローカルで迅速にスキャンされます。LLM 呼び出しやトークン費用は発生しません。
  • レガシー ルール カタログ: 実行ごとにあまりにも多くの項目にフラグを付けるスキャナは無視されます。候補ルールは、約 45,000 個のオープンソース リポジトリを半分に分割してテストしました。ルールはルール作成用の半分で作成および調整され、未確認のホールドアウト用の半分で評価されました。私たちは、保持するよりも多くの候補ルールを破棄し、レガシーコードに相当するものがない機能をスキップし、実際のメリットがない構文のみの入れ替え(動作する + または ~ 兄弟セレクタを :has() に書き換えるなど)を廃止しました。デフォルトでリリースするには、ルールが、未知のコードに対して少なくとも 80% の静的マッチャー精度と 90% の検証後精度を達成する必要があります。
  • コンテキストアウェアな誤検出フィルタリング: すべてのルールの一致には、明示的な keepWhen/dropWhen ルーブリックが付属しています。これにより、エージェントは周囲のコードを評価し、意図的なフォールバック、CSS @supports ガード、類似のコードを破棄してから、結果を提示します。
  • 信頼性の高いレガシー パターンに限定(拡大中): legacy-scan は、約 200 のガイドのサブセット(約 20%)をチェックします。このサブセットでは、レガシーコードを誤検出なしで決定論的に検出できます。このカバレッジは今後拡大していく予定です。カタログの残りの部分については、エージェントがビルド時にガイドを検索して取得します。

モダナイゼーション ワークフローを呼び出す方法

Modern Web Guidance でコードをモダナイズするには、バージョン 1.0 以降が必要です。npm またはエージェントのプラグイン マーケットプレイスを使用してインストールまたは更新します。

# Install Modern Web Guidance 1.0 in your project
npx modern-web-guidance@latest install

# Or update an existing installation
npx modern-web-guidance@latest update

モダナイゼーション ワークフローはコアスキルの定義の一部であるため、リポジトリまたはフォルダ全体で「レガシー パターン」を確認するか「モダナイズ」するようエージェントに依頼することで、自然言語でスキャナをトリガーできます。

注: 単一のコンポーネントに名前を付けると、代わりに通常のガイド検索が実行されます。

例として、リポジトリ全体をスキャンするプロンプトの例を次に示します。

Modernize this repository using Modern Web Guidance. Scan our frontend files for legacy patterns, verify the findings, and propose a modernization plan before making any code edits.

特定のフォルダを指定することもできます。

Check src/components/forms for legacy web patterns that can be refactored to modern Baseline features.

現在、legacy-scan はターミナルで手動で実行できますが、自動化された CI / CD パイプラインの統合は現在開発中です。

検出して修正するパターンの例

認定ルールは、フォームと UI、ダイアログとコントロール、CSS レイアウト、タイポグラフィ、ビジュアル デザイン、セキュリティの 4 つのドメインにわたる一般的なレガシー アンチパターンを対象としています。次の表に、以前のパターンの例と、それに対応する最新のパターンを示します。

ドメイン 以前のパターンが検出されました 最新の代替手段
フォームと UI JS scrollHeight textarea 自動サイズ変更フック CSS field-sizing: content(form-fields-automatically-fit-contents)
フォームと UI Enter keydown 送信ハンドラに IME ガードがありません if (e.isComposing || e.keyCode === 229) return; (ime-safe-enter-submit)
フォームと UI 読み込み時に未操作の入力に :invalid CSS スタイルが適用される :user-invalid 疑似クラスと :user-valid 疑似クラス(validate-input-after-interaction)
フォームと UI 認証フォームと購入手続きフォームに autocomplete トークンがない 標準化された autocomplete 値(autofill-sign-in-form、autofill-payment-form)
ダイアログとコントロール e.target === dialog 個のクリック リスナーがドラッグ選択を妨げています <dialog closedby="any">(プログレッシブ エンハンスメント(ダイアログ)を使用)
ダイアログとコントロール オーバーレイの命令型 addEventListener クリック リスナー 宣言型の popover 属性と popovertarget 属性(declarative-dialog-popover-control)
CSS レイアウト、タイポグラフィ、ビジュアル デザイン max-height: 9999px アコーディオン アニメーションのハック interpolate-size: allow-keywords と calc-size()(animate-to-intrinsic-sizes)
CSS レイアウト、タイポグラフィ、ビジュアル デザイン 子の状態に基づく JS 親クラスの切り替え 関係セレクタ :has(:checked) / :has(:focus-visible)(child-state-based-styling)
CSS レイアウト、タイポグラフィ、ビジュアル デザイン @media (prefers-color-scheme: dark) 個のブロックを複製しました CSS light-dark() 関数(dark-mode、dark-mode-toggle)
セキュリティ 外部 CDN スクリプトタグにサブリソースの整合性がない integrity 属性と crossorigin="anonymous" 属性(secure-external-subresources)

コード変換の例

プロンプトが表示されたら、コーディング エージェントはモダナイゼーション ワークフローを使用して、以前のアンチパターンを最新のアンチパターンに変換できます。いくつか例を挙げましょう。

<textarea> 要素の自動拡張

すべての input イベントで scrollHeight を測定する従来の JavaScript では、レイアウト スラッシングが発生します。これにより、パフォーマンスの問題(特に Interaction to Next Paint(INP))が発生する可能性があります。モダナイゼーション ワークフローを使用すると、エージェントは次の処理を行うことができます。

// Before: Imperative layout recalculation on every keystroke
textarea.addEventListener('input', () => {
  textarea.style.height = 'auto';
  textarea.style.height = `${textarea.scrollHeight}px`;
});

このラボでは JavaScript は必要ありません。モダナイゼーション ワークフローは、エージェントに CSS に置き換えるよう指示します。

/* After: Native declarative field sizing */
textarea {
  field-sizing: content;
  min-block-size: 3lh;
  max-block-size: 15lh;
}

宣言型ポップオーバー

JavaScript イベント リスナーを使用したカスタム モーダルとポップアップ ロジックは、標準の HTML 属性に置き換えることができます。

<!-- Before: a click listener that only calls showPopover() -->
<button id="openBtn">Open Menu</button>
<div id="menu" popover>Menu Content</div>
<script>
  openBtn.addEventListener('click', () => menu.showPopover());
</script>

<!-- After: declarative control, no JavaScript -->
<button popovertarget="menu">Open Menu</button>
<div id="menu" popover>Menu Content</div>

IME セーフな Enter キーによる送信

保護されていない Enter キーリスナーは、ユーザーが日本語、中国語、韓国語のインプット メソッド エディタ(IME)で入力すると、メッセージの送信を早期にトリガーします。

エージェントがコンポジション状態ガードを追加します。

// Before: Fires mid-composition when confirming kanji/hanzi characters
textarea.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    sendMessage();
  }
});


// After: Accurately checks IME composition state
textarea.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    if (e.isComposing || e.keyCode === 229) return;
    sendMessage();
  }
});

仕組み: 4 つのステップからなるモダナイゼーション ワークフロー

既存のアプリで動作しているコードをリファクタリングするには、信頼が必要です。自動化されたチャーンや、微妙な回帰を望む人はいないからです。--fix フラグがないのもそのためです。一見単純に見えるモダナイゼーションでも、命令型の JS リスナーや npm パッケージを削除して動作を HTML と CSS に移行するなど、クロスレイヤのリファクタリングになることがよくあります。これには、微妙な動作やブラウザ サポートの課題が伴います。

代わりに、モダナイゼーション ワークフローは、コーディング エージェントを使用して 4 ステップのループを実行します。

  1. スキャン(legacy-scan): エージェントは npx modern-web-guidance legacy-scan <path> --json を実行します。これにより、関連する部分文字列のファイルが事前にスクリーニングされ、候補ファイルとルールに対してのみ AST、CSS、HTML パーサーが起動されます。検出結果がこの段階に達すると、誤検出ではない可能性がすでに高くなっています(約 92%)。すべての照合には、エージェント用の確認チェックリストが含まれます。
  2. コンテキスト検証(keepWhen/dropWhen): コーディング エージェントはリポジトリを開いているため、各一致の周囲のコードをそのルールの検証ルーブリックに照らして検査します。scrollHeight の読み取りが <textarea> ハックではなく仮想化スクロールの一部である場合、または @supports チェックですでにプロパティが保護されている場合、検出結果は自動的に破棄されます。
  3. レポート: エージェントは、検証済みの検出結果を要約します(legacy-scan は、決定的ルールを持つガイドのサブセットと、編集前にプランの確認をリクエストした場合はモダナイゼーション プランを対象としています)。
  4. ガイドの取得、リファクタリング、テスト検証: モダナイズをリクエストされると、エージェントは npx modern-web-guidance retrieve <guide-id> を実行して適切なガイドを取得します。ガイドのベースライン互換性パターンに従ってコードのリファクタリングを実行し、変更されたファイルに対して legacy-scan <path> を再実行して、プロジェクトのテストスイートとともに解決を確認します。

試してみる

ターミナルで 1 回限りの legacy-scan を実行する場合でも、コーディング エージェントに古いモジュールのモダナイズを依頼する場合でも、モダナイゼーション ワークフローを使用すると、従来のリンターのノイズなしで、レガシー ウェブ プラットフォームの負債を返済できます。

静的コードのモダナイゼーションから、ライブ ブラウザの検証、ベンチマーク、デバッグに移行する場合は、Modern Web Guidance とエージェント向け Chrome DevTools を組み合わせて使用します。

次のステップとリソース