0
# Patching System
1
2
Monkey patching infrastructure for browser and Node.js APIs, enabling zone context preservation across various asynchronous operations.
3
4
## Capabilities
5
6
### Core Patching API
7
8
Zone.js provides a comprehensive patching system to integrate with native APIs.
9
10
```typescript { .api }
11
/**
12
* Patch function type for extending Zone.js functionality
13
* @param global - Global object (window, global, etc.)
14
* @param Zone - Zone constructor
15
* @param api - ZonePrivate API for patch utilities
16
*/
17
type PatchFn = (global: Window, Zone: ZoneType, api: ZonePrivate) => void;
18
19
/**
20
* Load a patch for specified native module
21
* @param name - Unique name for the patch
22
* @param fn - Patch function to execute
23
* @param ignoreDuplicate - Whether to ignore duplicate patch names
24
*/
25
__load_patch(name: string, fn: PatchFn, ignoreDuplicate?: boolean): void;
26
```
27
28
**Usage Examples:**
29
30
```typescript
31
import 'zone.js';
32
33
// Load a custom patch
34
Zone.__load_patch('custom-api', (global, Zone, api) => {
35
// Patch some custom API
36
const originalMethod = global.customAPI?.someMethod;
37
if (originalMethod) {
38
global.customAPI.someMethod = api.wrapWithCurrentZone(
39
originalMethod,
40
'customAPI.someMethod'
41
);
42
}
43
});
44
45
// Load browser patches
46
Zone.__load_patch('browser', (global, Zone, api) => {
47
patchBrowser(Zone);
48
});
49
50
// Load Node.js patches
51
Zone.__load_patch('node', (global, Zone, api) => {
52
patchNode(Zone);
53
});
54
```
55
56
### ZonePrivate API
57
58
Internal API providing utilities for developing custom patches.
59
60
```typescript { .api }
61
/**
62
* Private API for patch development
63
*/
64
interface ZonePrivate {
65
/** Get current zone frame information */
66
currentZoneFrame(): ZoneFrame;
67
68
/** Generate zone symbol with prefix */
69
symbol(name: string): string;
70
71
/** Schedule a microtask */
72
scheduleMicroTask(task?: MicroTask): void;
73
74
/** Handle unhandled errors */
75
onUnhandledError(error: Error): void;
76
77
/** Notify that microtask queue is drained */
78
microtaskDrainDone(): void;
79
80
/** Check if uncaught errors should be shown */
81
showUncaughtError(): boolean;
82
83
/** Patch EventTarget APIs */
84
patchEventTarget(global: any, api: ZonePrivate, apis: any[], options?: any): boolean[];
85
86
/** Patch object properties for event handlers */
87
patchOnProperties(obj: any, properties: string[] | null, prototype?: any): void;
88
89
/** Patch Promise.then method */
90
patchThen(ctor: Function): void;
91
92
/** Patch a method with zone awareness */
93
patchMethod(
94
target: any,
95
name: string,
96
patchFn: (delegate: Function, delegateName: string, name: string) => Function
97
): Function | null;
98
99
/** Bind arguments with zone context */
100
bindArguments(args: any[], source: string): any[];
101
102
/** Patch macrotask APIs (setTimeout, etc.) */
103
patchMacroTask(obj: any, funcName: string, metaCreator: Function): void;
104
105
/** Patch event prototype methods */
106
patchEventPrototype(global: any, api: ZonePrivate): void;
107
108
/** Check if running in IE or Edge */
109
isIEOrEdge(): boolean;
110
111
/** Object.defineProperty reference */
112
ObjectDefineProperty: typeof Object.defineProperty;
113
114
/** Object.getOwnPropertyDescriptor reference */
115
ObjectGetOwnPropertyDescriptor: typeof Object.getOwnPropertyDescriptor;
116
117
/** Object.create reference */
118
ObjectCreate: typeof Object.create;
119
120
/** Array.prototype.slice reference */
121
ArraySlice: typeof Array.prototype.slice;
122
123
/** Patch constructor class */
124
patchClass(className: string): void;
125
126
/** Wrap callback with current zone */
127
wrapWithCurrentZone(callback: any, source: string): any;
128
129
/** Filter properties for patching */
130
filterProperties(target: any, onProperties: string[], ignoreProperties: any[]): string[];
131
132
/** Attach origin reference to patched function */
133
attachOriginToPatched(target: any, origin: any): void;
134
135
/** Redefine property with descriptor */
136
_redefineProperty(target: any, callback: string, desc: any): void;
137
138
/** Native microtask scheduler */
139
nativeScheduleMicroTask(func: Function): void;
140
141
/** Get global objects and utilities */
142
getGlobalObjects(): {
143
globalSources: any;
144
zoneSymbolEventNames: any;
145
eventNames: string[];
146
isBrowser: boolean;
147
isMix: boolean;
148
isNode: boolean;
149
TRUE_STR: string;
150
FALSE_STR: string;
151
ZONE_SYMBOL_PREFIX: string;
152
ADD_EVENT_LISTENER_STR: string;
153
REMOVE_EVENT_LISTENER_STR: string;
154
} | undefined;
155
}
156
```
157
158
### Browser Patches
159
160
Zone.js provides comprehensive patches for browser APIs.
161
162
```typescript { .api }
163
/**
164
* Patch core browser APIs
165
* @param Zone - Zone constructor
166
*/
167
function patchBrowser(Zone: ZoneType): void;
168
169
/**
170
* Patch common browser APIs (timers, RAF, etc.)
171
* @param Zone - Zone constructor
172
*/
173
function patchCommon(Zone: ZoneType): void;
174
175
/**
176
* Patch EventTarget API
177
* @param global - Global object
178
* @param api - ZonePrivate API
179
*/
180
function eventTargetPatch(global: any, api: ZonePrivate): void;
181
182
/**
183
* Patch timer APIs (setTimeout, setInterval)
184
* @param window - Window object
185
* @param setName - Setter function name
186
* @param cancelName - Canceller function name
187
* @param nameSuffix - Name suffix for debugging
188
*/
189
function patchTimer(window: any, setName: string, cancelName: string, nameSuffix: string): void;
190
191
/**
192
* Patch Promise API
193
* @param Zone - Zone constructor
194
*/
195
function patchPromise(Zone: ZoneType): void;
196
197
/**
198
* Patch Fetch API
199
* @param Zone - Zone constructor
200
*/
201
function patchFetch(Zone: ZoneType): void;
202
```
203
204
**Usage Examples:**
205
206
```typescript
207
// Browser patches are typically loaded automatically
208
import 'zone.js'; // Loads browser patches
209
210
// Manual browser patching
211
Zone.__load_patch('browser', (global, Zone, api) => {
212
patchBrowser(Zone);
213
});
214
215
// Patch specific APIs
216
Zone.__load_patch('timers', (global, Zone, api) => {
217
patchTimer(global, 'setTimeout', 'clearTimeout', 'Timeout');
218
patchTimer(global, 'setInterval', 'clearInterval', 'Interval');
219
});
220
221
Zone.__load_patch('promise', (global, Zone, api) => {
222
patchPromise(Zone);
223
});
224
```
225
226
### Node.js Patches
227
228
Zone.js provides patches for Node.js APIs to enable zone context in server environments.
229
230
```typescript { .api }
231
/**
232
* Patch core Node.js APIs
233
* @param Zone - Zone constructor
234
*/
235
function patchNode(Zone: ZoneType): void;
236
237
/**
238
* Patch EventEmitter API
239
* @param Zone - Zone constructor
240
*/
241
function patchEvents(Zone: ZoneType): void;
242
243
/**
244
* Patch File System API
245
* @param Zone - Zone constructor
246
*/
247
function patchFs(Zone: ZoneType): void;
248
249
/**
250
* Patch Node.js utilities
251
* @param Zone - Zone constructor
252
*/
253
function patchNodeUtil(Zone: ZoneType): void;
254
```
255
256
**Usage Examples:**
257
258
```typescript
259
// Node.js patches
260
import 'zone.js/node';
261
262
// Or load manually
263
Zone.__load_patch('node', (global, Zone, api) => {
264
patchNode(Zone);
265
});
266
267
// Patch specific Node.js APIs
268
Zone.__load_patch('events', (global, Zone, api) => {
269
patchEvents(Zone);
270
});
271
272
Zone.__load_patch('fs', (global, Zone, api) => {
273
patchFs(Zone);
274
});
275
```
276
277
### Web API Patches
278
279
Extended patches for modern web APIs.
280
281
```typescript { .api }
282
/**
283
* Patch Canvas API
284
* @param Zone - Zone constructor
285
*/
286
function patchCanvas(Zone: ZoneType): void;
287
288
/**
289
* Patch MessagePort API
290
* @param Zone - Zone constructor
291
*/
292
function patchMessagePort(Zone: ZoneType): void;
293
294
/**
295
* Patch MediaQuery API
296
* @param Zone - Zone constructor
297
*/
298
function patchMediaQuery(Zone: ZoneType): void;
299
300
/**
301
* Patch Notification API
302
* @param Zone - Zone constructor
303
*/
304
function patchNotifications(Zone: ZoneType): void;
305
306
/**
307
* Patch ResizeObserver API
308
* @param Zone - Zone constructor
309
*/
310
function patchResizeObserver(Zone: ZoneType): void;
311
312
/**
313
* Patch WebRTC PeerConnection API
314
* @param Zone - Zone constructor
315
*/
316
function patchRtcPeerConnection(Zone: ZoneType): void;
317
318
/**
319
* Patch getUserMedia API
320
* @param Zone - Zone constructor
321
*/
322
function patchUserMedia(Zone: ZoneType): void;
323
324
/**
325
* Patch WebSocket API
326
* @param global - Global object
327
* @param api - ZonePrivate API
328
*/
329
function apply(api: ZonePrivate, global: any): void;
330
```
331
332
**Usage Examples:**
333
334
```typescript
335
import 'zone.js';
336
337
// Load specific web API patches
338
Zone.__load_patch('canvas', (global, Zone, api) => {
339
patchCanvas(Zone);
340
});
341
342
Zone.__load_patch('webapis-notification', (global, Zone, api) => {
343
patchNotifications(Zone);
344
});
345
346
Zone.__load_patch('webapis-resize-observer', (global, Zone, api) => {
347
patchResizeObserver(Zone);
348
});
349
350
// Use patched APIs - zone context is preserved
351
const myZone = Zone.current.fork({ name: 'web-api-zone' });
352
353
myZone.run(() => {
354
// Notification API preserves zone context
355
new Notification('Test', {
356
body: 'Zone context preserved'
357
});
358
359
// ResizeObserver preserves zone context
360
const observer = new ResizeObserver((entries) => {
361
console.log('ResizeObserver in:', Zone.current.name); // 'web-api-zone'
362
});
363
364
observer.observe(document.body);
365
});
366
```
367
368
### Framework Integration Patches
369
370
Patches for test frameworks and libraries.
371
372
```typescript { .api }
373
/**
374
* Patch Jasmine testing framework
375
* @param Zone - Zone constructor
376
*/
377
function patchJasmine(Zone: ZoneType): void;
378
379
/**
380
* Patch Jest testing framework
381
* @param Zone - Zone constructor
382
*/
383
function patchJest(Zone: ZoneType): void;
384
385
/**
386
* Patch Mocha testing framework
387
* @param Zone - Zone constructor
388
*/
389
function patchMocha(Zone: ZoneType): void;
390
391
/**
392
* Patch RxJS library
393
* @param Zone - Zone constructor
394
*/
395
function patchRxJs(Zone: ZoneType): void;
396
```
397
398
**Usage Examples:**
399
400
```typescript
401
// Framework patches are typically loaded with testing bundle
402
import 'zone.js/testing'; // Includes Jasmine patches
403
404
// Manual framework patching
405
Zone.__load_patch('jasmine', (global, Zone, api) => {
406
patchJasmine(Zone);
407
});
408
409
Zone.__load_patch('rxjs', (global, Zone, api) => {
410
patchRxJs(Zone);
411
});
412
```
413
414
### Custom Patch Development
415
416
Utilities for developing custom patches.
417
418
```typescript { .api }
419
/**
420
* Patch object properties for event handlers
421
* @param obj - Object to patch
422
* @param properties - Properties to patch
423
* @param prototype - Prototype to patch (optional)
424
*/
425
function patchOnProperties(obj: any, properties: string[] | null, prototype?: any): void;
426
427
/**
428
* Patch a single property
429
* @param obj - Object to patch
430
* @param prop - Property name to patch
431
* @param prototype - Prototype to patch (optional)
432
*/
433
function patchProperty(obj: any, prop: string, prototype?: any): void;
434
435
/**
436
* Patch method with zone awareness
437
* @param target - Object containing the method
438
* @param name - Method name
439
* @param patchFn - Function that returns the patched method
440
*/
441
function patchMethod(target: any, name: string, patchFn: Function): Function | null;
442
443
/**
444
* Patch microtask method
445
* @param obj - Object to patch
446
* @param funcName - Function name
447
* @param metaCreator - Function to create task metadata
448
*/
449
function patchMicroTask(obj: any, funcName: string, metaCreator: Function): void;
450
451
/**
452
* Patch macrotask method
453
* @param obj - Object to patch
454
* @param funcName - Function name
455
* @param metaCreator - Function to create task metadata
456
*/
457
function patchMacroTask(obj: any, funcName: string, metaCreator: Function): void;
458
```
459
460
**Usage Examples:**
461
462
```typescript
463
// Custom patch for a third-party library
464
Zone.__load_patch('custom-library', (global, Zone, api) => {
465
const CustomLib = global.CustomLib;
466
if (!CustomLib) return;
467
468
// Patch event properties
469
api.patchOnProperties(CustomLib.prototype, ['ondata', 'onerror', 'onend']);
470
471
// Patch async method
472
api.patchMethod(CustomLib.prototype, 'asyncMethod', (delegate, delegateName, name) => {
473
return function(this: any, ...args: any[]) {
474
const callback = args[args.length - 1];
475
if (typeof callback === 'function') {
476
args[args.length - 1] = api.wrapWithCurrentZone(callback, `${name}_callback`);
477
}
478
return delegate.apply(this, args);
479
};
480
});
481
482
// Patch timer-like method
483
api.patchMacroTask(CustomLib.prototype, 'delayedCall', (self: any, args: any[]) => {
484
return {
485
source: 'CustomLib.delayedCall',
486
delay: args[1] || 0,
487
callback: args[0],
488
args: []
489
};
490
});
491
});
492
493
// Use the patched library
494
const myZone = Zone.current.fork({ name: 'custom-lib-zone' });
495
496
myZone.run(() => {
497
const lib = new CustomLib();
498
499
// Event handlers preserve zone context
500
lib.ondata = (data) => {
501
console.log('Data received in:', Zone.current.name); // 'custom-lib-zone'
502
};
503
504
// Async methods preserve zone context
505
lib.asyncMethod((result) => {
506
console.log('Async result in:', Zone.current.name); // 'custom-lib-zone'
507
});
508
});
509
```
510
511
### Patch Utilities
512
513
Common utilities used in patch development.
514
515
```typescript { .api }
516
/**
517
* Wrap callback with current zone context
518
* @param callback - Function to wrap
519
* @param source - Debug identifier
520
* @returns Wrapped function
521
*/
522
function wrapWithCurrentZone<T extends Function>(callback: T, source: string): T;
523
524
/**
525
* Generate zone symbol with prefix
526
* @param name - Symbol name
527
* @returns Prefixed symbol string
528
*/
529
function zoneSymbol(name: string): string;
530
531
/**
532
* Check if property is writable
533
* @param propertyDesc - Property descriptor
534
* @returns true if property is writable
535
*/
536
function isPropertyWritable(propertyDesc: any): boolean;
537
538
/**
539
* Copy symbol properties from source to destination
540
* @param src - Source object
541
* @param dest - Destination object
542
*/
543
function copySymbolProperties(src: any, dest: any): void;
544
545
/**
546
* Attach origin reference to patched function
547
* @param patched - Patched function
548
* @param original - Original function
549
*/
550
function attachOriginToPatched(patched: Function, original: any): void;
551
```
552
553
**Usage Examples:**
554
555
```typescript
556
// Utility usage in custom patches
557
Zone.__load_patch('utilities-example', (global, Zone, api) => {
558
const originalSetTimeout = global.setTimeout;
559
const timeoutSymbol = api.symbol('setTimeout');
560
561
// Store original function
562
global[timeoutSymbol] = originalSetTimeout;
563
564
// Create wrapped version
565
global.setTimeout = function(callback: Function, delay: number, ...args: any[]) {
566
const wrappedCallback = api.wrapWithCurrentZone(callback, 'setTimeout');
567
return originalSetTimeout.call(this, wrappedCallback, delay, ...args);
568
};
569
570
// Attach origin reference
571
api.attachOriginToPatched(global.setTimeout, originalSetTimeout);
572
573
// Copy any symbol properties
574
api.copySymbolProperties(originalSetTimeout, global.setTimeout);
575
});
576
```