Skip to content

Only recompile components when a template changed, instead of before every request - #2730

Merged
joelhawksley merged 1 commit into
ViewComponent:mainfrom
czj:compile-cache-template-watcher
Oct 19, 2026
Merged

joelhawksley merged 1 commit into
ViewComponent:mainfrom
czj:compile-cache-template-watcher

Conversation

@czj

@czj czj commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Closes #2729

What are you trying to accomplish?

When templates aren't cached, which is the default in development, the engine empties the compile cache before every request, so every request recompiles every component it renders, even when no template changed. This only invalidates the cache when a template or a translation file was added, changed, or removed.

On our app (between 43 and 60 components per page), median of 7 requests after a warm-up:

Page Before After
Home 261 ms 160 ms
Category 148 ms 71 ms
Product 217 ms 106 ms
Brand 166 ms 83 ms

What approach did you choose and why?

The same one as Action View's ActionView::CacheExpiry::ViewReloader for views: a config.file_watcher over the autoload paths, since components can live outside app/components and in engines, watching ActionView::Template::Handlers.extensions plus yml and yaml for sidecar translations. Changes to Ruby files, inline templates included, already reload the application, so the cache is also cleared on before_class_unload.

The watcher is built on the first request that doesn't cache templates, so the template handlers registered by gems like Slim or Haml are known by then, and ActionView::Base.cache_template_loading is still checked on every request, as the test helpers toggle it.

Anything you want to highlight for special attention from reviewers?

The existing tests for template changes being reflected on the next request fail if the watcher doesn't invalidate the cache, so they cover the change. I added one checking that a component isn't recompiled when no template changed, which fails on main, and one for an added template.

When templates aren't cached, the engine emptied the compile cache
before every request, so every request recompiled every component it
rendered, even when nothing changed.

Like Action View does for views, watch the templates and translation
files in the autoload paths with config.file_watcher, and only
invalidate the cache when one of them is added, changed, or removed.
Changes to Ruby files reload the application, which clears the cache.
@joelhawksley
joelhawksley merged commit 8d7627c into ViewComponent:main Oct 19, 2026
20 checks passed
@czj
czj deleted the compile-cache-template-watcher branch October 19, 2026 17:46
@czj

czj commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks a lot @joelhawksley !

joelhawksley added a commit to mhenrixon/view_component that referenced this pull request Oct 19, 2026
Resolve conflicts with ViewComponent#2730's template watcher. Move hook registration
into CompileCache.watch_templates so the cached-templates case is tested
in-process instead of in a subprocess, and drop the runtime caching
check, which only existed to support a test that toggled caching after
boot.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f2e356ff-16cd-4517-8e63-a8600747d3fa
joelhawksley added a commit to mhenrixon/view_component that referenced this pull request Oct 19, 2026
…olation

Boot a fresh development or production app per test in a forked process,
the way railties tests do, instead of an Open3 subprocess or an extracted
method. These tests run in their own rake task since the sandbox is
already booted in the test process.

Inline the executor hook back into the engine, and restore ViewComponent#2730's
integration tests that a previous commit dropped by mistake.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f2e356ff-16cd-4517-8e63-a8600747d3fa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Only recompile components when a template changed, instead of before every request

2 participants