Streaming AI Output in Vue 3: The ReadableStream Pipeline Every Frontend Dev Needs
Streaming is now table stakes for any AI product interface. A frontend engineer who can't wire up a `ReadableStream` and parse SSE will ship a chat UI that feels broken compared to every major AI assistant.
Streaming output is the standard for AI chat interfaces because it attacks perceived latency, not absolute latency. When a user sees text appear token by token, the psychological wait collapses even if the total generation time is unchanged. The mechanism relies on a simple protocol agreement—`stream: true` in the request body—and the Server-Sent Events (SSE) format, which delivers each token as a `data:` line over a persistent HTTP connection.
A Vue 3 implementation walks through the full pipeline: `response.body.getReader()` opens the stream, `TextDecoder` converts binary chunks to UTF-8, a buffer reassembles lines that were split across network packets, and a filter isolates SSE `data:` lines. Each line's JSON payload is parsed to extract `delta.content`, which gets appended to a reactive `ref`. Vue's reactivity system then updates the DOM automatically.
The piece also contrasts SSE with WebSocket, noting that SSE's built-in browser reconnection and one-way server-to-client flow make it the right fit for AI streaming. Practical additions include `AbortController` for canceling in-flight requests, error handling for non-OK responses, and a blinking cursor to signal that generation is still active.
Streaming's value is almost entirely psychological—it doesn't speed up the model, but it makes the product feel alive.
The buffer pattern for reassembling split SSE lines is a microcosm of a universal problem in network programming: chunks are not messages.
SSE's built-in auto-reconnect is an underappreciated advantage over WebSocket for read-heavy AI interfaces; it removes an entire class of state-management bugs.
Placing 'Thinking...' before the fetch call is a small UX detail that acknowledges the user's action immediately, preventing the perception that the app is frozen.
Teaching `TextEncoder`/`TextDecoder` alongside the streaming pipeline grounds the abstraction in concrete bytes, which helps developers debug garbled output.