Skip to content

Commit 240fa86

Browse files
authored
Merge pull request #2411 from jsolas/add-activesupport-notifications-to-compiler-
Add after_compile hook for component extensions
2 parents c54ee6b + a9b108c commit 240fa86

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

docs/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ nav_order: 6
1010

1111
## main
1212

13+
* Add `after_compile` class method hook to enable extensions to run logic after component compilation.
14+
15+
*Jose Solás*
16+
1317
* Fix outdated reference to preview layout configuration in docs.
1418

1519
*Lucas Geron*

lib/view_component/base.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,16 @@ def __vc_compiled?
610610
__vc_compiler.compiled?
611611
end
612612

613+
# Hook called by the compiler after a component is compiled.
614+
#
615+
# Extensions can override this class method to run logic after
616+
# compilation (e.g., generate helpers, register metadata, etc.).
617+
#
618+
# By default, this is a no-op.
619+
def after_compile
620+
# no-op by default
621+
end
622+
613623
# @private
614624
def __vc_ensure_compiled
615625
__vc_compile unless __vc_compiled?

lib/view_component/compiler.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ def compile(raise_errors: false, force: false)
5252
@component.__vc_build_i18n_backend
5353

5454
CompileCache.register(@component)
55+
56+
@component.after_compile
5557
end
5658
end
5759

test/sandbox/test/base_test.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,63 @@ def test_uses_module_configuration
195195
assert_equal false, TestAlreadyConfigurableModule::SomeComponent.instrumentation_enabled
196196
assert_equal false, TestAlreadyConfiguredModule::SomeComponent.instrumentation_enabled
197197
end
198+
199+
def test_after_compile_hook_called_on_compile
200+
klass = Class.new(ViewComponent::Base) do
201+
@@calls = 0
202+
203+
def self.calls
204+
@@calls
205+
end
206+
207+
class << self
208+
def after_compile
209+
@@calls += 1
210+
end
211+
end
212+
213+
erb_template ""
214+
end
215+
216+
self.class.const_set(:TempHookComponent, klass)
217+
ViewComponent::CompileCache.invalidate_class!(klass)
218+
219+
ViewComponent::Compiler.new(klass).compile(force: true)
220+
assert_equal 1, klass.calls
221+
ensure
222+
self.class.send(:remove_const, :TempHookComponent) if self.class.const_defined?(:TempHookComponent)
223+
ViewComponent::CompileCache.invalidate_class!(klass) if defined?(klass)
224+
end
225+
226+
def test_after_compile_not_called_on_cached_compile
227+
klass = Class.new(ViewComponent::Base) do
228+
@@calls = 0
229+
230+
def self.calls
231+
@@calls
232+
end
233+
234+
class << self
235+
def after_compile
236+
@@calls += 1
237+
end
238+
end
239+
240+
erb_template ""
241+
end
242+
243+
self.class.const_set(:TempHookCachedComponent, klass)
244+
ViewComponent::CompileCache.invalidate_class!(klass)
245+
246+
compiler = ViewComponent::Compiler.new(klass)
247+
compiler.compile(force: true)
248+
assert_equal 1, klass.calls
249+
250+
# compile again without force -> should not call hook again
251+
compiler.compile
252+
assert_equal 1, klass.calls
253+
ensure
254+
self.class.send(:remove_const, :TempHookCachedComponent) if self.class.const_defined?(:TempHookCachedComponent)
255+
ViewComponent::CompileCache.invalidate_class!(klass) if defined?(klass)
256+
end
198257
end

0 commit comments

Comments
 (0)