Eleventy テンプレートエラーのデバッグ情報を改善

shoelace-style/webawesome

ドキュメントビルド中にテンプレートエラーが発生した際、これまで undefined ✖ Error while writing the docs. という無意味なメッセージしか表示されなかった問題が修正されました。エラーの実際のファイルパス・行番号・パーサーメッセージが正しく表示されるようになります。

背景

Eleventyはテンプレートのレンダリング失敗を TemplateContentRenderError でラップして報告しますが、有用な詳細情報(ファイルパス・行番号・列番号)は originalError プロパティに格納されています。しかし、scripts/docs.js のエラーハンドラは error.cause を参照していたため、ほぼ常に undefined が表示されていました。

この問題はウォッチモードの再ビルドハンドラ(scripts/build.js)にも存在しており、開発中にテンプレートを誤った状態で保存した際も同様に無意味なエラー出力しか得られませんでした。

技術的な変更

formatError 関数を scripts/utils.js に新設し、エラーオブジェクトの構造を考慮した表示フォーマットを一元化しました。

新設された formatError 関数は、originalErrorcausemessagestack の優先順位でエラー情報を取り出します:

export function formatError(err) {
  const inner = err?.originalError || err?.cause;
  const innerStr = inner?.message || inner?.stack;
  const outer = err?.message;
  return innerStr && outer && !innerStr.includes(outer)
    ? `${outer}\n\n${innerStr}`
    : innerStr || err?.stack || outer || String(err);
}

originalError が存在する場合、外側のエラーメッセージと内側の詳細情報を改行で区切って両方表示します。内側の文字列がすでに外側のメッセージを含んでいる場合は重複を避けるため内側のみを表示します。スタックトレースより .message を優先するのは、Eleventy のエラーメッセージにはすでにファイルパスと行番号が含まれており、内部フレームの羅列を表示しても開発者の役に立たないためです。

scripts/docs.js では、エラーハンドラを以下のように変更しました:

変更前:

} catch (error) {
  console.warn = originalWarn;

  console.error('\n\n' + chalk.red(error.cause) + '\n');

変更後:

} catch (error) {
  if (outputs.warn.length > 0) {
    console.error(chalk.yellow('\n11ty warnings captured during build:'));
    for (const args of outputs.warn) {
      console.error(chalk.yellow('  ' + args.map(a => a?.message || a?.stack || String(a)).join(' ')));
    }
  }

  console.error('\n\n' + chalk.red(formatError(error)) + '\n');
} finally {
  restoreConsole();

あわせて、ビルド中に Eleventy が出力した警告を outputs.warn に蓄積して表示する処理も追加されました。従来はビルドスクリプトが console.warn をインターセプトして出力を抑制していましたが、エラー発生時には蓄積した警告を遡って表示することで、問題の手掛かりとなる情報が失われなくなります。また、console.warn の復元を catch ブロックから finally ブロック に移したことで、正常終了時にもインターセプトが確実に解除されるようになりました。

stubConsole 関数の引数の展開方法も修正されています:

変更前:

console[key] = function (...args) {
  outputs[key].push(...args);
};

変更後:

console[key] = function (...args) {
  outputs[key].push(args);
};

...args でスプレッドしていた従来の実装では、後から各引数を個別に参照できず警告の整形が困難でした。args をそのまま配列として格納することで、後続の args.map(a => a?.message || ...) によるフォーマット処理が成立します。

設計判断

エラー整形ロジックを scripts/utils.js に集約する 方針が採られました。docs.jsbuild.js の両方が同じ問題を抱えていたため、formatError を共有ユーティリティとして切り出すことで重複を排除し、将来のビルドスクリプト追加時にも一貫したエラー表示が得られます。

PR説明にも明示されているとおり、すべての変更はエラーパスに閉じており、正常なビルドの挙動には影響しません。エラーメッセージの改善という局所的な目的に対して変更範囲を最小限に抑えた判断といえます。

まとめ

この変更は、開発者がドキュメントビルドのエラーに直面した際に失っていた「なぜ失敗したか」という情報を取り戻します。formatError による Eleventy 固有のエラー構造への対応と finally による確実なコンソール復元は、DX 改善における堅牢性の高い実装パターンを示しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
28854844

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)の3部構成が明確で、ガイドラインに完全に準拠しています。特に「設計判断」セクションが含まれていることで、変更の意図がより深く理解できます。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトの形式(```言語:ファイルパス)や、PR番号へのリンク記法([#2340](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

ビルドスクリプトやエラーハンドリングに関する内容であり、専門知識を持つエンジニアという対象読者に適合しています。用語の使い方も適切で、過度な説明がありません。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクション、各パラグラフが「総論→各論」の構成になっており、トピックセンテンスが段落の先頭に置かれているため、非常に読みやすい構造になっています。1段落1トピックの原則も概ね守られています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているすべてのコードブロック(formatError関数、docs.jsの変更前後など)は、提供されたDiff情報と完全に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「TemplateContentRenderError」「originalError」「cause」「finallyブロック」「インターセプト」など、技術用語が文脈に応じて正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

formatError関数のロジックや、docs.jsにおける警告表示の追加、finallyブロックへの処理移管など、すべての技術的な説明がDiffのコード変更と論理的に整合しており、正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(エラーメッセージの問題、originalErrorとcauseの違い、build.jsへの適用など)は、PRのDescriptionやDiffによって裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2340)、ファイルパス、関数名などの固有名詞はすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「Eleventy テンプレートエラーのデバッグ情報を改善」は、PRのタイトル「Improve Local DX」の意図を汲み取り、具体的な変更内容を的確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容は提供されたPR情報に限定されており、バージョンのサポート状況やリリース日程といった外部知識の追記(捏造)はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「これまで」「従来は」といった時間表現は、PRによる変更という文脈において正確に使用されており、PR情報との矛盾はありません。