| name | wsh-sse-optimization |
| description | SSE streaming optimization — batching char-by-char events and debouncing React re-renders for Crok AI chat performance |
WSH: SSE Streaming Optimization
Optimizing Server-Sent Events (SSE) streaming where character-by-character emission causes thousands of events and React re-renders, destroying TBT scores.
Use this skill when the Crok AI chat SSE endpoint streams individual characters, causing excessive client-side re-renders.
Techniques
Server-Side: Batch Characters into Chunks
Instead of emitting one SSE event per character, batch into word/sentence-sized chunks.
for (const char of response) {
res.write(`event: message\nid: ${messageId++}\ndata: ${JSON.stringify({ text: char, done: false })}\n\n`);
}
const CHUNK_SIZE = 50;
for (let i = 0; i < response.length; i += CHUNK_SIZE) {
if (res.closed) break;
const chunk = response.slice(i, i + CHUNK_SIZE);
const data = JSON.stringify({ text: chunk, done: false });
res.write(`event: message\nid: ${messageId++}\ndata: ${data}\n\n`);
}
Impact: Reduces SSE events from ~5000+ to ~100. Each event triggers an EventSource onmessage callback, JSON parse, and React setState. Reducing events by 50x dramatically cuts TBT.
Client-Side: No Changes Needed
The existing useSSE hook concatenates text via onMessage callback. It already handles multi-character chunks correctly since onMessage does prevContent + data.text. No client changes required if the server sends larger chunks.
Pitfalls
| Pitfall | Symptom | Fix |
|---|
| Chunk size too large | Response feels "jumpy" instead of streaming | Use 30-80 chars, balancing UX and performance |
| Breaking mid-UTF8 | Garbled characters | Use Array.from(response) to iterate by codepoints, then batch |
| SSE format issues | Client receives partial data | Ensure each res.write is a complete SSE event |
VRT Risks
| Change | Visual Impact | Mitigation |
|---|
| Faster response delivery | Chat messages appear faster but same content | None needed — VRT captures final state |
| Text chunking | None — final text is identical | Verify final content matches |
Project-Specific Notes
- The Crok response is a ~307-line Markdown file (
crok-response.md) containing code blocks, math formulas, tables
- Response is ~5000+ characters → ~5000+ SSE events at char-by-char
- Client uses
react-markdown + rehype-katex + react-syntax-highlighter to render each update
- Every
setContent() call triggers full markdown re-parse and re-render
- Batching to 50-char chunks = ~100 events = 50x fewer re-renders