or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdinternal-helpers.mdnodejs-integration.mdstreaming-rendering.mdstring-rendering.mdweb-streams.md

streaming-rendering.mddocs/

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

```