0
# Workbox Streams
1
2
Workbox Streams provides utilities for working with ReadableStreams in service workers and web applications. It offers functions to concatenate multiple stream sources into a single ReadableStream, create HTTP responses from concatenated streams, detect browser support for streaming APIs, and implement streaming strategies for Workbox routing.
3
4
## Package Information
5
6
- **Package Name**: workbox-streams
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install workbox-streams`
10
11
## Core Imports
12
13
```typescript
14
import {
15
concatenate,
16
concatenateToResponse,
17
isSupported,
18
strategy,
19
type StreamSource,
20
type StreamsHandlerCallback
21
} from "workbox-streams";
22
```
23
24
For CommonJS:
25
26
```javascript
27
const {
28
concatenate,
29
concatenateToResponse,
30
isSupported,
31
strategy
32
} = require("workbox-streams");
33
```
34
35
## Basic Usage
36
37
```typescript
38
import {
39
concatenate,
40
concatenateToResponse,
41
isSupported,
42
strategy
43
} from "workbox-streams";
44
45
// Check browser support for streaming
46
if (isSupported()) {
47
// Concatenate multiple stream sources
48
const sourcePromises = [
49
fetch('/api/header'),
50
fetch('/api/content'),
51
fetch('/api/footer')
52
];
53
54
const {done, stream} = concatenate(sourcePromises);
55
56
// Or create a Response directly
57
const {done: responseDone, response} = concatenateToResponse(
58
sourcePromises,
59
{'content-type': 'text/html'}
60
);
61
62
// Use in service worker
63
self.addEventListener('fetch', (event) => {
64
event.waitUntil(responseDone);
65
event.respondWith(response);
66
});
67
}
68
```
69
70
## Architecture
71
72
Workbox Streams is built around streaming and fallback patterns:
73
74
- **Stream Concatenation**: Core functionality for combining multiple stream sources sequentially
75
- **Browser Compatibility**: Automatic detection and fallback for browsers without streaming support
76
- **Workbox Integration**: Strategy functions designed for use with Workbox routing
77
- **Response Creation**: Utilities to convert streams into standard Response objects
78
- **Promise Tracking**: Support for service worker waitUntil() patterns
79
80
## Capabilities
81
82
### Stream Concatenation
83
84
Combines multiple stream sources into a single ReadableStream with sequential data flow.
85
86
```typescript { .api }
87
/**
88
* Takes multiple source Promises and returns a ReadableStream with sequential data
89
* @param sourcePromises - Array of Promises resolving to StreamSource objects
90
* @returns Object with completion Promise and ReadableStream
91
*/
92
function concatenate(sourcePromises: Promise<StreamSource>[]): {
93
done: Promise<void>;
94
stream: ReadableStream;
95
};
96
```
97
98
**Usage Example:**
99
100
```typescript
101
import { concatenate } from "workbox-streams";
102
103
const sourcePromises = [
104
Promise.resolve(new Response('Hello ')),
105
Promise.resolve(new Response('World!')),
106
fetch('/api/data')
107
];
108
109
const {done, stream} = concatenate(sourcePromises);
110
111
// Use the stream
112
const response = new Response(stream, {
113
headers: {'content-type': 'text/plain'}
114
});
115
116
// Wait for completion
117
await done;
118
```
119
120
### Response Stream Concatenation
121
122
Creates an HTTP Response with body consisting of concatenated stream data.
123
124
```typescript { .api }
125
/**
126
* Takes multiple source Promises and returns a Response with concatenated data
127
* @param sourcePromises - Array of Promises resolving to StreamSource objects
128
* @param headersInit - Optional headers for the response (if no 'Content-Type', defaults to 'text/html')
129
* @returns Object with completion Promise and Response
130
*/
131
function concatenateToResponse(
132
sourcePromises: Promise<StreamSource>[],
133
headersInit?: HeadersInit
134
): {
135
done: Promise<void>;
136
response: Response;
137
};
138
```
139
140
**Usage Example:**
141
142
```typescript
143
import { concatenateToResponse } from "workbox-streams";
144
145
const sourcePromises = [
146
fetch('/template/header'),
147
fetch('/content/body'),
148
fetch('/template/footer')
149
];
150
151
// With headers
152
const {done, response} = concatenateToResponse(
153
sourcePromises,
154
{
155
'content-type': 'text/html',
156
'cache-control': 'max-age=3600'
157
}
158
);
159
160
// Without headers (defaults to 'text/html')
161
const {done: done2, response: response2} = concatenateToResponse(sourcePromises);
162
163
// Use in service worker
164
self.addEventListener('fetch', (event) => {
165
if (event.request.url.endsWith('/composite-page')) {
166
event.waitUntil(done);
167
event.respondWith(response);
168
}
169
});
170
```
171
172
### Browser Support Detection
173
174
Determines whether the current browser supports streaming features.
175
176
```typescript { .api }
177
/**
178
* Checks if browser supports ReadableStream construction for streaming responses
179
* @returns true if streaming is supported, false otherwise
180
*/
181
function isSupported(): boolean;
182
```
183
184
**Usage Example:**
185
186
```typescript
187
import { isSupported, concatenateToResponse } from "workbox-streams";
188
189
function createCompositeResponse(sources: Promise<StreamSource>[], headers: HeadersInit) {
190
if (isSupported()) {
191
// Use streaming concatenation
192
return concatenateToResponse(sources, headers);
193
} else {
194
// Fallback to waiting for all sources
195
return Promise.all(sources).then(resolvedSources => {
196
// Manual concatenation fallback
197
return new Response(/* combined content */, {headers});
198
});
199
}
200
}
201
```
202
203
### Workbox Strategy Integration
204
205
Creates a strategy function compatible with Workbox routing that handles streaming with automatic fallback.
206
207
```typescript { .api }
208
/**
209
* Creates a Workbox-compatible strategy for streaming responses with fallback
210
* @param sourceFunctions - Array of handler functions returning StreamSource objects
211
* @param headersInit - Optional headers for responses (if no 'Content-Type', defaults to 'text/html')
212
* @returns RouteHandlerCallback compatible with Workbox routing
213
*/
214
function strategy(
215
sourceFunctions: StreamsHandlerCallback[],
216
headersInit?: HeadersInit
217
): RouteHandlerCallback;
218
```
219
220
**Usage Example:**
221
222
```typescript
223
import { strategy } from "workbox-streams";
224
import { registerRoute } from "workbox-routing";
225
226
// Define source functions
227
const sourceFunctions = [
228
// Header source
229
({url, request}) => fetch('/api/header'),
230
// Dynamic content based on URL
231
({url, request}) => fetch(`/api/content${url.pathname}`),
232
// Footer source
233
({url, request}) => fetch('/api/footer')
234
];
235
236
// Create streaming strategy with headers
237
const streamingStrategy = strategy(sourceFunctions, {
238
'content-type': 'text/html',
239
'cache-control': 'no-cache'
240
});
241
242
// Or without headers (defaults to 'text/html')
243
const basicStrategy = strategy(sourceFunctions);
244
245
// Register with Workbox routing
246
registerRoute(
247
({url}) => url.pathname.startsWith('/dynamic/'),
248
streamingStrategy
249
);
250
```
251
252
## Types
253
254
### StreamSource
255
256
Union type representing valid stream sources.
257
258
```typescript { .api }
259
/**
260
* Valid source types for streaming operations
261
*/
262
type StreamSource = Response | ReadableStream | BodyInit;
263
```
264
265
Where `BodyInit` includes: `Blob | BufferSource | FormData | URLSearchParams | string`
266
267
### StreamsHandlerCallback
268
269
Interface for handler functions used in streaming strategies.
270
271
```typescript { .api }
272
/**
273
* Handler function interface for streaming strategies
274
*/
275
interface StreamsHandlerCallback {
276
(options: RouteHandlerCallbackOptions): Promise<StreamSource> | StreamSource;
277
}
278
279
/**
280
* Generic object interface for key-value mapping (from workbox-core)
281
*/
282
interface MapLikeObject {
283
[key: string]: any;
284
}
285
286
/**
287
* Options passed to handler callbacks (from workbox-core)
288
*/
289
interface RouteHandlerCallbackOptions {
290
event: ExtendableEvent;
291
request: Request;
292
url: URL;
293
params?: string[] | MapLikeObject;
294
}
295
296
/**
297
* Route handler callback interface (from workbox-core)
298
*/
299
interface RouteHandlerCallback {
300
(options: RouteHandlerCallbackOptions): Promise<Response>;
301
}
302
```
303
304
## Error Handling
305
306
### Stream Processing Errors
307
308
When stream processing fails, errors are propagated through the Promise chain:
309
310
```typescript
311
import { concatenate } from "workbox-streams";
312
313
const {done, stream} = concatenate([
314
fetch('/api/source1'),
315
fetch('/api/source2')
316
]);
317
318
// Handle errors in the completion promise
319
done.catch(error => {
320
console.error('Stream concatenation failed:', error);
321
});
322
323
// Errors also propagate through the stream
324
const response = new Response(stream);
325
response.text().catch(error => {
326
console.error('Stream reading failed:', error);
327
});
328
```
329
330
### Opaque Response Handling
331
332
Workbox Streams throws a `WorkboxError` when attempting to stream opaque responses:
333
334
```typescript
335
// This will throw WorkboxError: 'opaque-streams-source'
336
const opaqueResponse = await fetch('https://external-api.com/data', {
337
mode: 'no-cors' // Creates opaque response
338
});
339
340
const {stream} = concatenate([Promise.resolve(opaqueResponse)]);
341
// Error: Cannot read from opaque response
342
```
343
344
## Browser Compatibility
345
346
- **Full Support**: Browsers with ReadableStream constructor (Chrome 43+, Firefox 65+, Safari 10.1+)
347
- **Fallback Mode**: Automatic fallback to blob-based concatenation for older browsers
348
- **Service Worker Context**: Designed for service worker environments but works in main thread
349
- **Streaming Benefits**: Only available in supporting browsers; fallback mode waits for all sources to complete