レポーター
svelte-vitals が検出結果をフォーマットして出力する方法を選択します。
svelte-vitals は 7 つの出力レポーターをサポートしています。--reporter <fmt> で選ぶか、環境に応じた自動選択に任せてください。
利用可能なレポーター
console(デフォルト)
ターミナル使用に適した、人間が読みやすいテキスト出力です。重大度ごとに検出結果をグループ化し、ルートパスとファイルの場所を含みます。
svelte-vitals --reporter console
json
マシン可読な JSON 出力。スクリプトやダッシュボードでの利用、他のツールへの結果の受け渡しに便利です。
svelte-vitals --reporter json
構造
{
"version": "0.35.0", // このレポートを生成した svelte-vitals のバージョン
"score": 97, // 総合 Health スコア(0〜100、切り捨て。100 は減点ゼロを意味する)
"weights": { "seo": 1 }, // 実際に適用されたカテゴリ別の Health 重み
"categories": {
"seo": {
"score": 94,
"scoreModel": {
"routeAverage": 94, // ルートごとのスコアの平均(切り捨て)
"sitePenalty": 0, // サイト全体の検出(route を持たないもの)による減点
"criticalCap": null // critical によってスコアが抑えられた場合はその上限値、なければ null
},
"keys": 42, // このカテゴリが測定した対象(ルートなど)の数
"affectedKeys": 6 // そのうち何らかの検出があった数
}
},
"summary": { "critical": 0, "warning": 33, "info": 44, "passed": 610, "dynamic": 2 },
"rules": {
// 実行されたすべてのルール。`findings: 0` のエントリは実行された上で何も検出しなかったことを示す。
// このマップに現れないルールはトップレベルで無効化されている(`--ignore`、`--rules`、`--category`、
// または設定ファイルの `rules: { id: 'off' }`)。`overrides` で無効化したルールは実行はされるため、
// 引き続きここに現れる(詳しくは後述)。
"architecture/unit-entry-file": { "findings": 0, "passed": 12 }
},
"routes": [
{
"route": "/about", // ルート ID。ファイル単位のルールではソースファイルのパス
"score": 95, // このルートが属するカテゴリ/スコープのルール一覧(重大度で重み付け)のうち、無傷で残った割合
"categories": { "seo": 94 }, // このルートで結果が出たカテゴリごとのスコア。そのカテゴリ自身の一覧に対する割合
"issues": [
{
"id": "seo/single-h1", // ルール ID
"category": "seo",
"severity": "warning", // 設定した severity の上書きを反映した後の値
"title": "Two <h1> elements", // 人が読む検出内容
"detection": { "presence": "none", "value": "absent" },
"location": "src/routes/about/+page.svelte",
"line": 12,
"recommendation": "Keep exactly one <h1> per page.",
"docsUrl": "https://svelte-vitals.dev/rules/seo/single-h1",
"fix": { "description": "…", "snippet": "…", "lang": "svelte" }
}
]
}
],
"siteIssues": [], // route を持たない検出(robots.txt、sitemap.xml など)。issue の構造は同じ
"inventories": {
"seo::route": 100 // "seo" と "route" の組み合わせで測定されるキーそれぞれの、下限値適用後の重大度ウェイト合計
},
"examined": {
"architecture/reserved-name-placement": {
"capitalisedUnitPlacements.parts → src/**": 28 // この宣言が判定した場所の数(許可・却下を問わない)
}
},
"skipped": {
"a11y/no-missing-id-ref": [
{
"route": "/checkout",
"refs": 2,
"causes": [{ "kind": "component", "detail": "Textbox", "file": "src/routes/checkout/+page.svelte", "line": 12 }]
}
]
}
}
あるキーに対するカテゴリのスコアは、そのカテゴリが持つ重大度ウェイトのうち生き残った割合です。チェックはカテゴリとスコープの組でグループ化されています。inventories のキーである seo::route がその単位です。同じ組の中でなら warning は info の5倍、critical は15倍のコストがかかるので、重大度の高い検出は必ずより大きなコストになります。ところが組をまたぐとこの順序は成り立ちません。チェック対象が極端に少ない組は、inventories がその組について報告している下限値を分母にスコアが計算されるため、そこでは1件あたりの負担が相対的に大きくなり、小さな組の warning が大きな組の critical より高くつくことがあります。同じルールが同じキーで何度検出されても、コストは1件分のままです。スコアの隣にある affectedKeys は、このカテゴリがプロジェクトのどれだけに触れたかを示します。スコアが深さなら、こちらは到達範囲です。
この段落が伝えていないことが、ほかにもあります。
-
下限値が効いた組は「測った結果」ではなくクランプされた値です。 持っているチェックが下限値に満たない組は
inventoriesに下限値が出るため、ルールが1本の組と8本の組が同じ値に見えることがあります。この数字はスコアが実際に使った分母であって、何本のチェックが走ったかではありません。実際に報告したチェックはrulesで確認してください。 -
::projectの組の数字は何も割りません。 ルートを持たない検出、つまり robots.txt や sitemap.xml の類は絶対値の減点で、warningは1件につきプロジェクトの規模に関わらずカテゴリから一律5点を引きます。これらのエントリがinventoriesに載っているのは形式を揃えるためだけです。 -
keysはカテゴリごとの数で、プロジェクト全体の数ではありません。 あるカテゴリのkeysは、そのカテゴリが触れたキーの数です。したがって同じ実行でもカテゴリによって分母が異なり、seoが13キー、architectureが334キーということが起こります。 -
キーごとのスコアは同一カテゴリ内でのみ比較可能です。カテゴリをまたいだ数値が示すのは、どちらの問題がより深刻かではなく、どちらのカテゴリで自身のチェックがより多く失敗しているかです。
-
inventoriesは1つの組に属するすべてのキーの分母を示すので、ルートごとのカテゴリスコア(routes[].categories)はそこから手計算で検算できます。これが成り立つのは、キーがルート ID かソースファイルパスのどちらか一方であり、この2つの空間が重ならないため、あるキーの1カテゴリ内の結果が必ず単一のスコープに属するからです。ルート自身のscoreはそうはいきません。複数の組にまたがるルートでは、触れたすべての組の生の重みを合計してから一度だけ下限値を適用するのに対し、inventoriesは各組を個別に下限値適用済みで公開しているため、両者は食い違うことがあります。
次の2つのフィールド名は、取り違えてもエラーにならず静かに空振りするため、特に注意してください。
- ルールの識別子は
idです(ruleではありません) - 検出内容のテキストは
titleです(messageではありません)
line・docsUrl・fix はルールが提供した場合のみ、location はファイルに紐づく検出の場合のみ現れます。issues に並ぶのは失敗した検出のみです。合格したチェックは summary.passed に数として計上されますが、一覧には出ません。失敗が1件も無いルートも routes には現れ、issues が空配列のまま自分のスコアを持ちます。
categories にはそのルートで実際に結果が出たカテゴリだけが並びます。あるカテゴリが無いのは「ここでは測定していない」という意味であり、「ここは満点だった」という意味ではありません。この値がルート自身の score の平均になっているとは、どちらの向きにも保証されません。score はそのルートが測定対象とした全体に対する1つの割合であるのに対し、各カテゴリのスコアはそのカテゴリ自身の一覧に対する割合だからです。ルート上のすべてのカテゴリが同じ割合を示すとき(検出結果が無いルートも含む)は両者が一致し、それ以外では数ポイントずれることがあります。
rules は、レポートの他の部分では答えられない問い、そのルールがそもそも実行されたかどうかに答えます。issues に載るのは失敗した検出結果だけなので、何も検出しなかったルールはそこに痕跡を残しません。トップレベルで無効化した(--ignore、--rules、--category、または設定ファイルの rules: { id: 'off' })ルールも同じく現れません。判定には rules を見ます。存在すれば実行された、存在しなければトップレベルで除外された、という意味です。ただし1つだけ例外があり、それは次に述べます。
rules の件数が表すのはツリーではなくレポートそのものです。baseline、抑制、--diff によるフィルタリングはレポートを組み立てる前に適用されるため、検出結果がすべて抑制されたルールも findings: 0 のまま rules に残ります。overrides で無効化したルールも同様です。トップレベルとは異なり、overrides はルールが実行された後にその結果(合格分も含む)を取り除くため、{ "findings": 0, "passed": 0 } として現れ、選択されて何も検出しなかったルールと見分けがつきません。rules に存在することが保証するのは、--ignore・--rules・--category・設定ファイルのトップレベルの rules で除外されなかったことだけで、overrides が検出結果を何も残さなかったことまでは保証しません。
examined は別の、トップレベルの独立したマップです。ルール ID、その下に宣言のラベル、その下にその宣言が判定した場所の数(許可したか却下したかを問わない)が入ります。--diff・--baseline・抑制によって絞り込まれることはありません。これらは rules に適用されるものであり、examined はレポートではなく分析そのものを表すため、rules の中ではなく隣に置かれています。このマップ自体は省略可能で、件数を報告したルールが1つも無い実行では examined ごと現れません。存在する場合、状態は3つあります。件数を一切報告しないルールにはエントリがありません。数えはするが設定が何も宣言していないルールには空のエントリが入ります。トップレベルの rules で architecture/reserved-name-placement を有効にしただけで配置を宣言しなければ、ちょうどこの状態になります。そして何も判定しなかった宣言は 0 として現れます。実際に現れるエントリは、そのルール自身の診断が使うのと同一の宣言ラベルを使います。architecture/reserved-name-placement の集約された finding と examined のエントリは capitalisedUnitPlacements.parts → src/** という文字列を共有しており、両者を並べて読めます。0 でない件数は、その宣言が少なくとも一度は検査されたことを示します。検出結果が無いルールだけでは答えられない問いです。
skipped はルール ID をキーとする、もう1つの分析側マップです。現時点では
a11y/no-missing-id-ref だけがこれを使います。このルールは解決しきったルート合成を必要とし、
その基準を満たせないルートは結果を出さないままスキップされます。各エントリにはスキップされた
ルート、その literal な id 参照数(refs。0 件のルートは、たとえ実行できたとしても何も検出
しません)、そして条件を満たせなかった原因が並びます。原因はそれぞれ kind(component・spread・
html・dynamic-id)、最初に該当した file と line、コンポーネントの場合は記述された名前
(detail)を持ちます。examined と同様、これはレポートではなく分析そのものを表すため、
--diff・--baseline・抑制によって絞り込まれることはありません。解析対象のルートが
1つもスキップされなかった場合は省略されます。
agent
AI コーディングエージェント向けに設計された Markdown 修正ドキュメントです。失敗した各検出結果には以下が含まれます。
- ルートとソースファイルの場所
- スニペット付きの具体的なコード修正
- 受け入れチェック
agent レポーターは、既知の AI エージェントハーネス(Claude Code、Cursor、Codex など)が検出された場合、または SVELTE_VITALS_AGENT=1 が設定されている場合に自動選択されます。この環境変数は、gunshi がまだ認識しないハーネス向けの共通オプトインです。認識対象は gunshi のエージェントプロファイルに委譲されており、ハードコードされた一覧ではなく gunshi の更新とともに拡張されます。明示的に指定せず自動選択された場合は、上書き方法を案内する 1 行のヒントが stderr に出力されます。
svelte-vitals --reporter agent
環境変数で自動選択を上書きするには、次のように設定します。
SVELTE_VITALS_REPORTER=agent svelte-vitals
sarif
SARIF v2.1 形式。GitHub Code Scanning、Azure DevOps、その他 SARIF を使用する SAST ツールと互換性があります。
svelte-vitals --reporter sarif
github
GitHub Actions の ワークフローコマンド 形式。プルリクエストにインラインで表示される ::error および ::warning アノテーションを出力します。
github レポーターは GITHUB_ACTIONS=true が設定されている場合(GitHub Actions が自動的に設定)に自動選択されます。
svelte-vitals --reporter github
md
コンパクトな Markdown サマリーです。Health スコア、カテゴリ別スコア表、重大度別件数、各ルールのドキュメントページへのリンク付き検出結果テーブルを含みます。GitHub Actions のジョブサマリーや PR コメント向けに設計されており、GitHub のコメントサイズ制限内に収まるよう検出結果の行数は 50 件に制限されます。このレポーターを自動的にワークフローへ組み込む svelte-vitals ci install については CI 連携ガイド を参照してください。
svelte-vitals --reporter md
HTML レポート
--reporter html は自己完結の HTML レポートを出力します。ライブダッシュボードと同じ UI で、レンダラーを共有しているため乖離しません。検索・並び替え可能なルート一覧、重大度とカテゴリのフィルター、ダークモード、検出結果ごとの AI Prompt が使えます。
静的ファイルには背後に dev サーバーがないため、ライブ更新の仕組み(SSE、measured への精緻化)はありません。CSS と JS をインライン化しているためオフラインで動作し、CI 成果物としても扱いやすくなっています。
svelte-vitals --reporter html # svelte-vitals-report.html を出力
svelte-vitals --reporter html --out-file report.html
svelte-vitals --reporter html --out-file - # ファイルではなく標準出力へ
デフォルトではカレントディレクトリに svelte-vitals-report.html を書き出し、パスを stderr に表示します。--out-file <path> で出力先を変更でき、--out-file - で標準出力にストリームします(パイプや CI 成果物向け)。
自動選択の優先順位
- 明示的な
--reporter <fmt>:常に最優先。 SVELTE_VITALS_REPORTER環境変数:自動検出を上書き。- 既知の AI エージェントハーネス(Claude Code、Cursor、Codex など)または
SVELTE_VITALS_AGENT=1→agent。 - GitHub Actions(
GITHUB_ACTIONS=true)→github。 - デフォルト →
console。
例:CI パイプライン
- name: Check SEO
run: npx svelte-vitals@latest --fail-on warning
# GITHUB_ACTIONS はすでに設定済み;github レポーターが自動選択される