Sprocketsの初期化順序問題を解決し、アセット読み込みエラーを修正

viewcomponent/view_component

ViewComponent 4.0以降で発生していたSprocketsのアセット解決エラーが修正されました。この問題は、RailsエンジンとRailtieの初期化順序に起因しており、eager_load が有効な環境でのみ顕在化していました。

背景

ViewComponent 4.0へのアップグレード後、CI環境など eager_load が有効な環境でのみ、image_tag を使用したコンポーネントが Sprockets::Rails::Helper::AssetNotFound エラーを発生させる問題が報告されました。同じテストをeager loadingなしで実行すると正常に動作するため、初期化のタイミングに問題があることが示唆されていました。

#2433 の調査により、ViewComponentが参照する resolve_assets_withnil になっていることが判明しました。一方、Rails.application.config.assets.resolve_with は正しく [:manifest, :environment] を保持していました。この不整合は、ViewComponentとSprocketsの after_initialize ブロックの実行順序によって引き起こされていました。

技術的な変更

lib/view_component/engine.rb の初期化フックが after_initialize から after_routes_loaded に変更されました。これにより、Sprocketsの設定が完全に初期化された後にViewComponentの設定がコピーされることが保証されます。

変更前:

config.after_initialize do |app|
  ActiveSupport.on_load(:view_component) do
    if defined?(Sprockets::Rails)
      include Sprockets::Rails::Helper

      # Copy relevant config to VC context
      self.debug_assets = app.config.assets.debug

変更後:

config.after_routes_loaded do
  ActiveSupport.on_load(:view_component) do
    if defined?(Sprockets::Rails)
      include Sprockets::Rails::Helper

      app = Rails.application

      # Copy relevant config to VC context
      self.debug_assets = app.config.assets.debug

変更に伴い、ブロック引数として渡されていた app は削除され、ブロック内で明示的に Rails.application を参照するようになりました。after_routes_loaded はブロック引数を提供しないため、この調整が必要でした。

設計判断

Railsの初期化ライフサイクルにおいて、after_routes_loaded コールバック が採用されました。

Railsは after_initialize ブロックを登録順に実行します。ViewComponentエンジンは、Sprockets Railtieが先に after_initialize ブロックを登録することを暗黙的に前提としていましたが、登録順序は保証されていませんでした。この問題は、eager loadingが有効な場合により顕著に現れました。

after_routes_loaded は、すべての初期化処理と after_initialize ブロックの実行が完了した後に呼び出されます。このコールバックを使用することで、Sprocketsの設定(config.assets.resolve_with など)が確実に設定された状態でViewComponentの初期化を実行できます。

このアプローチは、他のRailtieやエンジンとの初期化順序の依存関係を明示的に解消し、登録順序に依存しない堅牢な実装を実現しています。

まとめ

本PRは、ViewComponentの初期化フックを after_initialize から after_routes_loaded に移動することで、Sprocketsとの初期化順序問題を解決しました。この変更により、eager loadingが有効な環境でもアセット解決が正常に動作するようになり、CI環境での信頼性が向上しています。Railsの初期化ライフサイクルを正しく理解し活用することで、エンジン間の暗黙的な依存関係を排除した設計です。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事は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リンク記法の正確性

ファイル名付きシンタックスハイライト(```ruby:path```)やGitHubのIssue/PRリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

Railsの初期化ライフサイクルやSprocketsに関する知識を前提としており、専門知識を持つエンジニアという対象読者に適合しています。

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

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

各セクションが総論→各論の構成で書かれ、各段落もトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、可読性が高いです。

Diff内容との照合 ✓ PASS

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

記事内のコードブロックは、提供されたDiffの内容を正確に反映しています。変更前後のコードが正しく引用されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「Railtie」「eager_load」「after_initialize」「after_routes_loaded」などの技術用語が正確かつ適切な文脈で使用されています。

説明の技術的正確性 ✓ PASS

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

初期化順序の問題点と、`after_routes_loaded` を使うことでそれが解決される理由についての説明が、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのDescriptionやDiff、参照されているIssueの情報に基づいており、ハルシネーション(創作)は見られません。

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

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

PR番号(#2566)、Issue番号(#2433)などの数値や固有名詞はすべて正確に記載されています。

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

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

記事のタイトル「Sprocketsの初期化順序問題を解決し、アセット読み込みエラーを修正」は、PRの主題を的確に要約しています。

外部知識の正確性 ✓ PASS

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

PR情報に含まれない外部知識(バージョンのサポート状況、リリース予定など)の追加はなく、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

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

記事内で使用されている時間表現は適切であり、PRの事実関係を歪めるような記述はありません。