各種チェック
ビルドがグリーンでも、ページが無事だとは限りません。このツールチェーンは層ごとにチェックを一つずつ置き、「ビルドは緑、ページは壊れている」という類の静かな失敗をそれぞれの層で捕まえます——そのうち二つは、読者と同じやり方で、実ブラウザの中からページを見ます。
§1五つの関門、五つの層
| チェック | 同梱元 | 見るもの | 走らせるとき |
|---|---|---|---|
| check-content | エンジン、scripts/check-content.mjs | md/mdx のソース全ファイル | コンテンツリポジトリの CI、または書いた直後 |
| check-wikilinks | エンジン、scripts/check-wikilinks.mjs | [[ウィキリンク]] のグラフ | コンテンツリポジトリの CI、またはノート改名の後 |
| check-dist | エンジン、scripts/check-dist.mjs | astro build の出力 | 毎ビルドの後(postbuild) |
| ui_probe | このパッケージ、scripts/ui_probe.mjs | 実ブラウザで描画したページ | スタイル/レイアウト変更の後 |
| contrast_probe | このパッケージ、scripts/contrast_probe.mjs | 全テキストノードのコントラスト、両テーマ | トークン変更の後 |
§2check-content:ソース層
ページになる予定のすべての md/mdx を、サイトと寸分違わぬ同じ方言でコンパイルします——構文エラーも、静かな変形(対を作れない強調マーカー、MDX 評価に呑まれる波括弧、行の折り返しから生まれるリストマーカー、一行の $$、KaTeX が描画できない数式——全部入りデモが巻末に挙げるのと同じ一式)も、すべて CI を赤にします。
このスクリプトがエンジン由来でなければならない理由:プラグイン構成がサイトと食い違うチェッカーは、チェッカーが無いより悪い——数式プラグインを欠けば数式の波括弧を JSX 式と読み違え、GFM を欠けばテーブルのパイプを素通しします。方言はエンジンに一度だけ書かれ、サイトの描画、CMS の保存時検証、そしてこのスクリプトが、常に同じ一つを消費します。
node <engine>/scripts/check-content.mjs . --glob '**/index.{md,mdx}' --mathコンパイルの先で、frontmatter の静かな損失も二種類捕まえます:値の中の引用符なしの #(YAML はコメントと読み、その後ろを黙って切り落とします)と、そもそもパースできない YAML(行番号付きで報告)。
§3check-wikilinks:リンクグラフ
死んだ [[ウィキリンク]] は、意図してビルドを落としません——庭は、まだ育てていないノートへ先にリンクすることを許されるべきだからです。それでもリンクの腐敗は CI の仕事なので、エンジンは lint を同梱しています:ライブラリ自身のパーサと解決規則(別名、brand、タイトル、ロケールミラー)ですべてのウィキリンクを解決し、行方不明のもの、曖昧なもの、怪しいアンカーを報告します。--strict は死リンクを失敗の終了コードに変えます——このリポジトリの CI はそう走らせています:
node scripts/check-links.mjs§4check-dist:出力層
ビルド済みの dist/ では、読者がクリックできる内部参照はすべて実在しなければなりません。緑のビルドの下の静かな穴を捕まえます:
- 実在しないファイルを指す内部リンク/アセット(ルート再編成の後に何十個と現れる、あの類)。
- 実在しない id を指すページ内アンカー。
- パスの中の二重ロケールセグメント(
/en/en/——接頭辞済みのルートに i18n フォールバックがもう一段接頭辞を積む、あの古典)。 <a>の中に入れ子になった<a>(HTML パーサが外側を早めに閉じ、ボタンがカードの外にこぼれ落ちます)。- KaTeX のエラー残骸(ビルドは緑のまま、ページの数式は赤いテキスト)。
このデモは postbuild に配線しています:npm run build が緑なら、出力チェックも通っています。
node vendor/astro-inkbrush/scripts/check-dist.mjs dist --base ${DEMO_BASE:-/}§5レンダリング層プローブ
ソースも出力も正しいのに、ページは壊れている——ということがあり得ます。古典的なのは、どのスタイルシート規則にもマッチしないランディングカードが、裸のテキストを一行に詰め込んだ姿で描画されるケースです:リンクチェックもアンカーチェックも、描画されたページを見ないので緑のまま。ui_probe は実ブラウザで dist の全ページを 4 つのビューポート幅(1440/1024/768/430)で巡回し、測ります:ページの水平オーバーフロー、収まる先のスクロールボックスを持たないままコンテナより広い要素、どのスタイルシート規則にもスタイルされないクラス、飛んだ見出しレベル、重複 id、alt 属性のない画像、何も指していないページ内アンカーと aria-controls。機械が証明できることだけを報告します——美的判断はしません。
npm run build
node ../scripts/ui_probe.mjs dist # dist を自前で配信する。稼働中のサーバを見るなら baseUrl を渡す文書全体を検査します——クローム、サイドバー、ダイアログも含めて。グリーンとは、レポートの最終行が SAMPLES WITH FINDINGS: 0 であること(サンプルは「1 ルート × 1 幅」のことです)。
§6コントラストプローブ
トークンは AA を名乗るので、その主張は断言ではなく実測されます。contrast_probe は dist の全ページを実ブラウザで開き——ライトとダーク、デスクトップ幅とスマホ幅——既定状態で描画されたすべてのテキストランを測ります:HTML テキスト、SVG テキスト、::before / ::after の生成テキスト。代表ページでは、すべての <dialog data-probe-open> オーバーレイを開いた状態で測り(そこに検索ボックスがあれば実際にクエリを打ち込みます)——このマーカーは「このダイアログは書かれたままで完成している」というサイト側の宣言です。地の色はスタイルシートからは読みません:全グリフを透明にしてページを描画し、スクリーンショットを撮り、各ランの下のピクセルをその地とします。だからグラデーションも、color-mix() の混色も、半透明のレイヤーも、夜のパレットも、描画されたままの姿で測られます。ランの前景色には要素と祖先の opacity の累積が乗ります——つまり薄くされたテキストは、読者が実際に見る濃さで測られます。ホバーとフォーカスの状態はプローブせず、目視でレビューします。小さいテキストは 4.5:1、大きいテキスト(24px、または 18.66px の太字)は 3:1 が基準。色をパースできないランや地をサンプリングできないランは、それ自体が指摘として数えられます。レポートは基準を割ったすべてのランについて、ページ、テーマ、幅、セレクタ、二つの色、そして比を挙げます:
node ../scripts/contrast_probe.mjs dist # PROBE_THEMES / PROBE_WIDTHS で行列を絞れるui_probe と contrast_probe を掛けます——全部グリーンにしてからコミット。デモはパッケージの試験台を兼ねています。