Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 45a6bc1

Browse files
committed
fix(WebWorker): Patch WebSockets and XMLHttpRequest in WebWorker
Closes #249
1 parent 8400b3f commit 45a6bc1

7 files changed

+60
-16
lines changed

Diff for: karma.conf.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ module.exports = function (config) {
55
basePath: '',
66
files: [
77
'test/browser_entry_point.ts',
8+
'test/zone_worker_entry_point.ts',
89
'test/**/*.spec.ts',
910
{pattern: 'test/assets/**/*.*', watched: true, served: true, included: false},
1011
// Autowatcch all files to trigger rerun
1112
{pattern: 'lib/**/*.ts', watched: true, served: false, included: false},
12-
{pattern: 'test/**/*.ts', watched: true, served: false, included: false}
13+
{pattern: 'test/**/*.ts', watched: true, served: false, included: false},
14+
{pattern: 'test/ws-webworker-context.ts', watched: true, served: true, included: false},
15+
16+
{pattern: 'dist/**/*.js', watched: true, served: true, included: false}
1317
],
1418

1519
/*
@@ -23,7 +27,9 @@ module.exports = function (config) {
2327

2428
preprocessors: {
2529
'test/browser_entry_point.ts': [ 'webpack', 'sourcemap' ],
30+
'test/zone_worker_entry_point.ts': [ 'webpack', 'sourcemap' ],
2631
'test/**/*.spec.ts': [ 'webpack', 'sourcemap' ],
32+
'test/ws-webworker-context.ts': ['webpack', 'sourcemap']
2733
},
2834
webpack: {
2935
devtool: 'source-map',

Diff for: lib/patch/property-descriptor.ts

+17-13
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,28 @@ import * as keys from '../keys';
55
var eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart message mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error webglcontextrestored webglcontextlost webglcontextcreationerror'.split(' ');
66

77
export function apply() {
8-
if (utils.isWebWorker()){
9-
// on WebWorker so don't apply patch
8+
if (utils.isNode()) {
109
return;
1110
}
12-
11+
1312
var supportsWebSocket = typeof WebSocket !== 'undefined';
1413
if (canPatchViaPropertyDescriptor()) {
1514
// for browsers that we can patch the descriptor: Chrome & Firefox
16-
var onEventNames = eventNames.map(function (property) {
17-
return 'on' + property;
18-
});
19-
utils.patchProperties(HTMLElement.prototype, onEventNames);
15+
if (!utils.isWebWorker()){
16+
var onEventNames = eventNames.map(function (property) {
17+
return 'on' + property;
18+
});
19+
utils.patchProperties(HTMLElement.prototype, onEventNames);
20+
}
2021
utils.patchProperties(XMLHttpRequest.prototype);
2122
if (supportsWebSocket) {
2223
utils.patchProperties(WebSocket.prototype);
2324
}
2425
} else {
2526
// Safari, Android browsers (Jelly Bean)
26-
patchViaCapturingAllTheEvents();
27+
if (!utils.isWebWorker()){
28+
patchViaCapturingAllTheEvents();
29+
}
2730
utils.patchClass('XMLHttpRequest');
2831
if (supportsWebSocket) {
2932
webSocketPatch.apply();
@@ -32,21 +35,22 @@ export function apply() {
3235
}
3336

3437
function canPatchViaPropertyDescriptor() {
35-
if (!Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && typeof Element !== 'undefined') {
38+
if (!utils.isWebWorker() && !Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'onclick')
39+
&& typeof Element !== 'undefined') {
3640
// WebKit https://bugs.webkit.org/show_bug.cgi?id=134364
3741
// IDL interface attributes are not configurable
3842
var desc = Object.getOwnPropertyDescriptor(Element.prototype, 'onclick');
3943
if (desc && !desc.configurable) return false;
4044
}
4145

42-
Object.defineProperty(HTMLElement.prototype, 'onclick', {
46+
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', {
4347
get: function () {
4448
return true;
4549
}
4650
});
47-
var elt = document.createElement('div');
48-
var result = !!elt.onclick;
49-
Object.defineProperty(HTMLElement.prototype, 'onclick', {});
51+
var req = new XMLHttpRequest();
52+
var result = !!req.onreadystatechange;
53+
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', {});
5054
return result;
5155
};
5256

Diff for: lib/patch/register-element.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {_redefineProperty} from './define-property';
22
import * as utils from '../utils';
33

44
export function apply() {
5-
if (utils.isWebWorker() || !('registerElement' in (<any>global).document)) {
5+
if (utils.isWebWorker() || utils.isNode() || !('registerElement' in (<any>global).document)) {
66
return;
77
}
88

Diff for: lib/utils.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import * as keys from './keys';
2+
// Hack since TypeScript isn't compiling this for a worker.
3+
declare var WorkerGlobalScope;
24

35
export function bindArguments(args) {
46
for (var i = args.length - 1; i >= 0; i--) {
@@ -21,7 +23,11 @@ export function patchPrototype(obj, fnNames) {
2123
};
2224

2325
export function isWebWorker() {
24-
return (typeof document === "undefined");
26+
return (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope);
27+
}
28+
29+
export function isNode() {
30+
return (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]');
2531
}
2632

2733
export function patchProperty(obj, prop) {

Diff for: test/patch/WebSocket.spec.ts

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ describe('WebSocket', ifEnvSupports('WebSocket', function () {
2424
});
2525

2626

27+
it('should be patched in a Web Worker', done => {
28+
var worker = new Worker('/base/test/ws-webworker-context.ts');
29+
worker.onmessage = (e:MessageEvent) => {
30+
expect(e.data).toBe('pass');
31+
done();
32+
}
33+
});
34+
35+
2736
it('should work with addEventListener', function (done) {
2837
testZone.run(function() {
2938
socket.addEventListener('message', function (event) {

Diff for: test/ws-webworker-context.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare var zone;
2+
importScripts('/base/test/zone_worker_entry_point.ts');
3+
4+
zone.fork().run(() => {
5+
var websocket = new WebSocket('ws://localhost:8001');
6+
websocket.addEventListener('open', () => {
7+
var outerZone = (<any>self).zone;
8+
websocket.onmessage = () => {
9+
if((<any>self).zone.parent === outerZone) {
10+
(<any>self).postMessage('pass');
11+
} else {
12+
(<any>self).postMessage('fail');
13+
}
14+
};
15+
websocket.send('text');
16+
});
17+
});

Diff for: test/zone_worker_entry_point.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Setup tests for Zone without microtask support
2+
import '../lib/browser/zone';

0 commit comments

Comments
 (0)