Skip to content

Automatically track source digests for all components - #2720

Open
joelhawksley wants to merge 6 commits into
mainfrom
joelhawksley-caching-pr-strategy
Open

joelhawksley wants to merge 6 commits into
mainfrom
joelhawksley-caching-pr-strategy

Conversation

@joelhawksley

@joelhawksley joelhawksley commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

What are you trying to accomplish?

Automatically integrate all ViewComponents into Rails' template digest tree. No module include or application-level opt-in is required for source dependency tracking, .cache_digest, or digest-aware cache blocks inside component templates.

This consolidates and supersedes #2711 and #2713, building on Erik Axel Nielsen's fixes for silently incomplete cache digests. The scope was subsequently expanded to make digest tracking automatic for every component, eliminating the application-wide activation side effect of including ExperimentallyCacheable on an unrelated component.

What approach did you choose and why?

  • Install Action View dependency tracking and the synthetic resolver during engine initialization, without checking whether any component opted in.
  • Register component subclasses from ViewComponent::Base and share registration for literal renders and explicit # Template Dependency: declarations. Store actual class names and virtual paths rather than reconstructing names with camelize, preserving acronym names and custom paths without retaining stale class objects across reloads.
  • Move .cache_digest and component-template fragment digest integration to ViewComponent::Base. Direct digest computation also registers the component, including any overridden virtual path.
  • Keep ExperimentallyCacheable focused on the opt-in cache_on API. Automatic digest tracking does not automatically cache rendered output or add cache_on to all components.
  • Preserve unexpected digest-error propagation from Raise errors while computing cache digests #2712. Dynamic renders still require explicit declarations, and partials continue using Rails' digest behavior.

This intentionally changes the default for all applications: existing Rails fragment cache blocks involving components now include component source dependencies, even if no component includes the experimental caching module. Components without fragment blocks or cache_on do not start caching output.

Anything you want to highlight for special attention from reviewers?

Regression coverage includes template and Ruby dependencies without caching opt-in, explicit declarations, transitive invalidation through a child with a custom virtual path to an acronym-named grandchild, actual fragment output after source changes, discovery starting from an empty registry, direct digest computation without prior registration, and autoload error propagation.

Component-hosted fragment fixtures no longer include the caching module, so existing exact-key, inherited-template, invalidation, and partial fall-through tests now exercise automatic behavior. The view fragment fixture renders only components without caching opt-in.

The sandbox's Zeitwerk inflector maps http_untracked_component to HTTPUntrackedComponent without changing Active Support's global inflections, exercising names that cannot be recovered with path.camelize.

Validation:

  • Full default suite: 662 Minitests, 5 engine compatibility tests, and 8 RSpec examples, all passing.
  • Rails 7.1 caching suites: 99 tests / 218 assertions, all passing.
  • Full StandardRB, ERB lint, caching guide prose lint, and git diff --check pass.
  • Fresh minimal Rails application with no caching opt-in installs both tracking hooks and computes a plain component's digest.
  • Regenerated public API documentation for .cache_digest.

Erik is credited as a co-author for the original proposals and regression coverage.

Consolidate the fixes proposed in #2711 and #2713. Register literal and declared dependencies by their actual class names and virtual paths, preserving acronym names, custom paths, and transitive invalidation without enabling output caching or suppressing digest errors.

Co-authored-by: Erik Axel Nielsen <erikaxel@lucalabs.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62a65b38-1933-46c3-aa8b-de40801e2c7f
joelhawksley and others added 4 commits October 9, 2026 12:16
Split the guide sentence flagged by Vale, remove directives for a Rails cop not loaded by StandardRB, and remove a redundant line continuation rejected by current RuboCop.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62a65b38-1933-46c3-aa8b-de40801e2c7f
Install digest discovery at engine initialization and move component digest APIs and fragment key integration to Base. Track every component automatically while keeping cache_on output caching opt-in.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62a65b38-1933-46c3-aa8b-de40801e2c7f
@joelhawksley joelhawksley changed the title Track discovered component dependencies without per-component caching opt-in Automatically track source digests for all components Oct 15, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62a65b38-1933-46c3-aa8b-de40801e2c7f

This branch has not been deployed

No deployments
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.

1 participant