0
# Streaming Rendering
1
2
Progressive rendering capabilities that allow sending HTML to the client as it's generated, providing better perceived performance and user experience. Streaming is ideal for larger applications where you want to show content immediately rather than waiting for the complete page to render.
3
4
## Capabilities
5
6
### renderToSimpleStream
7
8
Core streaming function that renders to a simple readable interface. This is the foundation for all other streaming functions and allows custom stream implementations.
9
10
```typescript { .api }
11
/**
12
* Renders input in streaming mode using a simple readable interface
13
* @param input - Vue application instance or VNode to render
14
* @param context - SSR context for teleports and additional data
15
* @param stream - Stream implementation with push and destroy methods
16
* @returns The same stream instance passed in
17
*/
18
function renderToSimpleStream<T extends SimpleReadable>(
19
input: App | VNode,
20
context: SSRContext,
21
stream: T
22
): T;
23
24
interface SimpleReadable {
25
/** Push a chunk of content to the stream, null indicates end */
26
push(chunk: string | null): void;
27
/** Handle errors and cleanup */
28
destroy(err: any): void;
29
}
30
```
31
32
**Usage Examples:**
33
34
```typescript
35
import { createSSRApp } from "vue";
36
import { renderToSimpleStream } from "@vue/server-renderer";
37
38
const app = createSSRApp({
39
template: `
40
<div>
41
<h1>Streaming Content</h1>
42
<p>This content is sent progressively</p>
43
</div>
44
`,
45
});
46
47
// Create a simple stream collector
48
let result = '';
49
const context = {};
50
51
const stream = renderToSimpleStream(app, context, {
52
push(chunk) {
53
if (chunk === null) {
54
// Rendering complete
55
console.log('Final result:', result);
56
console.log('Teleports:', context.teleports);
57
} else {
58
// Append chunk to result
59
result += chunk;
60
console.log('Received chunk:', chunk);
61
}
62
},
63
destroy(err) {
64
console.error('Stream error:', err);
65
},
66
});
67
```
68
69
### Custom Stream Implementation
70
71
You can implement custom stream handling for specific use cases:
72
73
```typescript
74
import { renderToSimpleStream } from "@vue/server-renderer";
75
76
class CustomResponseStream {
77
constructor(private response: Response) {}
78
79
push(chunk: string | null): void {
80
if (chunk === null) {
81
// Complete the response
82
this.response.end();
83
} else {
84
// Write chunk to response
85
this.response.write(chunk);
86
}
87
}
88
89
destroy(err: any): void {
90
console.error('Streaming error:', err);
91
this.response.status(500).end('Internal Server Error');
92
}
93
}
94
95
// Usage with custom stream
96
const app = createSSRApp(/* your app */);
97
const response = getHttpResponse(); // Your HTTP response object
98
const stream = new CustomResponseStream(response);
99
100
renderToSimpleStream(app, {}, stream);
101
```
102
103
### Async Component Handling
104
105
Streaming automatically handles async components and renders them as they resolve:
106
107
```typescript
108
import { createSSRApp, defineAsyncComponent } from "vue";
109
import { renderToSimpleStream } from "@vue/server-renderer";
110
111
const AsyncComponent = defineAsyncComponent(() =>
112
new Promise(resolve => {
113
setTimeout(() => {
114
resolve({
115
template: '<div>Async content loaded!</div>'
116
});
117
}, 1000);
118
})
119
);
120
121
const app = createSSRApp({
122
components: { AsyncComponent },
123
template: `
124
<div>
125
<h1>Initial Content</h1>
126
<AsyncComponent />
127
<p>More content</p>
128
</div>
129
`,
130
});
131
132
const chunks: string[] = [];
133
renderToSimpleStream(app, {}, {
134
push(chunk) {
135
if (chunk === null) {
136
console.log('Streaming complete');
137
console.log('All chunks:', chunks);
138
} else {
139
console.log('Chunk received:', chunk);
140
chunks.push(chunk);
141
}
142
},
143
destroy(err) {
144
console.error('Error:', err);
145
},
146
});
147
148
// Output will show chunks being received as async components resolve
149
```
150
151
### Error Handling in Streams
152
153
Streaming includes built-in error handling and cleanup:
154
155
```typescript
156
import { createSSRApp } from "vue";
157
import { renderToSimpleStream } from "@vue/server-renderer";
158
159
const app = createSSRApp({
160
setup() {
161
// Simulate an error during rendering
162
throw new Error("Component rendering failed");
163
},
164
template: `<div>This won't be reached</div>`,
165
});
166
167
renderToSimpleStream(app, {}, {
168
push(chunk) {
169
console.log('Received:', chunk);
170
},
171
destroy(err) {
172
// This will be called with the error
173
console.error('Streaming failed:', err.message);
174
// Handle error - send error page, log, etc.
175
},
176
});
177
```
178
179
### Performance Benefits
180
181
Streaming provides several performance advantages:
182
183
1. **Faster Time to First Byte (TTFB)**: Users see content immediately
184
2. **Progressive Loading**: Content appears as it's rendered
185
3. **Better Perceived Performance**: Users can interact with visible content while rest loads
186
4. **Memory Efficiency**: Content is sent immediately rather than buffered
187
188
### Best Practices
189
190
```typescript
191
import { renderToSimpleStream } from "@vue/server-renderer";
192
193
// Always handle both success and error cases
194
renderToSimpleStream(app, context, {
195
push(chunk) {
196
if (chunk === null) {
197
// Always handle completion
198
this.finalize();
199
} else {
200
// Process chunk immediately
201
this.writeChunk(chunk);
202
}
203
},
204
destroy(err) {
205
// Always handle errors gracefully
206
this.handleError(err);
207
},
208
});
209
210
// Consider teleport handling
211
renderToSimpleStream(app, context, {
212
push(chunk) {
213
if (chunk === null) {
214
// Process teleports after main content
215
if (context.teleports) {
216
for (const [target, content] of Object.entries(context.teleports)) {
217
this.insertTeleport(target, content);
218
}
219
}
220
} else {
221
this.writeChunk(chunk);
222
}
223
},
224
destroy: this.handleError.bind(this),
225
});
226
```
227
228
## Integration Patterns
229
230
### Framework Integration
231
232
Streaming works well with most web frameworks:
233
234
```typescript
235
// Express.js example pattern
236
app.get('/stream', (req, res) => {
237
const vueApp = createSSRApp(/* your app */);
238
239
renderToSimpleStream(vueApp, {}, {
240
push(chunk) {
241
if (chunk === null) {
242
res.end();
243
} else {
244
res.write(chunk);
245
}
246
},
247
destroy(err) {
248
res.status(500).end('Error occurred');
249
},
250
});
251
});
252
```
253
254
### Caching Considerations
255
256
When implementing caching with streaming, consider chunk-level caching:
257
258
```typescript
259
const cache = new Map();
260
261
renderToSimpleStream(app, context, {
262
push(chunk) {
263
if (chunk !== null) {
264
// Cache chunks for potential reuse
265
cache.set(this.chunkId++, chunk);
266
}
267
},
268
destroy: this.handleError,
269
});
270
```