Commit 1ecd7dd
authored
feat(next): prevent admin panel errors when cacheComponents is enabled (#16020)
Fixes #8897, addresses
#14460
Adds initial support for Next.js `cacheComponents` so users who enable
it for their frontend don't get errors from the Payload admin panel.
This PR addresses the obvious breakage but does not guarantee full
compatibility - see the "Known Limitations" section below.
When `cacheComponents` is enabled in `next.config`, Next.js throws "Data
that blocks navigation was accessed outside of `<Suspense>`" errors
because the admin layout reads cookies, headers, and does auth queries
at the top level. This prevents users from enabling `cacheComponents` at
all if Payload is in the same Next.js app.
The fix has two parts. First, `withPayload` now detects
`cacheComponents` in the Next.js config and sets a
`PAYLOAD_CACHE_COMPONENTS_ENABLED` env var. Second, `RootLayout` reads
that env var and conditionally wraps its content in `<Suspense
fallback={null}>` above the `<html>` tag, which suppresses the errors.
When `cacheComponents` is not enabled, the Suspense is not used at all
and behavior is identical to before.
## Known Limitations
These are all caused by Next.js's `cacheComponents` and likely cannot be
fixed from our side.
### Page flash on hard refresh
When `cacheComponents` is enabled, hard refresh shows a brief gray flash
before the admin panel appears. Without `cacheComponents` there is no
flash. There is no per-route opt-out for this behavior. Related issue:
vercel/next.js#86739
### HTTP status codes (404 returns 200)
With `cacheComponents`, `notFound()` returns HTTP 200 instead of 404.
This happens because the Suspense boundary above `<html>` causes Next.js
to commit response headers (with status 200) before `notFound()` runs
inside the suspended content. The not-found UI still renders correctly -
only the HTTP status code is wrong. This is a [documented Next.js
streaming
limitation](https://nextjs.org/docs/app/api-reference/file-conventions/loading#status-codes).
### DOM accumulation breaks Playwright selectors
When `cacheComponents` is enabled, Next.js wraps route segments in
React's `<Activity>` component, keeping up to 3 previously visited pages
in the DOM with `display: none !important` instead of unmounting them.
This means Playwright selectors like `page.locator('#field-title')`
resolve to multiple elements (the visible one and hidden copies from
cached pages), causing strict mode violations. This is a [known
issue](vercel/next.js#86577) affecting all
Next.js apps using `cacheComponents` with Playwright.
Because of this, we cannot reliably run our e2e test suite with
`cacheComponents` enabled. Adapting the test suite would require
rewriting a large number of selectors across hundreds of tests - most of
our e2e tests use `page.locator()` with ID selectors, which would all
break when Activity duplicates the DOM. Until the Next.js team provides
a per-route opt-out for Activity (which they are [actively
exploring](vercel/next.js#86577 (comment))),
we cannot _guarantee_ full admin panel compatibility beyond the initial
error suppression this PR provides.1 parent 1a0f4d0 commit 1ecd7dd
File tree
9 files changed
+69
-14
lines changed- .github/workflows
- utilities
- docs/getting-started
- packages/next/src
- layouts/Root
- views/API
- withPayload
- test
9 files changed
+69
-14
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
293 | 293 | | |
294 | 294 | | |
295 | 295 | | |
296 | | - | |
| 296 | + | |
297 | 297 | | |
298 | 298 | | |
299 | 299 | | |
300 | 300 | | |
301 | 301 | | |
302 | 302 | | |
| 303 | + | |
303 | 304 | | |
304 | 305 | | |
305 | 306 | | |
| |||
396 | 397 | | |
397 | 398 | | |
398 | 399 | | |
399 | | - | |
| 400 | + | |
400 | 401 | | |
401 | 402 | | |
402 | 403 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
| 16 | + | |
15 | 17 | | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| 24 | + | |
22 | 25 | | |
23 | 26 | | |
24 | 27 | | |
| |||
28 | 31 | | |
29 | 32 | | |
30 | 33 | | |
31 | | - | |
| 34 | + | |
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
36 | 39 | | |
37 | 40 | | |
| 41 | + | |
38 | 42 | | |
39 | 43 | | |
40 | 44 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
28 | 36 | | |
29 | 37 | | |
30 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
48 | | - | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
| 24 | + | |
31 | 25 | | |
32 | 26 | | |
33 | 27 | | |
34 | 28 | | |
35 | 29 | | |
36 | | - | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
37 | 39 | | |
38 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
39 | 66 | | |
40 | 67 | | |
41 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
74 | 82 | | |
75 | 83 | | |
76 | 84 | | |
| |||
84 | 92 | | |
85 | 93 | | |
86 | 94 | | |
87 | | - | |
| 95 | + | |
88 | 96 | | |
89 | 97 | | |
90 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
37 | 41 | | |
38 | 42 | | |
39 | 43 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
0 commit comments