Skip to content

Commit 096375d

Browse files
feat: support web worker
1 parent 1bb6936 commit 096375d

14 files changed

+100
-34
lines changed

src/amplitude-client.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import getHost from './get-host';
1919
import baseCookie from './base-cookie';
2020
import { AmplitudeServerZone, getEventLogApi } from './server-zone';
2121
import ConfigManager from './config-manager';
22+
import GlobalScope from './global-scope';
2223

2324
/**
2425
* AmplitudeClient SDK API - instance constructor.
@@ -80,7 +81,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
8081

8182
try {
8283
_parseConfig(this.options, opt_config);
83-
if (isBrowserEnv() && window.Prototype !== undefined && Array.prototype.toJSON) {
84+
if (isBrowserEnv() && GlobalScope.Prototype !== undefined && Array.prototype.toJSON) {
8485
prototypeJsFix();
8586
utils.log.warn(
8687
'Prototype.js injected Array.prototype.toJSON. Deleting Array.prototype.toJSON to prevent double-stringify',
@@ -243,7 +244,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
243244
// Monitoring just page exits because that is the most requested feature for now
244245
// "If you're specifically trying to detect page unload events, the pagehide event is the best option."
245246
// https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
246-
window.addEventListener(
247+
GlobalScope.addEventListener(
247248
'pagehide',
248249
() => {
249250
handleVisibilityChange();
@@ -254,7 +255,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
254255
}
255256
} catch (err) {
256257
utils.log.error(err);
257-
if (type(opt_config.onError) === 'function') {
258+
if (opt_config && type(opt_config.onError) === 'function') {
258259
opt_config.onError(err);
259260
}
260261
}
@@ -751,14 +752,14 @@ var _sendParamsReferrerUserProperties = function _sendParamsReferrerUserProperti
751752
* @private
752753
*/
753754
AmplitudeClient.prototype._getReferrer = function _getReferrer() {
754-
return document.referrer;
755+
return typeof document !== 'undefined' ? document.referrer : '';
755756
};
756757

757758
/**
758759
* @private
759760
*/
760761
AmplitudeClient.prototype._getUrlParams = function _getUrlParams() {
761-
return location.search;
762+
return GlobalScope.location.search;
762763
};
763764

