@salesforce/pwa-kit-react-sdk 3.8.0-preview.0-basepath → 3.8.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -7
- package/package.json +6 -5
- package/ssr/browser/main.js +130 -0
- package/ssr/browser/main.test.js +54 -0
- package/ssr/server/react-rendering.js +434 -0
- package/ssr/server/react-rendering.test.js +745 -0
- package/ssr/universal/compatibility.js +31 -0
- package/ssr/universal/components/_app/index.js +35 -0
- package/ssr/universal/components/_app/index.test.js +20 -0
- package/ssr/universal/components/_app-config/index.js +87 -0
- package/ssr/universal/components/_app-config/index.test.js +21 -0
- package/ssr/universal/components/_document/index.js +92 -0
- package/ssr/universal/components/_document/index.test.js +58 -0
- package/ssr/universal/components/_error/index.js +55 -0
- package/ssr/universal/components/_error/index.test.js +28 -0
- package/ssr/universal/components/app-error-boundary/index.js +113 -0
- package/ssr/universal/components/app-error-boundary/index.test.js +109 -0
- package/ssr/universal/components/fetch-strategy/index.js +42 -0
- package/ssr/universal/components/refresh/index.js +123 -0
- package/ssr/universal/components/refresh/index.test.js +78 -0
- package/ssr/universal/components/route-component/index.js +415 -0
- package/ssr/universal/components/route-component/index.test.js +378 -0
- package/ssr/universal/components/switch/index.js +62 -0
- package/ssr/universal/components/throw-404/index.js +36 -0
- package/ssr/universal/components/throw-404/index.test.js +26 -0
- package/ssr/universal/components/with-correlation-id/index.js +36 -0
- package/ssr/universal/components/with-legacy-get-props/index.js +100 -0
- package/ssr/universal/components/with-legacy-get-props/index.test.js +35 -0
- package/ssr/universal/components/with-react-query/index.js +130 -0
- package/ssr/universal/components/with-react-query/index.test.js +101 -0
- package/ssr/universal/contexts/index.js +72 -0
- package/ssr/universal/contexts/index.test.js +101 -0
- package/ssr/universal/errors.js +34 -0
- package/ssr/universal/errors.test.js +20 -0
- package/ssr/universal/events.js +38 -0
- package/ssr/universal/events.test.js +39 -0
- package/ssr/universal/hooks/index.js +84 -0
- package/ssr/universal/routes.js +15 -0
- package/ssr/universal/utils.client.test.js +46 -0
- package/ssr/universal/utils.js +61 -0
- package/ssr/universal/utils.server.test.js +24 -0
- package/utils/assets.js +120 -0
- package/utils/assets.test.js +106 -0
- package/utils/logger-instance.js +19 -0
- package/utils/performance.js +126 -0
- package/utils/performance.test.js +50 -0
- package/utils/url.js +41 -0
- package/utils/url.test.js +47 -0
- package/utils/uuidv4.client.js +21 -0
- package/utils/uuidv4.client.test.js +27 -0
- package/utils/warnings.js +81 -0
- package/utils/warnings.test.js +48 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = _interopRequireWildcard(require("./utils"));
|
|
4
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
5
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
6
|
+
/*
|
|
7
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
8
|
+
* All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
10
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
describe('getProxyConfigs (client-side)', () => {
|
|
14
|
+
const configs = [{
|
|
15
|
+
foo: 'bar'
|
|
16
|
+
}];
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
global.Progressive = {
|
|
19
|
+
ssrOptions: {
|
|
20
|
+
proxyConfigs: configs
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
delete global.Progressive;
|
|
26
|
+
});
|
|
27
|
+
test('should return proxy configs set on window.Progressive', () => {
|
|
28
|
+
expect(utils.getProxyConfigs()).toEqual(configs);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe('getAssetUrl (client-side)', () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
global.Progressive = {
|
|
34
|
+
buildOrigin: 'test.com'
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
delete global.Progressive;
|
|
39
|
+
});
|
|
40
|
+
test('should return build origin when path is undefined', () => {
|
|
41
|
+
expect(utils.getAssetUrl()).toBe('test.com');
|
|
42
|
+
});
|
|
43
|
+
test('should return origin + path', () => {
|
|
44
|
+
expect(utils.getAssetUrl('/path')).toBe('test.com/path');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getProxyConfigs = exports.getAssetUrl = void 0;
|
|
7
|
+
var _ssrShared = require("@salesforce/pwa-kit-runtime/utils/ssr-shared");
|
|
8
|
+
var _ssrNamespacePaths = require("@salesforce/pwa-kit-runtime/utils/ssr-namespace-paths");
|
|
9
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
10
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
11
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
12
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
13
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
|
|
14
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
15
|
+
* All rights reserved.
|
|
16
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
17
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
18
|
+
*/ /**
|
|
19
|
+
* @module progressive-web-sdk/ssr/universal/utils
|
|
20
|
+
*/
|
|
21
|
+
const onClient = typeof window !== 'undefined';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the URL that should be used to load an asset from the bundle.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} path - relative path from the build directory to the asset
|
|
27
|
+
* @function
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
const getAssetUrl = path => {
|
|
31
|
+
/* istanbul ignore next */
|
|
32
|
+
const publicPath = onClient ? `${window.Progressive.buildOrigin}` : `${_ssrNamespacePaths.bundleBasePath}/${process.env.BUNDLE_ID || 'development'}/`;
|
|
33
|
+
return path ? `${publicPath}${path}` : publicPath;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {Object} ProxyConfig
|
|
38
|
+
* @property {String} protocol - http or https
|
|
39
|
+
* @property {String} host - the hostname
|
|
40
|
+
* @property {String} path - the path element that follows "mobify/proxy"
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Return the set of proxies configured for the app.
|
|
45
|
+
*
|
|
46
|
+
* The result is an array of objects, each of which has 'protocol'
|
|
47
|
+
* (either 'http' or 'https'), 'host' (the hostname) and 'path' (the
|
|
48
|
+
* path element that follows "/mobify/proxy/", defaulting to 'base' for
|
|
49
|
+
* the first proxy, and 'base2' for the next).
|
|
50
|
+
*
|
|
51
|
+
* @function
|
|
52
|
+
* @returns {Array<ProxyConfig>}
|
|
53
|
+
*/
|
|
54
|
+
exports.getAssetUrl = getAssetUrl;
|
|
55
|
+
const getProxyConfigs = () => {
|
|
56
|
+
const configs = onClient ? (window.Progressive.ssrOptions || {}).proxyConfigs || [] : _ssrShared.proxyConfigs;
|
|
57
|
+
|
|
58
|
+
// Clone to avoid accidental mutation of important configuration variables.
|
|
59
|
+
return configs.map(config => _objectSpread({}, config));
|
|
60
|
+
};
|
|
61
|
+
exports.getProxyConfigs = getProxyConfigs;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = _interopRequireWildcard(require("./utils"));
|
|
4
|
+
var _ssrShared = require("@salesforce/pwa-kit-runtime/utils/ssr-shared");
|
|
5
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
6
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
7
|
+
/**
|
|
8
|
+
* @jest-environment node
|
|
9
|
+
*/
|
|
10
|
+
/*
|
|
11
|
+
* Copyright (c) 2022, Salesforce, Inc.
|
|
12
|
+
* All rights reserved.
|
|
13
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
14
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
15
|
+
*/
|
|
16
|
+
// Jest requires the @jest-environment comment at the start of file, which
|
|
17
|
+
// conflicts with the eslint header rule.
|
|
18
|
+
/* eslint-disable header/header */
|
|
19
|
+
|
|
20
|
+
describe('getProxyConfigs (server-side)', () => {
|
|
21
|
+
test('should return the currently used proxy configs', () => {
|
|
22
|
+
expect(utils.getProxyConfigs()).toEqual(_ssrShared.proxyConfigs);
|
|
23
|
+
});
|
|
24
|
+
});
|
package/utils/assets.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.loadScript = void 0;
|
|
7
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
8
|
+
/*
|
|
9
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
10
|
+
* All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
12
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* loadScriptCounter is used as a key to the window.Mobify object handlers. We
|
|
17
|
+
* Want this outside the loadScript function so that it can be updated every
|
|
18
|
+
* loadScript is called with a new script to be embedded to the head tag.
|
|
19
|
+
* @private
|
|
20
|
+
*/
|
|
21
|
+
let loadScriptCounter = 0;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Writes script tag to the document, head tag
|
|
25
|
+
* @function
|
|
26
|
+
* @param {string} id - The id for script
|
|
27
|
+
* @param {string} src - The path to script
|
|
28
|
+
* @param {boolean} isAsync=true - Writes an asynchronous function
|
|
29
|
+
* @param {boolean} docwrite=false - Writes a string of text to a document
|
|
30
|
+
* @param {function} onload - The onload callback function
|
|
31
|
+
* @param {boolean} onerror - Rejects the function
|
|
32
|
+
* @example
|
|
33
|
+
* import {loadScript} from '@salesforce/pwa-kit-react-sdk/utils/utils'
|
|
34
|
+
*
|
|
35
|
+
* loadScript({
|
|
36
|
+
* id: 'loadScriptTest1',
|
|
37
|
+
* src: 'loadScriptTest1src'
|
|
38
|
+
* })
|
|
39
|
+
*/
|
|
40
|
+
const loadScript = ({
|
|
41
|
+
id,
|
|
42
|
+
src,
|
|
43
|
+
isAsync = true,
|
|
44
|
+
docwrite = false,
|
|
45
|
+
onload,
|
|
46
|
+
onerror
|
|
47
|
+
}) => {
|
|
48
|
+
const hasTriedLoadScript = ({
|
|
49
|
+
id,
|
|
50
|
+
src,
|
|
51
|
+
method
|
|
52
|
+
}) => {
|
|
53
|
+
const idQuery = id ? `[id="${id}"]` : '';
|
|
54
|
+
return document.querySelectorAll(`script${idQuery}` + `[src="${src}"]` + `[data-load-method="${method}"]`).length > 0;
|
|
55
|
+
};
|
|
56
|
+
const loadMethod = docwrite ? 'document.write()' : 'DOM';
|
|
57
|
+
if (hasTriedLoadScript({
|
|
58
|
+
id,
|
|
59
|
+
src,
|
|
60
|
+
method: loadMethod
|
|
61
|
+
})) {
|
|
62
|
+
console.warn(`[mobify.progressive] loadScript() already called for this script. Ignoring call. (method='${loadMethod}' id='${id}' src='${src}')`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (onload && typeof onload !== 'function') {
|
|
66
|
+
throw new Error(`loadScript()'s 'onload' parameter must be a function but was passed a ${typeof onload}!`);
|
|
67
|
+
}
|
|
68
|
+
if (onerror && typeof onerror !== 'function') {
|
|
69
|
+
throw new Error(`loadScript()'s 'onerror' parameter must be a function but was passed a ${typeof onerror}!`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// TODO: Check for navigator.connection. Need Android for this.
|
|
73
|
+
/* istanbul ignore next */
|
|
74
|
+
if (docwrite && document.readyState === 'loading') {
|
|
75
|
+
window.Mobify = window.Mobify || {};
|
|
76
|
+
let onLoadString = '';
|
|
77
|
+
let onErrorString = '';
|
|
78
|
+
if (typeof onload === 'function') {
|
|
79
|
+
window.Mobify.scriptOnLoads = _extends({}, window.Mobify.scriptOnLoads, {
|
|
80
|
+
[loadScriptCounter]: onload
|
|
81
|
+
});
|
|
82
|
+
// Space prefix is important for valid rendered HTML
|
|
83
|
+
onLoadString = ` onload="window.Mobify.scriptOnLoads['${loadScriptCounter}'] && window.Mobify.scriptOnLoads['${loadScriptCounter}']()"`;
|
|
84
|
+
}
|
|
85
|
+
if (typeof onerror === 'function') {
|
|
86
|
+
window.Mobify.scriptOnErrors = _extends({}, window.Mobify.scriptOnErrors, {
|
|
87
|
+
[loadScriptCounter]: onerror
|
|
88
|
+
});
|
|
89
|
+
// Space prefix is important for valid rendered HTML
|
|
90
|
+
onErrorString = ` onerror="window.Mobify.scriptOnErrors['${loadScriptCounter}'] && window.Mobify.scriptOnErrors['${loadScriptCounter}']()"`;
|
|
91
|
+
}
|
|
92
|
+
document.write(`<script id='${id}' src='${src}' data-load-method='${loadMethod}' charset='utf-8'${onLoadString}${onErrorString}></script>`);
|
|
93
|
+
loadScriptCounter++;
|
|
94
|
+
} else {
|
|
95
|
+
const script = document.createElement('script');
|
|
96
|
+
|
|
97
|
+
// Setting UTF-8 as our encoding ensures that certain strings (i.e.
|
|
98
|
+
// Japanese text) are not improperly converted to something else. We
|
|
99
|
+
// do this on the vendor scripts also just in case any libs we
|
|
100
|
+
// import have localized strings in them.
|
|
101
|
+
script.charset = 'utf-8';
|
|
102
|
+
script.async = isAsync;
|
|
103
|
+
if (id) {
|
|
104
|
+
script.id = id;
|
|
105
|
+
}
|
|
106
|
+
script.src = src;
|
|
107
|
+
script.dataset.loadMethod = loadMethod;
|
|
108
|
+
|
|
109
|
+
/* istanbul ignore next */
|
|
110
|
+
if (typeof onload === 'function') {
|
|
111
|
+
script.onload = onload;
|
|
112
|
+
}
|
|
113
|
+
/* istanbul ignore next */
|
|
114
|
+
if (typeof onerror === 'function') {
|
|
115
|
+
script.onerror = onerror;
|
|
116
|
+
}
|
|
117
|
+
document.getElementsByTagName('head')[0].appendChild(script);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
exports.loadScript = loadScript;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _assets = require("./assets");
|
|
4
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
5
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
/*
|
|
7
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
8
|
+
* All rights reserved.
|
|
9
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
10
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const sandbox = _sinon.default.createSandbox();
|
|
14
|
+
|
|
15
|
+
// Silence the error messages, they're on purpose here
|
|
16
|
+
let consoleError;
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
consoleError = console.error;
|
|
19
|
+
console.error = jest.fn();
|
|
20
|
+
});
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
console.error = consoleError;
|
|
23
|
+
sandbox.restore();
|
|
24
|
+
});
|
|
25
|
+
describe('loadScript', () => {
|
|
26
|
+
let fakeScriptElement;
|
|
27
|
+
const headElement = document.getElementsByTagName('head')[0];
|
|
28
|
+
const originalReadyState = document.readyState;
|
|
29
|
+
beforeEach(() => {
|
|
30
|
+
fakeScriptElement = {
|
|
31
|
+
id: null,
|
|
32
|
+
src: null,
|
|
33
|
+
async: null,
|
|
34
|
+
charset: null,
|
|
35
|
+
onload: null,
|
|
36
|
+
onerror: null,
|
|
37
|
+
dataset: {}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Mock out createElement and body.appendChild so that we don't have
|
|
41
|
+
// to fetch an actual script
|
|
42
|
+
sandbox.stub(document, 'createElement').returns(fakeScriptElement);
|
|
43
|
+
sandbox.stub(headElement, 'appendChild');
|
|
44
|
+
sandbox.stub(document, 'write');
|
|
45
|
+
Object.defineProperty(document, 'readyState', {
|
|
46
|
+
value: 'loading',
|
|
47
|
+
writable: true
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// If you need to actually see the logging from these modules,
|
|
51
|
+
// change these `.stub()` calls to `.spy()`. Tests won't be affected.
|
|
52
|
+
sandbox.stub(console, 'log');
|
|
53
|
+
sandbox.stub(console, 'warn');
|
|
54
|
+
});
|
|
55
|
+
afterAll(() => {
|
|
56
|
+
sandbox.restore();
|
|
57
|
+
document.readyState = originalReadyState;
|
|
58
|
+
});
|
|
59
|
+
test('loadScript defaults to using the DOM to load the script', () => {
|
|
60
|
+
(0, _assets.loadScript)({
|
|
61
|
+
id: 'loadScriptTest1',
|
|
62
|
+
src: 'loadScriptTest1src'
|
|
63
|
+
});
|
|
64
|
+
expect(document.createElement.called).toBe(true);
|
|
65
|
+
expect(headElement.appendChild.called).toBe(true);
|
|
66
|
+
const element = headElement.appendChild.getCall(0).args[0];
|
|
67
|
+
expect(element.id).toBe('loadScriptTest1');
|
|
68
|
+
expect(element.src).toBe('loadScriptTest1src');
|
|
69
|
+
});
|
|
70
|
+
test('loadScript uses document.write when the flag is enabled', () => {
|
|
71
|
+
(0, _assets.loadScript)({
|
|
72
|
+
id: 'loadScriptTest1',
|
|
73
|
+
src: 'loadScriptTest1src',
|
|
74
|
+
docwrite: true
|
|
75
|
+
});
|
|
76
|
+
expect(document.write.called).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
test('loadScript aborts if it finds the requested script has already been attempted', () => {
|
|
79
|
+
sandbox.stub(document, 'querySelectorAll').returns([1]);
|
|
80
|
+
(0, _assets.loadScript)({
|
|
81
|
+
id: 'loadScriptTest1',
|
|
82
|
+
src: 'loadScriptTest1src'
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Shouldn't have tried either method of inserting the script
|
|
86
|
+
expect(document.createElement.called).toBe(false);
|
|
87
|
+
expect(headElement.appendChild.called).toBe(false);
|
|
88
|
+
expect(document.write.called).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
test('loadScript throws if `onload` is provided but is not a function', () => {
|
|
91
|
+
expect(() => {
|
|
92
|
+
(0, _assets.loadScript)({
|
|
93
|
+
src: 'loadScriptTest2src',
|
|
94
|
+
onload: 'onload expects this to be a function'
|
|
95
|
+
});
|
|
96
|
+
}).toThrow();
|
|
97
|
+
});
|
|
98
|
+
test('loadScript throws if `onerror` is provided but is not a function', () => {
|
|
99
|
+
expect(() => {
|
|
100
|
+
(0, _assets.loadScript)({
|
|
101
|
+
src: 'loadScriptTest2src',
|
|
102
|
+
onerror: 'onerror expects this to be a function'
|
|
103
|
+
});
|
|
104
|
+
}).toThrow();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _loggerFactory = _interopRequireDefault(require("@salesforce/pwa-kit-runtime/utils/logger-factory"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
/*
|
|
10
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
11
|
+
* All rights reserved.
|
|
12
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const logger = Object.freeze((0, _loggerFactory.default)({
|
|
17
|
+
packageName: 'pwa-kit-react-sdk'
|
|
18
|
+
}));
|
|
19
|
+
var _default = exports.default = logger;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.PERFORMANCE_MARKS = void 0;
|
|
7
|
+
var _loggerInstance = _interopRequireDefault(require("./logger-instance"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
/*
|
|
10
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
11
|
+
* All rights reserved.
|
|
12
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
13
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const PERFORMANCE_MARKS = exports.PERFORMANCE_MARKS = {
|
|
17
|
+
total: 'ssr:total',
|
|
18
|
+
renderToString: 'ssr:render-to-string',
|
|
19
|
+
routeMatching: 'ssr:route-matching',
|
|
20
|
+
loadComponent: 'ssr:load-component',
|
|
21
|
+
fetchStrategies: 'ssr:fetch-strategies',
|
|
22
|
+
reactQueryPrerender: 'ssr:fetch-strategies:react-query:pre-render',
|
|
23
|
+
reactQueryUseQuery: 'ssr:fetch-strategies:react-query:use-query',
|
|
24
|
+
getProps: 'ssr:fetch-strategies:get-prop'
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* This is an SDK internal class that is responsible for measuring server side performance.
|
|
29
|
+
*
|
|
30
|
+
* This class manages two types of performance marks: start and end.
|
|
31
|
+
*
|
|
32
|
+
* By default, this timer is disabled. Only certain environment variables and feature flags turns it on.
|
|
33
|
+
*
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
class PerformanceTimer {
|
|
37
|
+
MARKER_TYPES = {
|
|
38
|
+
START: 'start',
|
|
39
|
+
END: 'end'
|
|
40
|
+
};
|
|
41
|
+
constructor(options = {}) {
|
|
42
|
+
this.enabled = options.enabled || false;
|
|
43
|
+
this.marks = {
|
|
44
|
+
start: new Map(),
|
|
45
|
+
end: new Map()
|
|
46
|
+
};
|
|
47
|
+
this.metrics = [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* This is a utility function to build the Server-Timing header.
|
|
52
|
+
* The function receives an array of performance metrics and returns a string that represents the Server-Timing header.
|
|
53
|
+
*
|
|
54
|
+
* see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing
|
|
55
|
+
*
|
|
56
|
+
* @function
|
|
57
|
+
* @private
|
|
58
|
+
*
|
|
59
|
+
* @return {String}
|
|
60
|
+
*/
|
|
61
|
+
buildServerTimingHeader() {
|
|
62
|
+
const header = this.metrics.map(metric => {
|
|
63
|
+
return `${metric.name};dur=${metric.duration}`;
|
|
64
|
+
}).join(', ');
|
|
65
|
+
return header;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* A utility function to format and log the performance metrics.
|
|
70
|
+
*
|
|
71
|
+
* @function
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
log() {
|
|
75
|
+
this.metrics.forEach(metric => {
|
|
76
|
+
_loggerInstance.default.info(`${metric.name} - ${metric.duration}ms ${metric.detail || ''}`, {
|
|
77
|
+
namespace: 'performance'
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* This is a utility function to create performance marks.
|
|
84
|
+
* The data will be used in console logs and the http response header `server-timing`.
|
|
85
|
+
*
|
|
86
|
+
* @function
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
mark(name, type, options = {}) {
|
|
90
|
+
if (!this.enabled) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!name) {
|
|
94
|
+
_loggerInstance.default.warn('Performance mark cannot be created because the name is undefined.', {
|
|
95
|
+
namespace: 'performance'
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (type !== this.MARKER_TYPES.START && type !== this.MARKER_TYPES.END) {
|
|
100
|
+
_loggerInstance.default.warn('Performance mark cannot be created because the type must be either "start" or "end".', {
|
|
101
|
+
namespace: 'performance'
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const timestamp = performance.now();
|
|
106
|
+
const isEnd = type === this.MARKER_TYPES.END;
|
|
107
|
+
const storage = isEnd ? this.marks.end : this.marks.start;
|
|
108
|
+
storage.set(name, {
|
|
109
|
+
name,
|
|
110
|
+
timestamp,
|
|
111
|
+
detail: options.detail
|
|
112
|
+
});
|
|
113
|
+
if (isEnd) {
|
|
114
|
+
const startMark = this.marks.start.get(name);
|
|
115
|
+
if (startMark) {
|
|
116
|
+
const measurement = {
|
|
117
|
+
name,
|
|
118
|
+
duration: (timestamp - startMark.timestamp).toFixed(2),
|
|
119
|
+
detail: options.detail
|
|
120
|
+
};
|
|
121
|
+
this.metrics.push(measurement);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
exports.default = PerformanceTimer;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _performance = _interopRequireDefault(require("./performance"));
|
|
4
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
5
|
+
/**
|
|
6
|
+
* @jest-environment node
|
|
7
|
+
*/
|
|
8
|
+
/*
|
|
9
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
10
|
+
* All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
12
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
+
*/
|
|
14
|
+
// The @jest-environment comment block *MUST* be the first line of the file for the tests to pass.
|
|
15
|
+
// That conflicts with the monorepo header rule, so we must disable the rule!
|
|
16
|
+
/* eslint-disable header/header */
|
|
17
|
+
|
|
18
|
+
describe('PerformanceTimer', () => {
|
|
19
|
+
test('is disabled by default', () => {
|
|
20
|
+
const timer = new _performance.default();
|
|
21
|
+
timer.mark('test', 'start');
|
|
22
|
+
expect(timer.marks.start.size).toBe(0);
|
|
23
|
+
});
|
|
24
|
+
test('can be enabled', () => {
|
|
25
|
+
const timer = new _performance.default({
|
|
26
|
+
enabled: true
|
|
27
|
+
});
|
|
28
|
+
timer.mark('test', 'start');
|
|
29
|
+
expect(timer.marks.start.size).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
test('marks can be added for both types', () => {
|
|
32
|
+
const timer = new _performance.default({
|
|
33
|
+
enabled: true
|
|
34
|
+
});
|
|
35
|
+
timer.mark('test', 'start');
|
|
36
|
+
timer.mark('test', 'end');
|
|
37
|
+
expect(timer.marks.start.size).toBe(1);
|
|
38
|
+
expect(timer.marks.end.size).toBe(1);
|
|
39
|
+
});
|
|
40
|
+
test('measurements are created when a pair of marks is added', () => {
|
|
41
|
+
const timer = new _performance.default({
|
|
42
|
+
enabled: true
|
|
43
|
+
});
|
|
44
|
+
timer.mark('test', 'start');
|
|
45
|
+
timer.mark('test', 'end');
|
|
46
|
+
expect(timer.metrics).toHaveLength(1);
|
|
47
|
+
expect(timer.metrics[0].name).toBe('test');
|
|
48
|
+
expect(parseFloat(timer.metrics[0].duration)).toBeGreaterThan(0);
|
|
49
|
+
});
|
|
50
|
+
});
|
package/utils/url.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getAppOrigin = void 0;
|
|
7
|
+
/*
|
|
8
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
9
|
+
* All rights reserved.
|
|
10
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
11
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns the application's origin.
|
|
16
|
+
*
|
|
17
|
+
* NOTE: This utility can only be used server-side after your application has been
|
|
18
|
+
* initialized using the `_createApp` method (This happens in your /app/ssr.js file).
|
|
19
|
+
*
|
|
20
|
+
* @function
|
|
21
|
+
* @deprecated use `useOrigin()` instead.
|
|
22
|
+
* This function will be removed in version 4.0.0.
|
|
23
|
+
* @returns {string} Returns the ORIGIN under which we are serving the page.
|
|
24
|
+
* @example
|
|
25
|
+
* import {getAppOrigin} from '@salesforce/pwa-kit-react-sdk/utils/url'
|
|
26
|
+
*
|
|
27
|
+
* const url = `${getAppOrigin()}/path`
|
|
28
|
+
*/
|
|
29
|
+
const getAppOrigin = () => {
|
|
30
|
+
if (typeof window !== 'undefined') {
|
|
31
|
+
return window.location.origin;
|
|
32
|
+
}
|
|
33
|
+
const {
|
|
34
|
+
APP_ORIGIN
|
|
35
|
+
} = process.env;
|
|
36
|
+
if (!APP_ORIGIN) {
|
|
37
|
+
throw new Error(`Application is not initialized. Please ensure '_createApp' has been invoked before using this method.`);
|
|
38
|
+
}
|
|
39
|
+
return process.env.APP_ORIGIN;
|
|
40
|
+
};
|
|
41
|
+
exports.getAppOrigin = getAppOrigin;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _url = require("./url");
|
|
4
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
5
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
6
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
7
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
8
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
|
|
9
|
+
* Copyright (c) 2021, salesforce.com, inc.
|
|
10
|
+
* All rights reserved.
|
|
11
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
12
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
13
|
+
*/
|
|
14
|
+
describe('getAppOrigin', () => {
|
|
15
|
+
const OLD_ENV = process.env;
|
|
16
|
+
const OLD_WINDOW = global.window;
|
|
17
|
+
const TEST_ORIGIN = 'https://www.example.com';
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.resetModules();
|
|
20
|
+
process.env = _objectSpread({}, OLD_ENV);
|
|
21
|
+
});
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
process.env = OLD_ENV;
|
|
24
|
+
global.window = OLD_WINDOW;
|
|
25
|
+
});
|
|
26
|
+
test('returns `process.env.APP_ORIGIN` when on server', () => {
|
|
27
|
+
// Simulate being on the server by deleting the window.
|
|
28
|
+
delete global.window;
|
|
29
|
+
|
|
30
|
+
// Simulate starting the app server by simply setting the `APP_ORIGIN`
|
|
31
|
+
process.env.APP_ORIGIN = TEST_ORIGIN;
|
|
32
|
+
expect((0, _url.getAppOrigin)()).toBe(TEST_ORIGIN);
|
|
33
|
+
});
|
|
34
|
+
test('returns `window.location.origin` when on client', () => {
|
|
35
|
+
expect((0, _url.getAppOrigin)()).toBe('http://localhost');
|
|
36
|
+
});
|
|
37
|
+
test('throws error when APP_ORIGIN is not defined on server.', () => {
|
|
38
|
+
// Simulate being on the server by deleting the window.
|
|
39
|
+
delete global.window;
|
|
40
|
+
|
|
41
|
+
// Simulate app server not being initialized.
|
|
42
|
+
process.env.APP_ORIGIN = undefined;
|
|
43
|
+
expect(() => {
|
|
44
|
+
(0, _url.getAppOrigin)();
|
|
45
|
+
}).toThrow();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.uuidv4 = uuidv4;
|
|
7
|
+
/*
|
|
8
|
+
* Copyright (c) 2022, salesforce.com, inc.
|
|
9
|
+
* All rights reserved.
|
|
10
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
11
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Simple implementation to create a uuid using crypto
|
|
16
|
+
* See: https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
|
|
17
|
+
* @returns {*}
|
|
18
|
+
*/
|
|
19
|
+
function uuidv4() {
|
|
20
|
+
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16));
|
|
21
|
+
}
|