@salesforce/pwa-kit-react-sdk 4.0.0-extensibility-preview.3 → 4.0.0-extensibility-preview.4
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 +22 -1
- package/package.json +10 -10
- package/ssr/browser/main.d.ts.map +1 -1
- package/ssr/browser/main.js +7 -3
- package/ssr/browser/main.test.js +8 -8
- package/ssr/server/react-rendering.d.ts.map +1 -1
- package/ssr/server/react-rendering.js +21 -4
- package/ssr/universal/components/redirect-with-status/index.js +2 -2
- package/ssr/universal/components/route-component/index.d.ts +1 -1
- package/ssr/universal/components/route-component/index.d.ts.map +1 -1
- package/ssr/universal/components/route-component/index.js +41 -39
- package/ssr/universal/components/route-component/index.test.js +4 -4
- package/ssr/universal/components/switch/index.d.ts.map +1 -1
- package/ssr/universal/components/switch/index.js +28 -11
- package/ssr/universal/components/with-legacy-get-props/index.js +2 -2
- package/ssr/universal/components/with-react-query/index.js +3 -3
- package/ssr/universal/components/with-react-query/index.test.js +108 -2
- package/ssr/universal/contexts/index.d.ts +18 -0
- package/ssr/universal/contexts/index.d.ts.map +1 -1
- package/ssr/universal/contexts/index.js +25 -1
- package/ssr/universal/contexts/index.test.js +26 -0
- package/ssr/universal/errors.d.ts +6 -10
- package/ssr/universal/errors.d.ts.map +1 -1
- package/ssr/universal/errors.js +0 -5
- package/ssr/universal/events.d.ts +1 -1
- package/ssr/universal/events.d.ts.map +1 -1
- package/ssr/universal/events.js +7 -6
- package/ssr/universal/events.test.js +4 -4
- package/ssr/universal/hooks/index.d.ts +1 -0
- package/ssr/universal/hooks/index.d.ts.map +1 -1
- package/ssr/universal/hooks/index.js +16 -2
- package/ssr/universal/utils.d.ts +1 -1
- package/ssr/universal/utils.d.ts.map +1 -1
- package/ssr/universal/utils.js +8 -7
- package/utils/performance.js +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,34 @@
|
|
|
1
|
+
## v4.0.0-extensibility-preview.4 (Feb 12, 2025)
|
|
2
|
+
- Replace `event-emitter` in favor of the native `EventTarget` [#2289](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2289)
|
|
3
|
+
- Call app extension's new methods `getRoutes` and `getRoutesAsync` [#2308](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2308)
|
|
4
|
+
- Call app extension's `beforeRouteMatch` method with updated parameters [#2308](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2308)
|
|
5
|
+
- Enhanced SSR rendering by serializing application extension async routes [#2300](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2300)
|
|
6
|
+
|
|
1
7
|
## v4.0.0-extensibility-preview.3 (Dec 13, 2024)
|
|
8
|
+
|
|
2
9
|
## v4.0.0-extensibility-preview.2 (Dec 09, 2024)
|
|
10
|
+
|
|
3
11
|
## v4.0.0-extensibility-preview.1 (Dec 09, 2024)
|
|
12
|
+
|
|
4
13
|
## v4.0.0-extensibility-preview.0 (Nov 28, 2024)
|
|
5
14
|
- Integrate Application Extensions Project. (#2099)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2099]
|
|
6
15
|
- Add new `getStaticAssetUrl` utility to access assets specifically in the `/static` folder. (#2040)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2040]
|
|
7
16
|
- Update Application Extensions import in `react-rendering.js` and `main.js` (#2004)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2004]
|
|
8
17
|
- Define interface of the app extension's config [#2010](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2010)
|
|
9
|
-
|
|
18
|
+
|
|
19
|
+
## v3.10.0 (Feb 18, 2025)
|
|
20
|
+
- Fix the performance logging util to use the correct delimiter for the server-timing header. [#2225](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2295)
|
|
21
|
+
|
|
22
|
+
## v3.9.2 (Mar 07, 2025)
|
|
23
|
+
- Update PWA-Kit SDKs to v3.9.2 [#2304](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2304)
|
|
24
|
+
|
|
25
|
+
## v3.9.1 (Mar 05, 2025)
|
|
26
|
+
- Update PWA-Kit SDKs to v3.9.1 [#2301](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2301)
|
|
27
|
+
|
|
28
|
+
## v3.9.0 (Feb 18, 2025)
|
|
29
|
+
- Fix the performance logging util to not round duration. [#2199](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2199)
|
|
10
30
|
- Add RedirectWithStatus component, allowing finer grained control of rediriects and their status code [#2173](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2173)
|
|
31
|
+
- Support Node 22 [#2218](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2218)
|
|
11
32
|
|
|
12
33
|
## v3.8.0 (Oct 28, 2024)
|
|
13
34
|
- [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/pwa-kit-react-sdk",
|
|
3
|
-
"version": "4.0.0-extensibility-preview.
|
|
3
|
+
"version": "4.0.0-extensibility-preview.4",
|
|
4
4
|
"description": "A library that supports the isomorphic React rendering pipeline for Commerce Cloud Managed Runtime apps",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-react-sdk#readme",
|
|
@@ -38,11 +38,9 @@
|
|
|
38
38
|
"@loadable/babel-plugin": "^5.15.3",
|
|
39
39
|
"@loadable/server": "^5.15.3",
|
|
40
40
|
"@loadable/webpack-plugin": "^5.15.2",
|
|
41
|
-
"@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.
|
|
42
|
-
"@salesforce/pwa-kit-runtime": "4.0.0-extensibility-preview.
|
|
43
|
-
"@tanstack/react-query": "^4.28.0",
|
|
41
|
+
"@salesforce/pwa-kit-extension-sdk": "4.0.0-extensibility-preview.4",
|
|
42
|
+
"@salesforce/pwa-kit-runtime": "4.0.0-extensibility-preview.4",
|
|
44
43
|
"cross-env": "^5.2.1",
|
|
45
|
-
"event-emitter": "^0.3.5",
|
|
46
44
|
"hoist-non-react-statics": "^3.3.2",
|
|
47
45
|
"prop-types": "^15.8.1",
|
|
48
46
|
"react-ssr-prepass": "^1.5.0",
|
|
@@ -52,14 +50,15 @@
|
|
|
52
50
|
},
|
|
53
51
|
"devDependencies": {
|
|
54
52
|
"@loadable/component": "^5.15.3",
|
|
55
|
-
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.
|
|
53
|
+
"@salesforce/pwa-kit-dev": "4.0.0-extensibility-preview.4",
|
|
56
54
|
"@testing-library/jest-dom": "^5.16.5",
|
|
57
55
|
"@testing-library/react": "^14.0.0",
|
|
58
56
|
"@testing-library/user-event": "^14.4.3",
|
|
59
57
|
"@types/hoist-non-react-statics": "~3.3.5",
|
|
58
|
+
"@types/mocha": "^10.0.10",
|
|
60
59
|
"@types/react": "~18.2.0",
|
|
61
60
|
"@types/react-dom": "~18.2.1",
|
|
62
|
-
"internal-lib-build": "4.0.0-extensibility-preview.
|
|
61
|
+
"internal-lib-build": "4.0.0-extensibility-preview.4",
|
|
63
62
|
"node-html-parser": "^3.3.6",
|
|
64
63
|
"nodemon": "^2.0.22",
|
|
65
64
|
"react": "^18.2.0",
|
|
@@ -72,17 +71,18 @@
|
|
|
72
71
|
},
|
|
73
72
|
"peerDependencies": {
|
|
74
73
|
"@loadable/component": "^5.15.3",
|
|
74
|
+
"@tanstack/react-query": "^4.28.0",
|
|
75
75
|
"react": "^18.2.0",
|
|
76
76
|
"react-dom": "^18.2.0",
|
|
77
77
|
"react-helmet": "^6.1.0",
|
|
78
78
|
"react-router-dom": "^5.3.4"
|
|
79
79
|
},
|
|
80
80
|
"engines": {
|
|
81
|
-
"node": "^16.11.0 || ^18.0.0 || ^20.0.0",
|
|
82
|
-
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
81
|
+
"node": "^16.11.0 || ^18.0.0 || ^20.0.0 || ^22.0.0",
|
|
82
|
+
"npm": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
|
|
83
83
|
},
|
|
84
84
|
"publishConfig": {
|
|
85
85
|
"directory": "dist"
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "5ad3b1f0e598cfe0fbdec5b1212b4dabc0a8733c"
|
|
88
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/ssr/browser/main.jsx"],"names":[],"mappings":"AA0BO,2EAoBN;AAEM;;;;;;;4CAmCN;;;;;;;;;;;AAWM,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/ssr/browser/main.jsx"],"names":[],"mappings":"AA0BO,2EAoBN;AAEM;;;;;;;4CAmCN;;;;;;;;;;;AAWM,uCA8DN"}
|
package/ssr/browser/main.js
CHANGED
|
@@ -58,7 +58,10 @@ const OuterApp = ({
|
|
|
58
58
|
// Invoke the Application Extensions 'beforeRouteMatch' hook. This hook accepts ALL the routes for the current
|
|
59
59
|
// application including all routes added from the configured extensions.
|
|
60
60
|
extensions.forEach(applicationExtension => {
|
|
61
|
-
routes = applicationExtension.beforeRouteMatch(
|
|
61
|
+
routes = applicationExtension.beforeRouteMatch({
|
|
62
|
+
allRoutes: routes,
|
|
63
|
+
locals
|
|
64
|
+
});
|
|
62
65
|
});
|
|
63
66
|
return /*#__PURE__*/_react.default.createElement(_contexts.ServerContext.Provider, {
|
|
64
67
|
value: {}
|
|
@@ -113,7 +116,7 @@ const start = exports.start = /*#__PURE__*/function () {
|
|
|
113
116
|
// this to set up, eg. Redux stores.
|
|
114
117
|
const locals = {};
|
|
115
118
|
|
|
116
|
-
// AppConfig.restore *must* come before
|
|
119
|
+
// AppConfig.restore *must* come before getAllRoutes()
|
|
117
120
|
AppConfig.restore(locals, window.__PRELOADED_STATE__.__STATE_MANAGEMENT_LIBRARY);
|
|
118
121
|
|
|
119
122
|
// We need to tell the routeComponent HOC when the app is hydrating in order to
|
|
@@ -132,10 +135,11 @@ const start = exports.start = /*#__PURE__*/function () {
|
|
|
132
135
|
applicationExtensions,
|
|
133
136
|
locals
|
|
134
137
|
});
|
|
138
|
+
const routes = yield (0, _routeComponent.getAllRoutes)(locals);
|
|
135
139
|
const props = {
|
|
136
140
|
error: window.__ERROR__,
|
|
137
141
|
locals: locals,
|
|
138
|
-
routes
|
|
142
|
+
routes,
|
|
139
143
|
extensions: applicationExtensions,
|
|
140
144
|
WrappedApp
|
|
141
145
|
};
|
package/ssr/browser/main.test.js
CHANGED
|
@@ -9,16 +9,16 @@ var _uuidv = require("../../utils/uuidv4.client");
|
|
|
9
9
|
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); }
|
|
10
10
|
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; }
|
|
11
11
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
-
|
|
12
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
13
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } /*
|
|
13
14
|
* Copyright (c) 2022, salesforce.com, inc.
|
|
14
15
|
* All rights reserved.
|
|
15
16
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
16
17
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
17
18
|
*/
|
|
18
|
-
|
|
19
19
|
jest.mock('../../utils/uuidv4.client');
|
|
20
20
|
describe('main', function () {
|
|
21
|
-
test('OuterApp renders without error', ()
|
|
21
|
+
test('OuterApp renders without error', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
22
22
|
_uuidv.uuidv4.mockReturnValueOnce('7f21aea5-6962-4162-8204-9da85c802022');
|
|
23
23
|
const oldPreloadedState = window.__PRELOADED_STATE__;
|
|
24
24
|
window.__PRELOADED_STATE__ = {
|
|
@@ -29,15 +29,15 @@ describe('main', function () {
|
|
|
29
29
|
const props = {
|
|
30
30
|
error: undefined,
|
|
31
31
|
locals,
|
|
32
|
-
routes: (0, _routeComponent.
|
|
32
|
+
routes: yield (0, _routeComponent.getAllRoutes)(locals),
|
|
33
33
|
WrappedApp: (0, _routeComponent.routeComponent)(App, false, locals),
|
|
34
34
|
extensions: []
|
|
35
35
|
};
|
|
36
36
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_main.OuterApp, props));
|
|
37
37
|
expect(_react2.screen.getByText('App')).toBeInTheDocument();
|
|
38
38
|
window.__PRELOADED_STATE__ = oldPreloadedState;
|
|
39
|
-
});
|
|
40
|
-
test('OuterApp triggers the error page when there is an error', ()
|
|
39
|
+
}));
|
|
40
|
+
test('OuterApp triggers the error page when there is an error', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
41
41
|
const oldWindowError = window.__ERROR__;
|
|
42
42
|
window.__ERROR__ = new errors.HTTPNotFound('Not found');
|
|
43
43
|
const App = () => /*#__PURE__*/_react.default.createElement("div", null, "App");
|
|
@@ -45,12 +45,12 @@ describe('main', function () {
|
|
|
45
45
|
const props = {
|
|
46
46
|
error: window.__ERROR__,
|
|
47
47
|
locals,
|
|
48
|
-
routes: (0, _routeComponent.
|
|
48
|
+
routes: yield (0, _routeComponent.getAllRoutes)(locals),
|
|
49
49
|
WrappedApp: (0, _routeComponent.routeComponent)(App, false, locals),
|
|
50
50
|
extensions: []
|
|
51
51
|
};
|
|
52
52
|
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_main.OuterApp, props));
|
|
53
53
|
expect(_react2.screen.getByText('Error Status: 404')).toBeInTheDocument();
|
|
54
54
|
window.__ERROR__ = oldWindowError;
|
|
55
|
-
});
|
|
55
|
+
}));
|
|
56
56
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-rendering.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/react-rendering.js"],"names":[],"mappings":"AAyDA,+CAA4C;AAyBrC,+DA4BN;AAYM,
|
|
1
|
+
{"version":3,"file":"react-rendering.d.ts","sourceRoot":"","sources":["../../../src/ssr/server/react-rendering.js"],"names":[],"mappings":"AAyDA,+CAA4C;AAyBrC,+DA4BN;AAYM,oEAsJN;;AAkKD;;;oDAIK"}
|
|
@@ -140,7 +140,7 @@ const render = exports.render = /*#__PURE__*/function () {
|
|
|
140
140
|
applicationExtensions,
|
|
141
141
|
locals: res.locals
|
|
142
142
|
});
|
|
143
|
-
let routes = (0, _routeComponent.
|
|
143
|
+
let routes = yield (0, _routeComponent.getAllRoutes)(res.locals);
|
|
144
144
|
const [pathname] = req.originalUrl.split('?');
|
|
145
145
|
const location = {
|
|
146
146
|
pathname,
|
|
@@ -149,11 +149,25 @@ const render = exports.render = /*#__PURE__*/function () {
|
|
|
149
149
|
})
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
+
// Some application extensions need to be serialized because they have asynchronous state
|
|
153
|
+
const serializedExtensions = Object.fromEntries(applicationExtensions.flatMap(extension => {
|
|
154
|
+
if (typeof extension.getRoutesAsync !== 'function') return [];
|
|
155
|
+
const routes = extension.serializeAsyncRoutes();
|
|
156
|
+
// TODO W-18257236: Use a unique key for each extension like the extension ID from
|
|
157
|
+
// extension-meta.json
|
|
158
|
+
return [[extension.getName(), {
|
|
159
|
+
routes
|
|
160
|
+
}]];
|
|
161
|
+
}));
|
|
162
|
+
|
|
152
163
|
// Step 1 - Find the match.
|
|
153
164
|
|
|
154
165
|
// Call `beforeRouteMatch` application extension hook.
|
|
155
166
|
applicationExtensions.forEach(applicationExtension => {
|
|
156
|
-
routes = applicationExtension.beforeRouteMatch(
|
|
167
|
+
routes = applicationExtension.beforeRouteMatch({
|
|
168
|
+
allRoutes: routes,
|
|
169
|
+
locals: res.locals
|
|
170
|
+
});
|
|
157
171
|
});
|
|
158
172
|
res.__performanceTimer.mark(_performance.PERFORMANCE_MARKS.routeMatching, 'start');
|
|
159
173
|
let route;
|
|
@@ -225,7 +239,8 @@ const render = exports.render = /*#__PURE__*/function () {
|
|
|
225
239
|
res,
|
|
226
240
|
location,
|
|
227
241
|
config,
|
|
228
|
-
appJSX
|
|
242
|
+
appJSX,
|
|
243
|
+
serializedExtensions
|
|
229
244
|
});
|
|
230
245
|
} catch (e) {
|
|
231
246
|
// This is an unrecoverable error.
|
|
@@ -310,7 +325,8 @@ const renderApp = args => {
|
|
|
310
325
|
appStateError,
|
|
311
326
|
appJSX,
|
|
312
327
|
appState,
|
|
313
|
-
config
|
|
328
|
+
config,
|
|
329
|
+
serializedExtensions
|
|
314
330
|
} = args;
|
|
315
331
|
const extractor = new _server2.ChunkExtractor({
|
|
316
332
|
statsFile: BUNDLES_PATH,
|
|
@@ -373,6 +389,7 @@ const renderApp = args => {
|
|
|
373
389
|
__CONFIG__: config,
|
|
374
390
|
__PRELOADED_STATE__: appState,
|
|
375
391
|
__ERROR__: error,
|
|
392
|
+
__EXTENSIONS__: serializedExtensions,
|
|
376
393
|
// `window.Progressive` has a long history at Mobify and some
|
|
377
394
|
// client-side code depends on it. Maintain its name out of tradition.
|
|
378
395
|
Progressive: getWindowProgressive(req, res)
|
|
@@ -15,8 +15,8 @@ const _excluded = ["status", "staticContext"];
|
|
|
15
15
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
16
16
|
*/
|
|
17
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
19
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
18
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
19
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
20
20
|
/**
|
|
21
21
|
* The `RedirectWithStatus` component is used to specify a different status code when redirecting via
|
|
22
22
|
* the Redirect component.
|
|
@@ -2,5 +2,5 @@ export function routeComponent(Wrapped: any, isPage: any, locals: any): {
|
|
|
2
2
|
(props: any): import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
displayName: string;
|
|
4
4
|
};
|
|
5
|
-
export function
|
|
5
|
+
export function getAllRoutes(locals?: {}): Promise<any[]>;
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/route-component/index.js"],"names":[],"mappings":"AAyDO;;;EAkVN;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/route-component/index.js"],"names":[],"mappings":"AAyDO;;;EAkVN;AAWM,0DA0BN"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.routeComponent = exports.
|
|
6
|
+
exports.routeComponent = exports.getAllRoutes = void 0;
|
|
7
7
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
8
8
|
var _react = _interopRequireDefault(require("react"));
|
|
9
9
|
var _reactRouterDom = require("react-router-dom");
|
|
@@ -11,14 +11,14 @@ var _hoistNonReactStatics = _interopRequireDefault(require("hoist-non-react-stat
|
|
|
11
11
|
var _appErrorBoundary = require("../../components/app-error-boundary");
|
|
12
12
|
var _throw2 = _interopRequireDefault(require("../../components/throw-404"));
|
|
13
13
|
var _compatibility = require("../../compatibility");
|
|
14
|
-
var
|
|
14
|
+
var _routes = _interopRequireDefault(require("../../routes"));
|
|
15
15
|
var _events = require("../../events");
|
|
16
16
|
var _withLegacyGetProps = require("../../components/with-legacy-get-props");
|
|
17
17
|
var _refresh = _interopRequireDefault(require("../refresh"));
|
|
18
18
|
const _excluded = ["component"];
|
|
19
19
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
21
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
20
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
21
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
22
22
|
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
23
23
|
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
24
24
|
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; }
|
|
@@ -381,43 +381,45 @@ const routeComponent = (Wrapped, isPage, locals) => {
|
|
|
381
381
|
};
|
|
382
382
|
|
|
383
383
|
/**
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
384
|
+
* Get all of the routes, including those from the app itself, the app
|
|
385
|
+
* extensions, and the SDK's internal routes.
|
|
386
|
+
*
|
|
387
|
+
* Also, wrap each route's component with the route-component HOC so that
|
|
388
|
+
* they all support `getProps` methods server-side and client-side in the same way.
|
|
387
389
|
*
|
|
388
390
|
* @private
|
|
389
391
|
*/
|
|
390
392
|
exports.routeComponent = routeComponent;
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
_routes
|
|
393
|
+
const getAllRoutes = exports.getAllRoutes = /*#__PURE__*/function () {
|
|
394
|
+
var _ref2 = _asyncToGenerator(function* (locals = {}) {
|
|
395
|
+
const {
|
|
396
|
+
applicationExtensions = []
|
|
397
|
+
} = locals;
|
|
398
|
+
const extensionRoutes = (yield Promise.all(applicationExtensions.map(extension => typeof extension.getRoutesAsync === 'function' ? extension.getRoutesAsync({
|
|
399
|
+
locals
|
|
400
|
+
}) : extension.getRoutes({
|
|
401
|
+
locals
|
|
402
|
+
})))).flat();
|
|
403
|
+
const allRoutes = [
|
|
404
|
+
// NOTE: this route needs to be above _routes, in case _routes has a fallback route of `path: '*'`
|
|
405
|
+
{
|
|
406
|
+
path: '/__pwa-kit/refresh',
|
|
407
|
+
component: _refresh.default
|
|
408
|
+
}, ...extensionRoutes, ...(typeof _routes.default === 'function' ? (0, _routes.default)() : _routes.default), {
|
|
409
|
+
path: '*',
|
|
410
|
+
component: _throw2.default
|
|
411
|
+
}];
|
|
412
|
+
return allRoutes.map(_ref3 => {
|
|
413
|
+
let {
|
|
414
|
+
component
|
|
415
|
+
} = _ref3,
|
|
416
|
+
rest = _objectWithoutProperties(_ref3, _excluded);
|
|
417
|
+
return _objectSpread({
|
|
418
|
+
component: component ? routeComponent(component, true, locals) : component
|
|
419
|
+
}, rest);
|
|
420
|
+
});
|
|
403
421
|
});
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
component: _refresh.default
|
|
409
|
-
}, ..._routes, {
|
|
410
|
-
path: '*',
|
|
411
|
-
component: _throw2.default
|
|
412
|
-
}];
|
|
413
|
-
return allRoutes.map(_ref2 => {
|
|
414
|
-
let {
|
|
415
|
-
component
|
|
416
|
-
} = _ref2,
|
|
417
|
-
rest = _objectWithoutProperties(_ref2, _excluded);
|
|
418
|
-
return _objectSpread({
|
|
419
|
-
component: component ? routeComponent(component, true, locals) : component
|
|
420
|
-
}, rest);
|
|
421
|
-
});
|
|
422
|
-
};
|
|
423
|
-
exports.getRoutes = getRoutes;
|
|
422
|
+
return function getAllRoutes() {
|
|
423
|
+
return _ref2.apply(this, arguments);
|
|
424
|
+
};
|
|
425
|
+
}();
|
|
@@ -253,9 +253,9 @@ describe('The routeComponent component', () => {
|
|
|
253
253
|
});
|
|
254
254
|
}));
|
|
255
255
|
});
|
|
256
|
-
describe('
|
|
257
|
-
test('wraps components with the routeComponent HOC', ()
|
|
258
|
-
const mappedRoutes = (0, _index.
|
|
256
|
+
describe('getAllRoutes', () => {
|
|
257
|
+
test('wraps components with the routeComponent HOC', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
258
|
+
const mappedRoutes = yield (0, _index.getAllRoutes)();
|
|
259
259
|
expect(mappedRoutes).toHaveLength(3);
|
|
260
260
|
const [first, second, third] = mappedRoutes;
|
|
261
261
|
const expectedRefetchName = 'WithErrorHandling(withRouter(routeComponent(Refresh)))';
|
|
@@ -264,7 +264,7 @@ describe('getRoutes', () => {
|
|
|
264
264
|
expect(second.component.displayName).toBe(expectedName);
|
|
265
265
|
const expected404Name = 'WithErrorHandling(withRouter(routeComponent(Throw404)))';
|
|
266
266
|
expect(third.component.displayName).toBe(expected404Name);
|
|
267
|
-
});
|
|
267
|
+
}));
|
|
268
268
|
});
|
|
269
269
|
|
|
270
270
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/switch/index.jsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/switch/index.jsx"],"names":[],"mappings":";AAcA;;;;;;;;GAQG;AACH,6EAeC"}
|
|
@@ -9,6 +9,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
|
9
9
|
var _reactRouterDom = require("react-router-dom");
|
|
10
10
|
var _appErrorBoundary = _interopRequireDefault(require("../app-error-boundary"));
|
|
11
11
|
var _reactUid = require("react-uid");
|
|
12
|
+
var _contexts = require("../../contexts");
|
|
13
|
+
var _hooks = require("../../hooks");
|
|
12
14
|
const _excluded = ["component"];
|
|
13
15
|
/*
|
|
14
16
|
* Copyright (c) 2021, salesforce.com, inc.
|
|
@@ -18,8 +20,8 @@ const _excluded = ["component"];
|
|
|
18
20
|
*/
|
|
19
21
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
20
22
|
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); }
|
|
21
|
-
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var
|
|
22
|
-
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.
|
|
23
|
+
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
24
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
23
25
|
/**
|
|
24
26
|
* The Switch component packages up the bits of rendering that are shared between
|
|
25
27
|
* server and client-side. It's *mostly* a react-router Switch component, hence the
|
|
@@ -38,9 +40,28 @@ const Switch = props => {
|
|
|
38
40
|
} = props;
|
|
39
41
|
return /*#__PURE__*/_react.default.createElement(_reactUid.UIDReset, null, /*#__PURE__*/_react.default.createElement(_appErrorBoundary.default, {
|
|
40
42
|
error: error
|
|
41
|
-
}, !error && /*#__PURE__*/_react.default.createElement(
|
|
43
|
+
}, !error && /*#__PURE__*/_react.default.createElement(_contexts.RoutesProvider, {
|
|
44
|
+
routes: routes
|
|
45
|
+
}, /*#__PURE__*/_react.default.createElement(App, {
|
|
42
46
|
preloadedProps: appState.appProps
|
|
43
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
47
|
+
}, /*#__PURE__*/_react.default.createElement(RoutesConsumer, {
|
|
48
|
+
appState: appState
|
|
49
|
+
})))));
|
|
50
|
+
};
|
|
51
|
+
Switch.propTypes = {
|
|
52
|
+
error: _propTypes.default.object,
|
|
53
|
+
appState: _propTypes.default.object,
|
|
54
|
+
routes: _propTypes.default.array,
|
|
55
|
+
App: _propTypes.default.func,
|
|
56
|
+
preloadedProps: _propTypes.default.object
|
|
57
|
+
};
|
|
58
|
+
const RoutesConsumer = ({
|
|
59
|
+
appState
|
|
60
|
+
}) => {
|
|
61
|
+
const {
|
|
62
|
+
routes
|
|
63
|
+
} = (0, _hooks.useRoutes)();
|
|
64
|
+
return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Switch, null, routes.map((route, i) => {
|
|
44
65
|
const {
|
|
45
66
|
component: Component
|
|
46
67
|
} = route,
|
|
@@ -50,13 +71,9 @@ const Switch = props => {
|
|
|
50
71
|
}, routeProps), /*#__PURE__*/_react.default.createElement(_reactUid.UIDFork, null, /*#__PURE__*/_react.default.createElement(Component, {
|
|
51
72
|
preloadedProps: appState.pageProps
|
|
52
73
|
})));
|
|
53
|
-
}))
|
|
74
|
+
}));
|
|
54
75
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
appState: _propTypes.default.object,
|
|
58
|
-
routes: _propTypes.default.array,
|
|
59
|
-
App: _propTypes.default.func,
|
|
60
|
-
preloadedProps: _propTypes.default.object
|
|
76
|
+
RoutesConsumer.propTypes = {
|
|
77
|
+
appState: _propTypes.default.object.isRequired
|
|
61
78
|
};
|
|
62
79
|
var _default = exports.default = Switch;
|
|
@@ -49,7 +49,7 @@ const withLegacyGetProps = Wrapped => {
|
|
|
49
49
|
// to avoid blocking the execution of the getProps function to maximize performance
|
|
50
50
|
// getTemplateName should be very fast, under 0.2ms
|
|
51
51
|
c.getTemplateName().then(templateName => {
|
|
52
|
-
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}
|
|
52
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}.${templateName}`, 'start');
|
|
53
53
|
});
|
|
54
54
|
return c.getProps ? c.getProps({
|
|
55
55
|
req,
|
|
@@ -58,7 +58,7 @@ const withLegacyGetProps = Wrapped => {
|
|
|
58
58
|
location
|
|
59
59
|
}).then(result => {
|
|
60
60
|
c.getTemplateName().then(templateName => {
|
|
61
|
-
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}
|
|
61
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.getProps}.${templateName}`, 'end');
|
|
62
62
|
});
|
|
63
63
|
return result;
|
|
64
64
|
}) : Promise.resolve({});
|
|
@@ -83,10 +83,10 @@ const withReactQuery = (Wrapped, options = {}) => {
|
|
|
83
83
|
yield Promise.all(queries.map((q, i) => {
|
|
84
84
|
var _q$meta, _q$meta2;
|
|
85
85
|
// always include the index to avoid duplicate entries
|
|
86
|
-
const displayName = (_q$meta = q.meta) !== null && _q$meta !== void 0 && _q$meta.displayName ? `${(_q$meta2 = q.meta) === null || _q$meta2 === void 0 ? void 0 : _q$meta2.displayName}
|
|
87
|
-
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}
|
|
86
|
+
const displayName = (_q$meta = q.meta) !== null && _q$meta !== void 0 && _q$meta.displayName ? `${(_q$meta2 = q.meta) === null || _q$meta2 === void 0 ? void 0 : _q$meta2.displayName}-${i}` : `${i}`;
|
|
87
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.${displayName}`, 'start');
|
|
88
88
|
return q.fetch().then(result => {
|
|
89
|
-
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}
|
|
89
|
+
res.__performanceTimer.mark(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.${displayName}`, 'end', {
|
|
90
90
|
detail: q.queryHash
|
|
91
91
|
});
|
|
92
92
|
return result;
|
|
@@ -4,14 +4,23 @@ var _index = require("./index");
|
|
|
4
4
|
var _react = require("@testing-library/react");
|
|
5
5
|
var _react2 = _interopRequireDefault(require("react"));
|
|
6
6
|
var _loggerInstance = _interopRequireDefault(require("../../../../utils/logger-instance"));
|
|
7
|
+
var _performance = require("../../../../utils/performance");
|
|
7
8
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
10
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
11
|
+
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; }
|
|
12
|
+
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; }
|
|
13
|
+
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; }
|
|
14
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
15
|
+
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
16
|
* Copyright (c) 2022, Salesforce, Inc.
|
|
10
17
|
* All rights reserved.
|
|
11
18
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
12
19
|
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
13
20
|
*/
|
|
14
|
-
|
|
21
|
+
jest.mock('@tanstack/react-query', () => _objectSpread(_objectSpread({}, jest.requireActual('@tanstack/react-query')), {}, {
|
|
22
|
+
dehydrate: jest.fn().mockReturnValue({})
|
|
23
|
+
}));
|
|
15
24
|
jest.mock('../../../../utils/logger-instance', () => {
|
|
16
25
|
return {
|
|
17
26
|
error: jest.fn()
|
|
@@ -98,4 +107,101 @@ describe('withReactQuery', function () {
|
|
|
98
107
|
getHOCsInUse: () => ['xyz']
|
|
99
108
|
}).getHOCsInUse()).toHaveLength(2);
|
|
100
109
|
});
|
|
110
|
+
test('Performance markers use hyphen as delimiter for displayName', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
111
|
+
const mockPerformanceTimer = {
|
|
112
|
+
mark: jest.fn()
|
|
113
|
+
};
|
|
114
|
+
const mockQueryMeta = {
|
|
115
|
+
displayName: 'TestQuery'
|
|
116
|
+
};
|
|
117
|
+
const mockQueryCache = {
|
|
118
|
+
getAll: jest.fn().mockReturnValue([{
|
|
119
|
+
options: {
|
|
120
|
+
enabled: true
|
|
121
|
+
},
|
|
122
|
+
meta: mockQueryMeta,
|
|
123
|
+
queryHash: 'test-hash',
|
|
124
|
+
fetch: jest.fn().mockResolvedValue({})
|
|
125
|
+
}])
|
|
126
|
+
};
|
|
127
|
+
const mockQueryClient = {
|
|
128
|
+
getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
|
|
129
|
+
};
|
|
130
|
+
const res = {
|
|
131
|
+
locals: {
|
|
132
|
+
__queryClient: mockQueryClient
|
|
133
|
+
},
|
|
134
|
+
__performanceTimer: mockPerformanceTimer
|
|
135
|
+
};
|
|
136
|
+
const Component = (0, _index.withReactQuery)({});
|
|
137
|
+
yield Component.doInitAppState({
|
|
138
|
+
res,
|
|
139
|
+
appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
|
|
140
|
+
});
|
|
141
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.TestQuery-0`, 'start');
|
|
142
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.TestQuery-0`, 'end', expect.objectContaining({
|
|
143
|
+
detail: 'test-hash'
|
|
144
|
+
}));
|
|
145
|
+
}));
|
|
146
|
+
test('Performance markers use index as displayName when meta.displayName is not available', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
147
|
+
const mockPerformanceTimer = {
|
|
148
|
+
mark: jest.fn()
|
|
149
|
+
};
|
|
150
|
+
const mockQueryCache = {
|
|
151
|
+
getAll: jest.fn().mockReturnValue([{
|
|
152
|
+
options: {
|
|
153
|
+
enabled: true
|
|
154
|
+
},
|
|
155
|
+
meta: {},
|
|
156
|
+
queryHash: 'test-hash',
|
|
157
|
+
fetch: jest.fn().mockResolvedValue({})
|
|
158
|
+
}])
|
|
159
|
+
};
|
|
160
|
+
const mockQueryClient = {
|
|
161
|
+
getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
|
|
162
|
+
};
|
|
163
|
+
const res = {
|
|
164
|
+
locals: {
|
|
165
|
+
__queryClient: mockQueryClient
|
|
166
|
+
},
|
|
167
|
+
__performanceTimer: mockPerformanceTimer
|
|
168
|
+
};
|
|
169
|
+
const Component = (0, _index.withReactQuery)({});
|
|
170
|
+
yield Component.doInitAppState({
|
|
171
|
+
res,
|
|
172
|
+
appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Verify the performance marker uses just the index when no displayName is available
|
|
176
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.0`, 'start');
|
|
177
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(`${_performance.PERFORMANCE_MARKS.reactQueryUseQuery}.0`, 'end', expect.objectContaining({
|
|
178
|
+
detail: 'test-hash'
|
|
179
|
+
}));
|
|
180
|
+
}));
|
|
181
|
+
test('Performance markers for reactQueryPrerender are set correctly', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
182
|
+
const mockPerformanceTimer = {
|
|
183
|
+
mark: jest.fn()
|
|
184
|
+
};
|
|
185
|
+
const mockQueryCache = {
|
|
186
|
+
getAll: jest.fn().mockReturnValue([])
|
|
187
|
+
};
|
|
188
|
+
const mockQueryClient = {
|
|
189
|
+
getQueryCache: jest.fn().mockReturnValue(mockQueryCache)
|
|
190
|
+
};
|
|
191
|
+
const res = {
|
|
192
|
+
locals: {
|
|
193
|
+
__queryClient: mockQueryClient
|
|
194
|
+
},
|
|
195
|
+
__performanceTimer: mockPerformanceTimer
|
|
196
|
+
};
|
|
197
|
+
const Component = (0, _index.withReactQuery)({});
|
|
198
|
+
yield Component.doInitAppState({
|
|
199
|
+
res,
|
|
200
|
+
appJSX: /*#__PURE__*/_react2.default.createElement("div", null, "Test")
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Verify the performance markers for reactQueryPrerender are set correctly
|
|
204
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(_performance.PERFORMANCE_MARKS.reactQueryPrerender, 'start');
|
|
205
|
+
expect(mockPerformanceTimer.mark).toHaveBeenCalledWith(_performance.PERFORMANCE_MARKS.reactQueryPrerender, 'end');
|
|
206
|
+
}));
|
|
101
207
|
});
|
|
@@ -21,6 +21,24 @@ export namespace CorrelationIdProvider {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
export const ServerContext: React.Context<any>;
|
|
24
|
+
export const RoutesContext: React.Context<any>;
|
|
25
|
+
/**
|
|
26
|
+
* This provider initializes the routes
|
|
27
|
+
* @param children
|
|
28
|
+
* @param routes - array of routes
|
|
29
|
+
*/
|
|
30
|
+
export function RoutesProvider({ routes, children }: {
|
|
31
|
+
routes: any;
|
|
32
|
+
children: any;
|
|
33
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export namespace RoutesProvider {
|
|
35
|
+
export namespace propTypes_1 {
|
|
36
|
+
export const routes: PropTypes.Validator<any[]>;
|
|
37
|
+
const children_1: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
|
|
38
|
+
export { children_1 as children };
|
|
39
|
+
}
|
|
40
|
+
export { propTypes_1 as propTypes };
|
|
41
|
+
}
|
|
24
42
|
import React from "react";
|
|
25
43
|
import PropTypes from "prop-types";
|
|
26
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/contexts/index.js"],"names":[],"mappings":"AAYA,sDAAkD;AAGlD;;;;;;;GAOG;AACH;;;;4CAiCC;;;;;;;;;AA3CD,+CAA2C"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/contexts/index.js"],"names":[],"mappings":"AAYA,sDAAkD;AAGlD;;;;;;;GAOG;AACH;;;;4CAiCC;;;;;;;;;AA3CD,+CAA2C;AAoD3C,+CAA2C;AAE3C;;;;GAIG;AACH;;;4CAQC"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.ServerContext = exports.CorrelationIdProvider = exports.CorrelationIdContext = void 0;
|
|
6
|
+
exports.ServerContext = exports.RoutesProvider = exports.RoutesContext = exports.CorrelationIdProvider = exports.CorrelationIdContext = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
9
|
var _reactRouterDom = require("react-router-dom");
|
|
@@ -69,4 +69,28 @@ CorrelationIdProvider.propTypes = {
|
|
|
69
69
|
resetOnPageChange: _propTypes.default.bool,
|
|
70
70
|
correlationId: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func]).isRequired,
|
|
71
71
|
location: _propTypes.default.object
|
|
72
|
+
};
|
|
73
|
+
const RoutesContext = exports.RoutesContext = /*#__PURE__*/_react.default.createContext();
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* This provider initializes the routes
|
|
77
|
+
* @param children
|
|
78
|
+
* @param routes - array of routes
|
|
79
|
+
*/
|
|
80
|
+
const RoutesProvider = ({
|
|
81
|
+
routes,
|
|
82
|
+
children
|
|
83
|
+
}) => {
|
|
84
|
+
const [_routes, setRoutes] = (0, _react.useState)(routes);
|
|
85
|
+
return /*#__PURE__*/_react.default.createElement(RoutesContext.Provider, {
|
|
86
|
+
value: {
|
|
87
|
+
routes: _routes,
|
|
88
|
+
setRoutes
|
|
89
|
+
}
|
|
90
|
+
}, children);
|
|
91
|
+
};
|
|
92
|
+
exports.RoutesProvider = RoutesProvider;
|
|
93
|
+
RoutesProvider.propTypes = {
|
|
94
|
+
routes: _propTypes.default.array.isRequired,
|
|
95
|
+
children: _propTypes.default.node.isRequired
|
|
72
96
|
};
|
|
@@ -98,4 +98,30 @@ describe('CorrelationIdProvider', function () {
|
|
|
98
98
|
// expecting the provider to have a different correlation id when a page navigation happens
|
|
99
99
|
expect(firstRenderedId).not.toEqual(secondRenderedId);
|
|
100
100
|
}));
|
|
101
|
+
});
|
|
102
|
+
describe('RoutesProvider', () => {
|
|
103
|
+
it('provides routes via context', () => {
|
|
104
|
+
const testRoutes = [{
|
|
105
|
+
path: '/home'
|
|
106
|
+
}, {
|
|
107
|
+
path: '/about'
|
|
108
|
+
}];
|
|
109
|
+
const TestComponent = () => {
|
|
110
|
+
const {
|
|
111
|
+
routes
|
|
112
|
+
} = (0, _hooks.useRoutes)();
|
|
113
|
+
return /*#__PURE__*/_react.default.createElement("div", null, routes.map(route => route.path).join(', '));
|
|
114
|
+
};
|
|
115
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_index.RoutesProvider, {
|
|
116
|
+
routes: testRoutes
|
|
117
|
+
}, /*#__PURE__*/_react.default.createElement(TestComponent, null)));
|
|
118
|
+
expect(_react2.screen.getByText('/home, /about')).toBeInTheDocument();
|
|
119
|
+
});
|
|
120
|
+
it('throws an error when useRoutes is used outside RoutesProvider', () => {
|
|
121
|
+
const TestComponent = () => {
|
|
122
|
+
(0, _hooks.useRoutes)();
|
|
123
|
+
return null;
|
|
124
|
+
};
|
|
125
|
+
expect(() => (0, _react2.render)(/*#__PURE__*/_react.default.createElement(TestComponent, null))).toThrow('useRoutes must be used within a RoutesProvider');
|
|
126
|
+
});
|
|
101
127
|
});
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
export class HTTPError extends Error {
|
|
2
|
-
|
|
3
|
-
constructor:
|
|
4
|
-
|
|
5
|
-
message: any;
|
|
6
|
-
status: any;
|
|
1
|
+
export declare class HTTPError extends Error {
|
|
2
|
+
status: number;
|
|
3
|
+
constructor(status: number, message: string);
|
|
4
|
+
toString(): string;
|
|
7
5
|
}
|
|
8
|
-
export class HTTPNotFound extends HTTPError {
|
|
9
|
-
constructor(message:
|
|
10
|
-
constructor: typeof HTTPNotFound;
|
|
11
|
-
__proto__: HTTPNotFound;
|
|
6
|
+
export declare class HTTPNotFound extends HTTPError {
|
|
7
|
+
constructor(message: string);
|
|
12
8
|
}
|
|
13
9
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/errors.
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/errors.ts"],"names":[],"mappings":"AAOA,qBAAa,SAAU,SAAQ,KAAK;IAChC,MAAM,EAAE,MAAM,CAAA;gBAEF,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAK3C,QAAQ;CAGX;AAED,qBAAa,YAAa,SAAQ,SAAS;gBAC3B,OAAO,EAAE,MAAM;CAG9B"}
|
package/ssr/universal/errors.js
CHANGED
|
@@ -14,9 +14,6 @@ exports.HTTPNotFound = exports.HTTPError = void 0;
|
|
|
14
14
|
class HTTPError extends Error {
|
|
15
15
|
constructor(status, message) {
|
|
16
16
|
super(message);
|
|
17
|
-
this.constructor = HTTPError;
|
|
18
|
-
this.__proto__ = HTTPError.prototype;
|
|
19
|
-
this.message = message;
|
|
20
17
|
this.status = status;
|
|
21
18
|
}
|
|
22
19
|
toString() {
|
|
@@ -27,8 +24,6 @@ exports.HTTPError = HTTPError;
|
|
|
27
24
|
class HTTPNotFound extends HTTPError {
|
|
28
25
|
constructor(message) {
|
|
29
26
|
super(404, message);
|
|
30
|
-
this.constructor = HTTPNotFound;
|
|
31
|
-
this.__proto__ = HTTPNotFound.prototype;
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
exports.HTTPNotFound = HTTPNotFound;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/events.js"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/events.js"],"names":[],"mappings":";;;;AA6BA,0BAAgC;AAlBhC;IACI,wDAOC;IACD,qCAMC;CACJ"}
|
package/ssr/universal/events.js
CHANGED
|
@@ -4,8 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.pages = exports.PAGEEVENTS = void 0;
|
|
7
|
-
var _eventEmitter = _interopRequireDefault(require("event-emitter"));
|
|
8
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
7
|
/*
|
|
10
8
|
* Copyright (c) 2021, salesforce.com, inc.
|
|
11
9
|
* All rights reserved.
|
|
@@ -17,22 +15,25 @@ const PAGEEVENTS = exports.PAGEEVENTS = {
|
|
|
17
15
|
PAGELOAD: 'PAGELOAD',
|
|
18
16
|
ERROR: 'ERROR'
|
|
19
17
|
};
|
|
20
|
-
class Pages {
|
|
18
|
+
class Pages extends EventTarget {
|
|
21
19
|
pageLoad(templateName, start, end) {
|
|
22
20
|
const payload = {
|
|
23
21
|
templateName,
|
|
24
22
|
start,
|
|
25
23
|
end
|
|
26
24
|
};
|
|
27
|
-
this.
|
|
25
|
+
this.dispatchEvent(new CustomEvent(PAGEEVENTS.PAGELOAD, {
|
|
26
|
+
detail: payload
|
|
27
|
+
}));
|
|
28
28
|
}
|
|
29
29
|
error(name, content) {
|
|
30
30
|
const payload = {
|
|
31
31
|
name,
|
|
32
32
|
content
|
|
33
33
|
};
|
|
34
|
-
this.
|
|
34
|
+
this.dispatchEvent(new CustomEvent(PAGEEVENTS.ERROR, {
|
|
35
|
+
detail: payload
|
|
36
|
+
}));
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
|
-
(0, _eventEmitter.default)(Pages.prototype);
|
|
38
39
|
const pages = exports.pages = new Pages();
|
|
@@ -12,8 +12,8 @@ describe('Page Events', () => {
|
|
|
12
12
|
test('emit and receive a PAGELOAD Page Event', () => {
|
|
13
13
|
expect.assertions(1);
|
|
14
14
|
return new Promise(resolve => {
|
|
15
|
-
_events.pages.
|
|
16
|
-
expect(JSON.stringify(evt)).toEqual(JSON.stringify({
|
|
15
|
+
_events.pages.addEventListener(_events.PAGEEVENTS.PAGELOAD, evt => {
|
|
16
|
+
expect(JSON.stringify(evt.detail)).toEqual(JSON.stringify({
|
|
17
17
|
templateName: 'blah',
|
|
18
18
|
start: 123,
|
|
19
19
|
end: 456
|
|
@@ -26,8 +26,8 @@ describe('Page Events', () => {
|
|
|
26
26
|
test('emit and receive a ERROR Page Event', () => {
|
|
27
27
|
expect.assertions(1);
|
|
28
28
|
return new Promise(resolve => {
|
|
29
|
-
_events.pages.
|
|
30
|
-
expect(JSON.stringify(evt)).toEqual(JSON.stringify({
|
|
29
|
+
_events.pages.addEventListener(_events.PAGEEVENTS.ERROR, evt => {
|
|
30
|
+
expect(JSON.stringify(evt.detail)).toEqual(JSON.stringify({
|
|
31
31
|
name: 'blah',
|
|
32
32
|
content: 'more blah'
|
|
33
33
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/hooks/index.js"],"names":[],"mappings":"AAgBO,oCAFM,MAAM,CAQlB;AAiBM,oCANM,aAAa,CAUzB;AAcM;;IAHM,MAAM,CAiBlB;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ssr/universal/hooks/index.js"],"names":[],"mappings":"AAgBO,oCAFM,MAAM,CAQlB;AAiBM,oCANM,aAAa,CAUzB;AAcM;;IAHM,MAAM,CAiBlB;AAOM,6BAFM,MAAM,CAQlB;;;;;;;;SAzDa,MAAM;;;;SACN,MAAM"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.useServerContext = exports.useOrigin = exports.useCorrelationId = void 0;
|
|
6
|
+
exports.useServerContext = exports.useRoutes = exports.useOrigin = exports.useCorrelationId = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _contexts = require("../contexts");
|
|
9
9
|
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); }
|
|
@@ -81,4 +81,18 @@ const useOrigin = ({
|
|
|
81
81
|
}
|
|
82
82
|
return APP_ORIGIN;
|
|
83
83
|
};
|
|
84
|
-
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Use this hook to get the routes value of the closest RoutesProvider component.
|
|
87
|
+
*
|
|
88
|
+
* @returns {object} array of routes
|
|
89
|
+
*/
|
|
90
|
+
exports.useOrigin = useOrigin;
|
|
91
|
+
const useRoutes = () => {
|
|
92
|
+
const context = (0, _react.useContext)(_contexts.RoutesContext);
|
|
93
|
+
if (!context) {
|
|
94
|
+
throw new Error('useRoutes must be used within a RoutesProvider');
|
|
95
|
+
}
|
|
96
|
+
return context;
|
|
97
|
+
};
|
|
98
|
+
exports.useRoutes = useRoutes;
|
package/ssr/universal/utils.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export declare const getAssetUrl: (path: string) => string;
|
|
|
18
18
|
* @function
|
|
19
19
|
* @returns {string} The full URL to the static asset.
|
|
20
20
|
*/
|
|
21
|
-
export declare const getStaticAssetUrl: (path
|
|
21
|
+
export declare const getStaticAssetUrl: (path?: string, opts?: GetAssetUrlOptions) => string;
|
|
22
22
|
/**
|
|
23
23
|
* @typedef {Object} ProxyConfig
|
|
24
24
|
* @property {String} protocol - http or https
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/utils.ts"],"names":[],"mappings":"AAuBA,KAAK,kBAAkB,GAAG;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACnC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,WAQvC,CAAA;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/ssr/universal/utils.ts"],"names":[],"mappings":"AAuBA,KAAK,kBAAkB,GAAG;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACnC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,SAAU,MAAM,WAQvC,CAAA;AAID;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,yBAAqB,kBAAkB,WAkBpE,CAAA;AAED;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,WAS3B,CAAA"}
|
package/ssr/universal/utils.js
CHANGED
|
@@ -20,7 +20,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
20
20
|
*/ /* eslint-disable @typescript-eslint/ban-ts-comment */ // @ts-ignore
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
const onClient = typeof window !== 'undefined';
|
|
23
|
-
const
|
|
23
|
+
const EXTENSIONS_NAMESPACE = '__extensions';
|
|
24
24
|
const STATIC_FOLDER = 'static';
|
|
25
25
|
/**
|
|
26
26
|
* Get the URL that should be used to load an asset from the bundle.
|
|
@@ -38,7 +38,7 @@ const getAssetUrl = path => {
|
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
// TODO: Once we establish that we have a new @salesforce/pwa-kit-extensibility package, we can move this utility to
|
|
41
|
-
// it as to not have direct references to
|
|
41
|
+
// it as to not have direct references to extensibility in the sdk. This will also reduce duplicate code.
|
|
42
42
|
/**
|
|
43
43
|
* Get the URL that should be used to load a static asset from the bundle.
|
|
44
44
|
*
|
|
@@ -49,21 +49,22 @@ const getAssetUrl = path => {
|
|
|
49
49
|
* @returns {string} The full URL to the static asset.
|
|
50
50
|
*/
|
|
51
51
|
exports.getAssetUrl = getAssetUrl;
|
|
52
|
-
const getStaticAssetUrl = (path, opts) => {
|
|
52
|
+
const getStaticAssetUrl = (path = '', opts = {}) => {
|
|
53
53
|
const {
|
|
54
54
|
appExtensionPackageName = ''
|
|
55
55
|
} = opts || {};
|
|
56
56
|
|
|
57
57
|
/* istanbul ignore next */
|
|
58
|
-
|
|
59
|
-
// @ts-ignore
|
|
60
|
-
`${window.Progressive.buildOrigin}` : `${_ssrNamespacePaths.bundleBasePath}/${process.env.BUNDLE_ID || 'development'}/`;
|
|
58
|
+
let publicPath = getAssetUrl('');
|
|
61
59
|
|
|
62
60
|
// Ensure all defined path arguments start with `/`.
|
|
63
61
|
if (path && !path.startsWith('/')) {
|
|
64
62
|
path = `/${path}`;
|
|
65
63
|
}
|
|
66
|
-
|
|
64
|
+
if (publicPath && !publicPath.endsWith('/')) {
|
|
65
|
+
publicPath = `${publicPath}/`;
|
|
66
|
+
}
|
|
67
|
+
return `${publicPath}${STATIC_FOLDER}${appExtensionPackageName ? `/${EXTENSIONS_NAMESPACE}/${appExtensionPackageName}` : ''}${path ? path : ''}`;
|
|
67
68
|
};
|
|
68
69
|
|
|
69
70
|
/**
|
package/utils/performance.js
CHANGED
|
@@ -14,14 +14,14 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
const PERFORMANCE_MARKS = exports.PERFORMANCE_MARKS = {
|
|
17
|
-
total: 'ssr
|
|
18
|
-
renderToString: 'ssr
|
|
19
|
-
routeMatching: 'ssr
|
|
20
|
-
loadComponent: 'ssr
|
|
21
|
-
fetchStrategies: 'ssr
|
|
22
|
-
reactQueryPrerender: 'ssr
|
|
23
|
-
reactQueryUseQuery: 'ssr
|
|
24
|
-
getProps: 'ssr
|
|
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
25
|
};
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -60,7 +60,7 @@ class PerformanceTimer {
|
|
|
60
60
|
*/
|
|
61
61
|
buildServerTimingHeader() {
|
|
62
62
|
const header = this.metrics.map(metric => {
|
|
63
|
-
return `${metric.name};dur=${metric.duration}`;
|
|
63
|
+
return `${metric.name};dur=${metric.duration.toFixed(2)}`;
|
|
64
64
|
}).join(', ');
|
|
65
65
|
return header;
|
|
66
66
|
}
|