Repository navigation
perf(bundle): code-split the Tiptap editor stack out of the eager bundle - #57
Merged
bhackett1024 merged 1 commit intoOct 1, 2026
Conversation
bhackett1024
marked this pull request as ready for review
September 30, 2026 23:04
Rebased on top of #56, which landed the same split on main: the editor now lazy-loads through RichTextEditor.tsx -> RichTextEditorImpl and the command palette lazy-loads in CommandPaletteProvider, so those stand as the chunking mechanism and the duplicate lazy wrapper from this commit is dropped (importers keep importing RichTextEditor unchanged). What remains from this commit is the destroyed-editor guard on the editable-sync effect (skip setEditable once editor.isDestroyed), the last piece of the iu36 hardening not already on main -- the content-sync guard and immediatelyRender: false landed via #56. Addresses the surface reported by Self Healing bug-muojitzp-iu36. Co-authored-by: Brian Hackett <bhackett@replay.io>
bhackett1024
force-pushed
the
task/fix-sh-bug-muojitzp-iu36-788kb-eagerly-l-7yqOo2bt
branch
from
October 1, 2026 16:55
21f8acf to
37c6c2b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Self Healing bug-muojitzp-iu36 (network-performance): production served one eagerly-loaded ~791KB
index-*.jscontaining the entire app — including the Tiptap rich-text editor and its toolbar stack — with zero code-splitting (verified live:https://obvious-issue-tracker-github.netlify.apploads a single 809,810-byte module script on first paint). Every surface pays for the editor even though only three render one.What
LazyRichTextEditor(src/components/ui/LazyRichTextEditor.tsx): aReact.lazywrapper with a layout-stableSuspensefallback; the three consumers (IssueDetailView,ActivityFeed,CreateIssueDialog) swap to it. Vite now emits Tiptap + ProseMirror as a separate on-demand chunk: eager JS drops 809,810 → 388,117 bytes (−52%; 246 → 117 KB gzip), and a fresh shell load fetches zero editor bytes until an editor surface mounts.RichTextEditorlifecycle guards: under the lazy/Suspense mount, React can discard the render that created the editor, and the discarded instance crashed the commit withCannot read properties of null (reading 'cached')(Tiptap's openuseEditor+ lazy/Suspense issue: the hook can hand back an editor destroyed before its first effect runs). Fixed with the vendor-recommended pattern:immediatelyRender: falsepluseditor.isDestroyedguards in the sync effects. Behavior under the original static import is unchanged apart from editor creation moving one effect-tick later.Rejected alternative: route-level splitting of all views — wider surface, and sibling reports this wave already own the command palette and main-bundle re-fetch behaviors; this fix stays scoped to this report's surface.
How to Review
LazyRichTextEditor.tsx(new) + the import/JSX swaps in the three consumers.immediatelyRender: false+isDestroyedguards inRichTextEditor.tsxare the non-obvious part — they are what makes mounting the editor insideSuspensesafe. Without them the issue detail view hard-crashes to a blank screen.Test Evidence
Local build + headless browser (
vite preview): fresh shell load requests 0 editor chunks; opening an issue detail fetches the chunk once and mounts both editors (description + comment composer); the create-issue dialog editor also mounts; typing round-trips into HTML in all three; zero uncaught console errors.npm run lintandnpm run buildgreen.Human author: Brian Hackett (bhackett@replay.io)
🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact