Mail and Admin: Fix rich-text editor crash on Inbox and Batch pages (QA)
Executive summary
Promotes a single fix from development to QA that resolves a runtime crash caused by the CKEditor rich-text editor loading incorrectly during server-side rendering. The Mail Inbox and Batch Mails pages were throwing errors on every load; the editor is now loaded only in the browser when actually needed, eliminating the crash and trimming the initial page payload.
Why this was needed
Production logs from the Mail app were emitting repeated ckeditor-duplicated-modules errors and a cascading TypeError: e.createElement is not a function on every load of /inbox and /batches/mails. CKEditor 5 (v42+) ships browser-ready code and was being mistakenly processed through the server build, causing its internal guard to fire when the same modules were evaluated on both the server and the browser. The Admin app's Email Reminders form carried the same latent defect, and the Vendor app held a dead, unused copy of the editor.
Client / user impact
Mail users no longer hit editor-related crashes when opening the Inbox or Batch Mails pages, and the rich-text editor in the Share-via-Mail dialog (Mail) and the Email Reminders form (Admin) loads reliably. A brief loading skeleton now appears the first time the editor opens so there is no blank gap or layout shift; subsequent opens are instant. Moving the editor to a lazy-loaded chunk also reduces the initial bundle size for these pages.
Technical scope
Promotes PR #982 (fix: resolve CKEditor duplicated-modules SSR crash across mail and admin) from dev to qa. Changes (10 files, +69/-412):
- Mail: removed
"ckeditor5"fromtranspilePackagesinnext.config.ts; wrappedRichTextEditorinShareViaMailDialogwithdynamic(..., { ssr: false })so all dialog consumers bypass SSR; movedckeditor5/ckeditor5.cssout of the root layout into the client editor module; exportedRichTextEditorPropsfor typeddynamicusage. - Admin: removed the CKEditor CSS import from the root layout; applied the same
dynamic({ ssr: false })wrapper to the editor inEmailReminderFormDialog. - @dsm/ui: colocated the CKEditor stylesheet import inside the shared
RichTextEditorcomponent. - Vendor (cleanup): deleted the unused
rich-text-editor.tsx(392 lines, zero importers) and pruned the orphan@ckeditor/ckeditor5-reactandckeditor5dependencies; lockfile updated accordingly. - UX: added a
Skeleton(min-h-[200px]) loading fallback at both lazy call sites.
Risk & mitigation
Low to moderate. The editor now loads asynchronously on first open, so risk centers on the editor failing to mount, missing styles (CSS moved from layout to chunk), or a visible loading delay; these are mitigated by the skeleton fallback and the fact that two existing Mail consumers already used this exact pattern. The Vendor dependency removal and lockfile change are the main cross-app risk, though Vendor renders no rich text. Mitigation: validated on QA across Mail, Admin, and Vendor before promotion to Production.
QA validation focus
- Mail: load
/inboxand/batches/mailsas Internal Admin; confirm nockeditor-duplicated-modulesorcreateElementerrors in console/container logs. - Mail: open a mail row > Share via mail; first open shows a brief skeleton then the editor mounts; type content and send a test share. Re-open the dialog (editor mounts instantly). Repeat from
/batches/mailsand smoke-check/mails/[id]and/batches/mails/[id]. - Admin: open Email Reminders > Create/Edit; editor mounts after a brief skeleton; type and save a body, insert a template variable (e.g.
{{current_date}}), confirm it persists and styles (toolbar/content) render correctly. - Vendor: smoke-test main flows for regressions (dead editor removed). Auth: one login round-trip since the lockfile changed.