ブート時の一括コンパイルを計測する `compile.view_component` イベントの追加
ViewComponentのEagerロード時の一括コンパイルが、compile.view_component という ActiveSupport::Notifications イベントとして計測できるようになりました。設定不要で常に発火するため、起動時のコンパイルコストを手軽に可視化できます。
背景
ViewComponentは既に render.view_component イベントによるレンダリング計測の仕組みを持っていましたが、ブート時の一括コンパイル(Eager Compilation)はこれまで計測の手段がありませんでした。config.eager_load = true の環境では、アプリケーション起動時に全コンポーネントの __vc_compile が一括実行されますが、その処理にどれだけ時間がかかっているかは外部から観察できない状態でした。
既存の render.view_component イベントは config.instrumentation_enabled = true が必要なオプトイン方式ですが、今回追加された compile.view_component は設定不要で、config.eager_load = true の場合に常に発火します。コンパイル計測はレンダリング計測とは異なりパフォーマンスへの影響が限定的であるため、常時有効化という判断が取られています。
技術的な変更
変更の核心は lib/view_component/engine.rb の view_component.eager_load_actions イニシャライザに ActiveSupport::Notifications.instrument ブロックを追加した1点です。
変更前:
initializer "view_component.eager_load_actions" do
ActiveSupport.on_load(:after_initialize) do
ViewComponent::Base.descendants.each(&:__vc_compile) if Rails.application.config.eager_load
end
end
変更後:
initializer "view_component.eager_load_actions" do
ActiveSupport.on_load(:after_initialize) do
if Rails.application.config.eager_load
ActiveSupport::Notifications.instrument("compile.view_component") do
ViewComponent::Base.descendants.each(&:__vc_compile)
end
end
end
end
instrument ブロックで全コンポーネントの __vc_compile 呼び出しを囲むだけの最小限の変更です。購読側では以下のようにイベントを受け取れます:
ActiveSupport::Notifications.subscribe("compile.view_component") do |event|
event.name # => "compile.view_component"
event.duration # => 123.45 (milliseconds)
end
テストは test/sandbox/test/instrumentation_test.rb に追加されました。ViewComponent::Engine.initializers から view_component.eager_load_actions を名前で取り出して直接実行する方式を採用しており、config.eager_load を一時的に true に切り替えた後、ViewComponent::CompileCache.invalidate! でキャッシュをクリアしてから検証しています。
設計判断
コンパイル全体を1つのイベントとして計測する粒度の選択が、この変更の核心的な設計判断です。
個々のコンポーネントごとにイベントを発火する設計も考えられますが、今回は全コンポーネントの一括コンパイルをまとめて1イベントとして扱っています。これはブート時の総コンパイルコストを把握するというユースケースに直接対応したものです。既存の render.view_component がリクエストごとの個別計測であるのに対し、compile.view_component はブート処理全体のコストを俯瞰するという異なる観測目的を持ちます。
また、オプトアウト不要の常時有効化は、コンパイルが eager_load = true 時のみ走るという前提から自然に導かれます。イベントが発火する条件が config.eager_load の真偽に完全に依存しており、それ以外の制御を加えないシンプルな実装となっています。
まとめ
compile.view_component イベントの追加により、ViewComponentのブート時コンパイルコストがActiveSupport::Notificationsの標準的なAPIで計測可能になりました。変更量は最小限ながら、既存の計測インフラを活用してデプロイ時のパフォーマンス観測に新たな軸を加えた変更です。