You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Track components that haven't opted into cacheability
- Resolve any ViewComponent::Base descendant as a dependency rather than
only registered ones, so a digest can't be silently partial
- Resolve unregistered components back from their virtual path, requiring
the path to round-trip to the same class
- Add regression tests for an untracked child changing without moving the
parent's digest or the fragment digest
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,6 +10,14 @@ nav_order: 6
10
10
11
11
## main
12
12
13
+
* Track every component in a fragment's render tree when the experimental caching feature is enabled, not only the components that included `ViewComponent::ExperimentallyCacheable`.
14
+
15
+
Dependency tracking used to be transitively opt-in: a parent that included the module got a digest covering only the children that also included it. The digest looked complete regardless, and the gap surfaced as stale HTML at an arbitrary later time, whenever an unrelated tracked component happened to change.
16
+
17
+
Only the component wrapped in the `<% cache %>` block needs the include now. Applications that never opt in are unaffected, since dependency tracking still short-circuits until the first component registers.
18
+
19
+
*Erik Axel Nielsen*
20
+
13
21
* Invalidate Action View's memoized template digests when a component registers with `ViewComponent::CacheDigest`, so a digest computed before the component loaded isn't served for the rest of the process.
Include `ViewComponent::ExperimentallyCacheable` in each component that should participate in caching:
31
+
Include `ViewComponent::ExperimentallyCacheable` in the component rendered inside the `cache` block:
32
32
33
33
```ruby
34
34
classPostComponent < ViewComponent::Base
@@ -42,6 +42,8 @@ end
42
42
43
43
That's all that's needed for the `<% cache %>` block above to work. The component is registered with Rails' digest tree, and the fragment is invalidated when the component's template, Ruby class, sidecar files, superclasses, child components, or rendered partials change, including components and partials rendered from an inline template or a `#call` method.
44
44
45
+
Once any component in the application has opted in, the whole render tree is tracked: the child components `PostComponent` renders, and the components *they* render, invalidate the fragment even when they don't include the module.
46
+
45
47
## Caching inside a component template
46
48
47
49
A `<% cache %>` block written inside a component's own template has the same problem, for the same reason: Rails digests the template that's rendering, and a component's template isn't in the view paths, so there's nothing to digest.
@@ -202,7 +204,7 @@ The same works in a template, where the branch is often the more natural place f
202
204
<%= render component.new(post: @post) %>
203
205
```
204
206
205
-
Declared components must include `ViewComponent::ExperimentallyCacheable` themselves, since a component that hasn't opted in has no digest to depend on.
207
+
Declared components don't need to include `ViewComponent::ExperimentallyCacheable` themselves. A component that overrides `virtual_path` does, since it's otherwise digested under a path that doesn't lead back to it.
0 commit comments