fix(cms): regenerate the import map so the Content field renders #143

Merged
tudor merged 1 commits from fix/payload-import-map into main 2026-09-02 20:12:18 +00:00
Owner

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.ai/code/session_01DXnXQKnPpZBBP61fBQiFkq

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
tudor added 1 commit 2026-09-02 19:44:21 +00:00
fix(cms): regenerate the import map so the Content field renders
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m11s
PR Checks / Backend Smoke (pull_request) Successful in 8s
PR Checks / Build Backend (no push) (pull_request) Successful in 11s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m10s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 52s
d47ac71c47
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

🤖 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.
## 🤖 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 main 2026-09-02 20:12:18 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tudor/school_compare#143