0
# @vitest/web-worker
1
2
@vitest/web-worker provides Web Worker support for Vitest testing without requiring JSDom. It simulates Web Worker functionality in the same thread, enabling developers to test web worker code in unit tests while maintaining full compatibility with the Web Worker API.
3
4
## Package Information
5
6
- **Package Name**: @vitest/web-worker
7
- **Package Type**: npm
8
- **Language**: TypeScript
9
- **Installation**: `npm install -D @vitest/web-worker`
10
11
## Core Imports
12
13
**Main entry (side-effect only, no exports):**
14
```typescript
15
import '@vitest/web-worker';
16
```
17
18
**Pure entry for manual setup:**
19
```typescript
20
import { defineWebWorkers } from '@vitest/web-worker/pure';
21
```
22
23
CommonJS (pure entry only):
24
```javascript
25
const { defineWebWorkers } = require('@vitest/web-worker/pure');
26
```
27
28
## Basic Usage
29
30
### Global Setup
31
32
Add to your Vitest configuration for global Web Worker support:
33
34
```typescript
35
import { defineConfig } from 'vitest/node';
36
37
export default defineConfig({
38
test: {
39
setupFiles: ['@vitest/web-worker'],
40
},
41
});
42
```
43
44
### Test Usage
45
46
```typescript
47
import '@vitest/web-worker';
48
import MyWorker from './worker?worker';
49
50
const worker = new MyWorker();
51
worker.postMessage('hello');
52
worker.onmessage = (e) => {
53
console.log(e.data); // 'hello world'
54
};
55
56
// Or with URL-based workers
57
const worker2 = new Worker(new URL('./worker.ts', import.meta.url));
58
```
59
60
## Architecture
61
62
@vitest/web-worker is built around these key components:
63
64
- **Automatic Setup**: Main entry point automatically configures global Worker/SharedWorker
65
- **Pure Setup**: Manual configuration through `defineWebWorkers` function
66
- **Same-thread Simulation**: Workers run in the same thread as tests for synchronous testing
67
- **Message Cloning**: Configurable message cloning strategies (native, ponyfill, none)
68
- **Inline Execution**: Uses VitestExecutor to run worker code in isolated contexts
69
70
## Capabilities
71
72
### Worker Configuration
73
74
Configure Web Worker behavior and message cloning strategies.
75
76
```typescript { .api }
77
/**
78
* Defines Worker and SharedWorker constructors on globalThis
79
* @param options - Optional configuration for worker behavior
80
*/
81
function defineWebWorkers(options?: DefineWorkerOptions): void;
82
83
interface DefineWorkerOptions {
84
/** Cloning strategy for message passing in Worker communication */
85
clone: CloneOption;
86
}
87
88
type CloneOption = 'native' | 'ponyfill' | 'none';
89
```
90
91
### Worker Constructor
92
93
Create simulated Web Workers for testing.
94
95
```typescript { .api }
96
/**
97
* Web Worker constructor that simulates worker behavior in same thread
98
* Available globally after importing '@vitest/web-worker' or calling defineWebWorkers()
99
*/
100
declare class Worker extends EventTarget {
101
/** Message event handler */
102
onmessage: ((event: MessageEvent) => void) | null;
103
/** Message error event handler */
104
onmessageerror: ((event: MessageEvent) => void) | null;
105
/** Error event handler */
106
onerror: ((event: ErrorEvent) => void) | null;
107
108
/**
109
* Create a new Worker instance
110
* @param url - Worker script URL or path
111
* @param options - Worker options including name
112
*/
113
constructor(url: URL | string, options?: WorkerOptions);
114
115
/**
116
* Send a message to the worker
117
* @param data - Data to send
118
* @param transferOrOptions - Transfer options or transferable objects
119
*/
120
postMessage(
121
data: any,
122
transferOrOptions?: StructuredSerializeOptions | Transferable[]
123
): void;
124
125
/** Terminate the worker and clean up resources */
126
terminate(): void;
127
}
128
129
interface WorkerOptions {
130
/** Optional name for the worker */
131
name?: string;
132
}
133
```
134
135
### SharedWorker Constructor
136
137
Create simulated Shared Web Workers for testing.
138
139
```typescript { .api }
140
/**
141
* SharedWorker constructor that simulates shared worker behavior
142
* Available globally after importing '@vitest/web-worker' or calling defineWebWorkers()
143
*/
144
declare class SharedWorker extends EventTarget {
145
/** Communication port for the shared worker */
146
readonly port: MessagePort;
147
/** Error event handler */
148
onerror: ((event: ErrorEvent) => void) | null;
149
150
/**
151
* Create a new SharedWorker instance
152
* @param url - SharedWorker script URL or path
153
* @param options - SharedWorker options or name string
154
*/
155
constructor(url: URL | string, options?: WorkerOptions | string);
156
}
157
```
158
159
### Worker Context API
160
161
API available within worker execution context.
162
163
```typescript { .api }
164
/**
165
* Dedicated Worker Global Scope - available as 'self' within worker context
166
* Compatible with standard DedicatedWorkerGlobalScope interface
167
*/
168
interface DedicatedWorkerGlobalScope {
169
/** Message event handler from main thread */
170
onmessage: ((event: MessageEvent) => void) | null;
171
/** Message error event handler */
172
onmessageerror: ((event: MessageEvent) => void) | null;
173
/** Error event handler */
174
onerror: ((event: ErrorEvent) => void) | null;
175
/** Worker origin */
176
readonly origin: string;
177
/** Worker name */
178
readonly name: string;
179
/** Cross-origin isolation status */
180
readonly crossOriginIsolated: boolean;
181
182
/**
183
* Post message to main thread
184
* @param data - Data to send
185
* @param transferOrOptions - Transfer options or transferable objects
186
*/
187
postMessage(
188
data: any,
189
transferOrOptions?: StructuredSerializeOptions | Transferable[]
190
): void;
191
192
/** Close/terminate the worker */
193
close(): void;
194
195
/** Import scripts (not supported in Vite - throws error) */
196
importScripts(): never;
197
198
/** Reference to worker global scope */
199
readonly self: DedicatedWorkerGlobalScope;
200
}
201
202
/**
203
* Shared Worker Global Scope - available as 'self' within shared worker context
204
* Compatible with standard SharedWorkerGlobalScope interface
205
*/
206
interface SharedWorkerGlobalScope {
207
/** Connect event handler when new clients connect */
208
onconnect: ((event: MessageEvent) => void) | null;
209
/** Worker name */
210
readonly name: string;
211
/** Worker origin */
212
readonly origin: string;
213
/** Cross-origin isolation status */
214
readonly crossOriginIsolated: boolean;
215
216
/** Close the worker port */
217
close(): void;
218
219
/** Import scripts (not supported in Vite - throws error) */
220
importScripts(): never;
221
222
/** Reference to shared worker global scope */
223
readonly self: SharedWorkerGlobalScope;
224
}
225
```
226
227
### Supporting Types
228
229
Types used by the defineWebWorkers function.
230
231
```typescript { .api }
232
/** Message cloning strategy options */
233
type CloneOption = 'native' | 'ponyfill' | 'none';
234
235
/** Configuration options for defining web workers */
236
interface DefineWorkerOptions {
237
/** Message cloning strategy for Worker communication */
238
clone: CloneOption;
239
}
240
```
241
242
## Configuration
243
244
### Environment Variables
245
246
Configure worker behavior through environment variables:
247
248
- `VITEST_WEB_WORKER_CLONE`: Set default cloning strategy (`'native' | 'ponyfill' | 'none'`)
249
250
### Debug Logging
251
252
Enable debug logging with the environment variable:
253
254
```bash
255
DEBUG=vitest:web-worker
256
```
257
258
## Import Patterns
259
260
The package supports various worker import patterns:
261
262
```typescript
263
// Vite worker imports with ?worker suffix
264
import MyWorker from './worker?worker';
265
const worker = new MyWorker();
266
267
// Vite shared worker imports with ?sharedworker suffix
268
import MySharedWorker from './worker?sharedworker';
269
const sharedWorker = new MySharedWorker();
270
271
// URL-based worker creation
272
const worker = new Worker(new URL('./worker.ts', import.meta.url));
273
const sharedWorker = new SharedWorker(new URL('./worker.ts', import.meta.url));
274
```
275
276
## Error Handling
277
278
- **Worker Initialization Errors**: Dispatched as 'error' events on the worker instance
279
- **Message Errors**: Failed message cloning results in 'messageerror' events
280
- **Import Scripts**: Throws error as `importScripts` is not supported in Vite workers
281
282
## Usage Examples
283
284
### Basic Worker Communication
285
286
```typescript
287
import '@vitest/web-worker';
288
289
// worker.ts
290
self.onmessage = (e) => {
291
self.postMessage(`${e.data} world`);
292
};
293
294
// test file
295
import MyWorker from './worker?worker';
296
297
const worker = new MyWorker();
298
worker.postMessage('hello');
299
worker.onmessage = (e) => {
300
expect(e.data).toBe('hello world');
301
};
302
```
303
304
### SharedWorker Communication
305
306
```typescript
307
import '@vitest/web-worker';
308
309
// shared-worker.ts
310
self.onconnect = (e) => {
311
const port = e.ports[0];
312
port.onmessage = (event) => {
313
port.postMessage(event.data);
314
};
315
};
316
317
// test file
318
import MySharedWorker from './shared-worker?sharedworker';
319
320
const worker = new MySharedWorker();
321
worker.port.postMessage('test');
322
worker.port.onmessage = (e) => {
323
expect(e.data).toBe('test');
324
};
325
```
326
327
### Custom Cloning Configuration
328
329
```typescript
330
import { defineWebWorkers } from '@vitest/web-worker/pure';
331
332
// Configure with no message cloning for performance
333
defineWebWorkers({ clone: 'none' });
334
335
// Configure with ponyfill cloning for compatibility
336
defineWebWorkers({ clone: 'ponyfill' });
337
338
// Configure with native cloning (requires Node 17+)
339
defineWebWorkers({ clone: 'native' });
340
```
341
342
### Conditional Setup
343
344
```typescript
345
import { defineWebWorkers } from '@vitest/web-worker/pure';
346
347
if (process.env.SUPPORT_WORKERS) {
348
defineWebWorkers({ clone: 'none' });
349
}
350
```
351
352
## Notes
353
354
- Worker does not support `onmessage = () => {}`. Use `self.onmessage = () => {}` instead
355
- Shared worker does not support `onconnect = () => {}`. Use `self.onconnect = () => {}` instead
356
- Transferring Buffer will not change its `byteLength`
357
- Workers have access to the same global space as tests
358
- Requires Node 17+ for native `structuredClone`, otherwise falls back to polyfill or no cloning