764765
/**
@@ -1779,7 +1780,7 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() {
17791780
}
17801781
this._sending = true;
17811782
}
1782-
var protocol = this.options.forceHttps ? 'https' : 'https:' === window.location.protocol ? 'https' : 'http';
1783+
var protocol = this.options.forceHttps ? 'https' : 'https:' === GlobalScope.location.protocol ? 'https' : 'http';
17831784
var url = protocol + '://' + this.options.apiEndpoint;
17841785

17851786
// fetch events to send

src/base-cookie.js

+3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ const sortByEventTime = (cookies) => {
9595
// test that cookies are enabled - navigator.cookiesEnabled yields false positives in IE, need to test directly
9696
const areCookiesEnabled = (opts = {}) => {
9797
const cookieName = Constants.COOKIE_TEST_PREFIX + base64Id();
98+
if (typeof document === 'undefined') {
99+
return false;
100+
}
98101
let _areCookiesEnabled = false;
99102
try {
100103
const uid = String(new Date());

src/base64.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import UTF8 from './utf8';
2+
import GlobalScope from './global-scope';
23

34
/*
45
* Base64 encoder/decoder
@@ -9,8 +10,8 @@ var Base64 = {
910

1011
encode: function (input) {
1112
try {
12-
if (window.btoa && window.atob) {
13-
return window.btoa(unescape(encodeURIComponent(input)));
13+
if (GlobalScope.btoa && GlobalScope.atob) {
14+
return GlobalScope.btoa(unescape(encodeURIComponent(input)));
1415
}
1516
} catch (e) {
1617
//log(e);
@@ -53,8 +54,8 @@ var Base64 = {
5354

5455
decode: function (input) {
5556
try {
56-
if (window.btoa && window.atob) {
57-
return decodeURIComponent(escape(window.atob(input)));
57+
if (GlobalScope.btoa && GlobalScope.atob) {
58+
return decodeURIComponent(escape(GlobalScope.atob(input)));
5859
}
5960
} catch (e) {
6061
//log(e);

src/config-manager.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Constants from './constants';
22
import { getDynamicConfigApi } from './server-zone';
3+
import GlobalScope from './global-scope';
34
/**
45
* Dynamic Configuration
56
* Find the best server url automatically based on app users' geo location.
@@ -15,14 +16,14 @@ class ConfigManager {
1516

1617
refresh(serverZone, forceHttps, callback) {
1718
let protocol = 'https';
18-
if (!forceHttps && 'https:' !== window.location.protocol) {
19+
if (!forceHttps && 'https:' !== GlobalScope.location.protocol) {
1920
protocol = 'http';
2021
}
2122
const dynamicConfigUrl = protocol + '://' + getDynamicConfigApi(serverZone);
2223
const self = this;
23-
const isIE = window.XDomainRequest ? true : false;
24+
const isIE = GlobalScope.XDomainRequest ? true : false;
2425
if (isIE) {
25-
const xdr = new window.XDomainRequest();
26+
const xdr = new GlobalScope.XDomainRequest();
2627
xdr.open('GET', dynamicConfigUrl, true);
2728
xdr.onload = function () {
2829
const response = JSON.parse(xdr.responseText);

src/cookiestorage.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import Cookie from './cookie';
77
import localStorage from './localstorage';
88
import baseCookie from './base-cookie';
9+
import GlobalScope from './global-scope';
910

1011
var cookieStorage = function () {
1112
this.storage = null;
@@ -43,7 +44,7 @@ cookieStorage.prototype.getStorage = function () {
4344
this._options.expirationDays = opts.expirationDays || this._options.expirationDays;
4445
// localStorage is specific to subdomains
4546
this._options.domain =
46-
opts.domain || this._options.domain || (window && window.location && window.location.hostname);
47+
opts.domain || this._options.domain || (GlobalScope && GlobalScope.location && GlobalScope.location.hostname);
4748
return (this._options.secure = opts.secure || false);
4849
},
4950
get: function (name) {

src/get-host.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
import GlobalScope from './global-scope';
2+
13
const getHost = (url) => {
2-
const a = document.createElement('a');
3-
a.href = url;
4-
return a.hostname || location.hostname;
4+
if (url) {
5+
if (typeof document !== 'undefined') {
6+
const a = document.createElement('a');
7+
a.href = url;
8+
return a.hostname || GlobalScope.location.hostname;
9+
}
10+
if (typeof URL === 'function') {
11+
const u = new URL(url);
12+
return u.hostname || GlobalScope.location.hostname;
13+
}
14+
}
15+
return GlobalScope.location.hostname;
516
};
617

718
export default getHost;

src/get-location.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import GlobalScope from './global-scope';
2+
13
const getLocation = () => {
2-
return window.location;
4+
return GlobalScope.location;
35
};
46

57
export default getLocation;

src/global-scope.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const GlobalScope = typeof window !== 'undefined' ? window : self;
2+
export default GlobalScope;

src/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// Entry point
22
import Amplitude from './amplitude';
3+
import GlobalScope from './global-scope';
34

4-
const old = (typeof window !== 'undefined' && window.amplitude) || {};
5+
const old = (typeof GlobalScope !== 'undefined' && GlobalScope.amplitude) || {};
56
const newInstance = new Amplitude();
67
newInstance._q = old._q || [];
78

src/localstorage.js

+13-7
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
* Implement localStorage to support Firefox 2-3 and IE 5-7
33
*/
44

5+
import GlobalScope from './global-scope';
6+
import WorkerStorage from './worker-storage';
7+
58
var localStorage;
69

710
if (!BUILD_COMPAT_LOCAL_STORAGE) {
8-
localStorage = window.localStorage;
11+
localStorage = GlobalScope.localStorage;
912
}
1013

