-
Notifications
You must be signed in to change notification settings - Fork 836
Description
Performance degradation with large nested documents (~18 seconds blocking time for mutations)
-- This report was written with help from an AI, that said I am a human 🙃 --
Description
We're experiencing severe performance issues when performing mutations (delete, duplicate, paste) on documents with many pages and nested components. A single delete operation blocks the main thread for ~18 seconds, making the editor unusable for large documents.
Environment
- Puck version: 0.20.2
- React version: 19.0.0
- Node version: 22.16.0
- Browser: Chrome (latest)
- OS: macOS
Document Structure
Our documents are PDF-like with:
- 23 pages (using a custom
Pagecomponent withtype: 'slot') - Each page contains 10+ nested components (tables, text blocks, images)
- ~230 total components across all pages
Performance Analysis
We instrumented the codebase extensively to isolate the bottleneck:
| Metric | Value | % of Total |
|---|---|---|
| Total blocking time | 17,862ms | 100% |
| Our component render time | 42ms (98 renders @ 0.4ms avg) | 0.2% |
| Puck internal processing | ~17,820ms | 99.8% |
Timing Breakdown
Action START: T+0ms
First component renders complete: T+100ms
↓
══════════ 12 SECOND GAP ══════════ ← Puck internals
↓
Second render batch: T+12,100ms
↓
══════════ 5 SECOND GAP ══════════ ← Puck internals
↓
Main thread free: T+17,862ms
Key Finding
99.8% of the time is spent BETWEEN component render batches, not in our component code. Our components render in <1ms each. The blocking time appears to be in Puck's internal state management, likely:
- History/undo system - Deep cloning the entire state tree
- Zone reconciliation - Processing deeply nested slot structures
- Multiple render passes - For selection, overlays, fields, etc.
Reproduction
- Create a document with 20+ pages using slot-based
Pagecomponents - Add 10+ components to each page (tables, text, etc.)
- Perform a delete/duplicate/paste operation
- Observe the UI freeze for 15-20 seconds
Expected Behavior
Mutations should complete in <500ms for a responsive editing experience.
Actual Behavior
Mutations block the main thread for 15-20 seconds, making the editor unusable for production documents.
Questions
- Is there a way to disable or debounce history recording for better performance?
- Are there recommended patterns for optimizing deeply nested slot structures?
- Is there a performance mode or lazy rendering option we're missing?
Workarounds Attempted
- ✅ Memoized all custom components with
React.memo- No significant improvement - ✅ Verified our component render times are <1ms each
We're happy to provide more details or help test potential fixes. This is a critical blocker for our production use case.