Streaming LLM Responses in Vue3 Without Third-Party Libraries
Dependency-free streaming keeps bundle sizes small and avoids the maintenance drag of third-party SSE clients. The buffer-based fragment reassembly pattern applies to any LLM API that emits Server-Sent Events, not just DeepSeek.
Streaming text from large language models no longer requires pulling in axios or dedicated SSE libraries. A single Vue3 component built on the Composition API wires up DeepSeek's chat endpoint using only the browser's built-in Fetch and ReadableStream APIs. A checkbox toggles the `stream` parameter, letting the same request function branch between blocking JSON responses and incremental delta parsing.
The core streaming loop reads binary chunks from `response.body.getReader()`, decodes them with TextDecoder, and filters for SSE `data:` lines. A running buffer catches truncated JSON fragments that span network packets, preventing parse errors that would otherwise break the typewriter effect. Each valid delta is appended to a reactive `ref`, which Vue uses to update the DOM in real time.
Environment variables keep the API key out of source control, and the walkthrough covers common pitfalls: CORS workarounds via Vite proxy or a backend relay, Chinese character encoding, and fallback logic for browsers that lack ReadableStream support.
Many front-end developers reach for SSE client libraries to avoid the boilerplate of ReadableStream, but the boilerplate is small enough that the dependency may not be worth the abstraction.
The buffer-reassembly pattern is the only genuinely tricky part of the whole flow; everything else is standard Fetch and string manipulation.
Toggling between streaming and non-streaming modes in the same function makes the component self-contained for demos, but a production setup would likely split these into separate concerns for error handling and retry logic.