1114
if (BUILD_COMPAT_LOCAL_STORAGE) {
@@ -14,9 +17,9 @@ if (BUILD_COMPAT_LOCAL_STORAGE) {
1417
var uid = new Date();
1518
var result;
1619
try {
17-
window.localStorage.setItem(uid, uid);
18-
result = window.localStorage.getItem(uid) === String(uid);
19-
window.localStorage.removeItem(uid);
20+
GlobalScope.localStorage.setItem(uid, uid);
21+
result = GlobalScope.localStorage.getItem(uid) === String(uid);
22+
GlobalScope.localStorage.removeItem(uid);
2023
return result;
2124
} catch (e) {
2225
// localStorage not available
@@ -25,12 +28,12 @@ if (BUILD_COMPAT_LOCAL_STORAGE) {
2528
};
2629

2730
if (windowLocalStorageAvailable()) {
28-
localStorage = window.localStorage;
29-
} else if (typeof window !== 'undefined' && window.globalStorage) {
31+
localStorage = GlobalScope.localStorage;
32+
} else if (typeof GlobalScope !== 'undefined' && GlobalScope.globalStorage) {
3033
// Firefox 2-3 use globalStorage
3134
// See https://developer.mozilla.org/en/dom/storage#globalStorage
3235
try {
33-
localStorage = window.globalStorage[window.location.hostname];
36+
localStorage = GlobalScope.globalStorage[GlobalScope.location.hostname];
3437
} catch (e) {
3538
// Something bad happened...
3639
}
@@ -85,6 +88,9 @@ if (BUILD_COMPAT_LOCAL_STORAGE) {
8588
} else {
8689
/* Nothing we can do ... */
8790
}
91+
} else if (typeof WorkerGlobalScope !== 'undefined') {
92+
// Web worker
93+
localStorage = new WorkerStorage();
8894
}
8995
if (!localStorage) {
9096
/* eslint-disable no-unused-vars */

src/metadata-storage.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import getLocation from './get-location';
1010
import ampLocalStorage from './localstorage';
1111
import topDomain from './top-domain';
1212
import utils from './utils';
13+
import GlobalScope from './global-scope';
1314

1415
const storageOptionExists = {
1516
[Constants.STORAGE_COOKIES]: true,
@@ -88,8 +89,8 @@ class MetadataStorage {
8889

8990
switch (this.storage) {
9091
case Constants.STORAGE_SESSION:
91-
if (window.sessionStorage) {
92-
window.sessionStorage.setItem(this.storageKey, value);
92+
if (GlobalScope.sessionStorage) {
93+
GlobalScope.sessionStorage.setItem(this.storageKey, value);
9394
}
9495
break;
9596
case Constants.STORAGE_LOCAL:
@@ -131,7 +132,7 @@ class MetadataStorage {
131132
}
132133
if (!str) {
133134
try {
134-
str = window.sessionStorage && window.sessionStorage.getItem(this.storageKey);
135+
str = GlobalScope.sessionStorage && GlobalScope.sessionStorage.getItem(this.storageKey);
135136
} catch (e) {
136137
utils.log.info(`window.sessionStorage unavailable. Reason: "${e}"`);
137138
}
@@ -187,8 +188,8 @@ class MetadataStorage {
187188
}
188189
if (!str) {
189190
try {
190-
str = window.sessionStorage && window.sessionStorage.getItem(this.storageKey);
191-
window.sessionStorage.clear();
191+
str = GlobalScope.sessionStorage && GlobalScope.sessionStorage.getItem(this.storageKey);
192+
GlobalScope.sessionStorage.clear();
192193
} catch (e) {
193194
utils.log.info(`window.sessionStorage unavailable. Reason: "${e}"`);
194195
}

src/utils.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import constants from './constants';
2+
import GlobalScope from './global-scope';
23
import type from './type';
34

45
var logLevels = {
@@ -54,7 +55,7 @@ var isEmptyString = function isEmptyString(str) {
5455

5556
var sessionStorageEnabled = function sessionStorageEnabled() {
5657
try {
57-
if (window.sessionStorage) {
58+
if (GlobalScope.sessionStorage) {
5859
return true;
5960
}
6061
} catch (e) {

src/worker-storage.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export default class WorkerStorage {
2+
constructor() {
3+
this.map = new Map();
4+
this.length = 0;
5+
}
6+
7+
key(index) {
8+
const keys = Array.from(this.map.keys());
9+
const key = keys[index];
10+
return this.map.get(key);
11+
}
12+
13+
getItem(key) {
14+
return this.map.get(key);
15+
}
16+
17+
setItem(key, value) {
18+
if (!this.map.has(key)) {
19+
this.length += 1;
20+
}
21+
this.map.set(key, value);
22+
}
23+
24+
removeItem(key) {
25+
if (this.map.has(key)) {
26+
this.length -= 1;
27+
this.map.delete(key);
28+
}
29+
}
30+
31+
clear() {
32+
this.map.clear();
33+
}
34+
}

src/xhr.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import queryString from 'query-string';
2+
import GlobalScope from './global-scope';
23

34
/*
45
* Simple AJAX request object
@@ -16,9 +17,9 @@ function setHeaders(xhr, headers) {
1617
}
1718

1819
Request.prototype.send = function (callback) {
19-
var isIE = window.XDomainRequest ? true : false;
20+
var isIE = GlobalScope.XDomainRequest ? true : false;
2021
if (isIE) {
21-
var xdr = new window.XDomainRequest();
22+
var xdr = new GlobalScope.XDomainRequest();
2223
xdr.open('POST', this.url, true);
2324
xdr.onload = function () {
2425
callback(200, xdr.responseText);

0 commit comments

Comments
 (0)