Creating a post in the admin panel showed no Content editor, and saving then failed validation on the field the writer was never shown.
Root cause
The admin panel does not import field components. The server hands the client a path per field and resolves it through the generated map at app/(payload)/admin/importMap.js; a richText field's is @payloadcms/richtext-lexical/rsc#RscEntryLexicalField.
The committed map held a single entry, @payloadcms/next/rsc#CollectionCards, generated before the blog collections existed and never re-run. A path missing from the map is not an error the panel reports. The field simply does not render, while required is still enforced server-side on save, which is why the failure presented as an unsaveable form rather than as anything diagnosable.
next build does not regenerate the map, so the stale copy shipped in the image. The editor was equally broken on staging and production.
The fix
Regenerating with payload generate:importmap adds 24 entries: the lexical RSC field, cell and diff components, BlocksFeatureClient for the Callout block, and the default toolbar features.
Two things stop it drifting again.
There was no script to run, which is how it drifted in the first place. package.json gets generate:importmap.
__tests__/payload/import-map.test.ts asserts the map carries an entry for each thing the config asks for, in the source-reading style of the other payload suites. Checked out against the old map, all five of its tests fail.
CLAUDE.md gains a note in the CMS section, since the silent-failure mode is not something you would infer from the config.
Verification
tsc --noEmit clean.
404 tests across 48 suites pass, including all four __tests__/payload/ suites.
next build succeeds with DATABASE_URL unset, as CI builds it.
No e2e/ change. The journeys cover the public blog and assert /admin is noindex; the authenticated editor is not reachable from them, and no public behaviour changes here. The real proof is creating a post in the staging panel once this is deployed.
Creating a post in the admin panel showed no Content editor, and saving then failed validation on the field the writer was never shown.
## Root cause
The admin panel does not import field components. The server hands the client a *path* per field and resolves it through the generated map at `app/(payload)/admin/importMap.js`; a richText field's is `@payloadcms/richtext-lexical/rsc#RscEntryLexicalField`.
The committed map held a single entry, `@payloadcms/next/rsc#CollectionCards`, generated before the blog collections existed and never re-run. A path missing from the map is not an error the panel reports. The field simply does not render, while `required` is still enforced server-side on save, which is why the failure presented as an unsaveable form rather than as anything diagnosable.
`next build` does not regenerate the map, so the stale copy shipped in the image. The editor was equally broken on staging and production.
## The fix
Regenerating with `payload generate:importmap` adds 24 entries: the lexical RSC field, cell and diff components, `BlocksFeatureClient` for the Callout block, and the default toolbar features.
Two things stop it drifting again.
- There was no script to run, which is how it drifted in the first place. `package.json` gets `generate:importmap`.
- `__tests__/payload/import-map.test.ts` asserts the map carries an entry for each thing the config asks for, in the source-reading style of the other payload suites. Checked out against the old map, all five of its tests fail.
`CLAUDE.md` gains a note in the CMS section, since the silent-failure mode is not something you would infer from the config.
## Verification
- `tsc --noEmit` clean.
- 404 tests across 48 suites pass, including all four `__tests__/payload/` suites.
- `next build` succeeds with `DATABASE_URL` unset, as CI builds it.
No `e2e/` change. The journeys cover the public blog and assert `/admin` is noindex; the authenticated editor is not reachable from them, and no public behaviour changes here. The real proof is creating a post in the staging panel once this is deployed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01DXnXQKnPpZBBP61fBQiFkq
Creating a post in the admin panel showed no Content editor, and saving
failed validation on the field the writer was never shown.
The admin panel does not import field components. The server hands the
client a path per field, and resolves it through the generated map at
app/(payload)/admin/importMap.js. A richText field's path is
@payloadcms/richtext-lexical/rsc#RscEntryLexicalField. The committed map
held one entry, @payloadcms/next/rsc#CollectionCards, generated before
the blog collections existed and never re-run. A path missing from the
map is not an error the panel reports: the field simply does not render,
while required is still enforced server-side on save.
next build does not regenerate the map, so the stale copy shipped in the
image and the editor was equally broken on staging and production.
Regenerated with payload generate:importmap, which adds the lexical RSC
field, cell and diff components, BlocksFeatureClient for the Callout
block, and the default toolbar features.
Two things stop it drifting again. There was no script to run, so
package.json gets generate:importmap. And a test asserts the map carries
an entry for each thing the config asks for, in the source-reading style
of the other payload suites; against the old map all five fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DXnXQKnPpZBBP61fBQiFkq
This PR documents the Payload admin import-map footgun (a missing entry silently drops a required field from the UI while the server still enforces it), adds a regression test that asserts the generated importMap.js contains the entries the current Posts collection config needs, adds a generate:importmap npm script, and re-generates importMap.js with the full set of lexical feature/RSC entries. The generated file's imports and map entries are internally consistent (each import is used exactly once), and the change looks like a solid, low-risk fix plus guardrail for the field-invisibility bug fixed in a prior commit.
🟡 Minor
nextjs-app/tests/payload/import-map.test.ts: The feature-coverage test only checks 8 of the ~20 lexical feature client entries now in the map (e.g. Underline, Strikethrough, Subscript, Superscript, InlineCode, Paragraph, Align, Indent, Checklist, Relationship, Blockquote, HorizontalRule are untested). If a future regeneration drops one of these untested entries, the test suite won't catch the regression it's meant to guard against.
nextjs-app/tests/payload/import-map.test.ts: Assertions are plain substring/regex checks against the raw file text rather than importing/executing importMap.js, so they can pass even if an entry only appears in a comment or an unrelated string, and won't catch a syntactically broken map file.
## 🤖 AI Code Review (Claude Code)
This PR documents the Payload admin import-map footgun (a missing entry silently drops a required field from the UI while the server still enforces it), adds a regression test that asserts the generated importMap.js contains the entries the current Posts collection config needs, adds a generate:importmap npm script, and re-generates importMap.js with the full set of lexical feature/RSC entries. The generated file's imports and map entries are internally consistent (each import is used exactly once), and the change looks like a solid, low-risk fix plus guardrail for the field-invisibility bug fixed in a prior commit.
### 🟡 Minor
- **nextjs-app/__tests__/payload/import-map.test.ts**: The feature-coverage test only checks 8 of the ~20 lexical feature client entries now in the map (e.g. Underline, Strikethrough, Subscript, Superscript, InlineCode, Paragraph, Align, Indent, Checklist, Relationship, Blockquote, HorizontalRule are untested). If a future regeneration drops one of these untested entries, the test suite won't catch the regression it's meant to guard against.
- **nextjs-app/__tests__/payload/import-map.test.ts**: Assertions are plain substring/regex checks against the raw file text rather than importing/executing importMap.js, so they can pass even if an entry only appears in a comment or an unrelated string, and won't catch a syntactically broken map file.
tudor
merged commit eb6d918650 into main2026-09-02 20:12:18 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Creating a post in the admin panel showed no Content editor, and saving then failed validation on the field the writer was never shown.
Root cause
The admin panel does not import field components. The server hands the client a path per field and resolves it through the generated map at
app/(payload)/admin/importMap.js; a richText field's is@payloadcms/richtext-lexical/rsc#RscEntryLexicalField.The committed map held a single entry,
@payloadcms/next/rsc#CollectionCards, generated before the blog collections existed and never re-run. A path missing from the map is not an error the panel reports. The field simply does not render, whilerequiredis still enforced server-side on save, which is why the failure presented as an unsaveable form rather than as anything diagnosable.next builddoes not regenerate the map, so the stale copy shipped in the image. The editor was equally broken on staging and production.The fix
Regenerating with
payload generate:importmapadds 24 entries: the lexical RSC field, cell and diff components,BlocksFeatureClientfor the Callout block, and the default toolbar features.Two things stop it drifting again.
package.jsongetsgenerate:importmap.__tests__/payload/import-map.test.tsasserts the map carries an entry for each thing the config asks for, in the source-reading style of the other payload suites. Checked out against the old map, all five of its tests fail.CLAUDE.mdgains a note in the CMS section, since the silent-failure mode is not something you would infer from the config.Verification
tsc --noEmitclean.__tests__/payload/suites.next buildsucceeds withDATABASE_URLunset, as CI builds it.No
e2e/change. The journeys cover the public blog and assert/adminis noindex; the authenticated editor is not reachable from them, and no public behaviour changes here. The real proof is creating a post in the staging panel once this is deployed.🤖 Generated with Claude Code
https://claude.ai/code/session_01DXnXQKnPpZBBP61fBQiFkq
🤖 AI Code Review (Claude Code)
This PR documents the Payload admin import-map footgun (a missing entry silently drops a required field from the UI while the server still enforces it), adds a regression test that asserts the generated importMap.js contains the entries the current Posts collection config needs, adds a generate:importmap npm script, and re-generates importMap.js with the full set of lexical feature/RSC entries. The generated file's imports and map entries are internally consistent (each import is used exactly once), and the change looks like a solid, low-risk fix plus guardrail for the field-invisibility bug fixed in a prior commit.
🟡 Minor