@salesforce/pwa-kit-react-sdk 4.0.0-extensibility-preview.2 → 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 +28 -0
- 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 +22 -5
- package/ssr/server/react-rendering.test.js +23 -0
- package/ssr/universal/components/redirect-with-status/index.d.ts +3 -0
- package/ssr/universal/components/redirect-with-status/index.d.ts.map +1 -0
- package/ssr/universal/components/redirect-with-status/index.js +46 -0
- package/ssr/universal/components/redirect-with-status/index.test.js +46 -0
- 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 +4 -0
- package/ssr/universal/hooks/index.d.ts.map +1 -1
- package/ssr/universal/hooks/index.js +49 -3
- 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 +11 -11
- package/utils/url.d.ts.map +1 -1
- package/utils/url.js +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,39 @@
|
|
|
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
|
+
|
|
7
|
+
## v4.0.0-extensibility-preview.3 (Dec 13, 2024)
|
|
8
|
+
|
|
1
9
|
## v4.0.0-extensibility-preview.2 (Dec 09, 2024)
|
|
10
|
+
|
|
2
11
|
## v4.0.0-extensibility-preview.1 (Dec 09, 2024)
|
|
12
|
+
|
|
3
13
|
## v4.0.0-extensibility-preview.0 (Nov 28, 2024)
|
|
4
14
|
- Integrate Application Extensions Project. (#2099)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2099]
|
|
5
15
|
- Add new `getStaticAssetUrl` utility to access assets specifically in the `/static` folder. (#2040)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2040]
|
|
6
16
|
- Update Application Extensions import in `react-rendering.js` and `main.js` (#2004)[https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2004]
|
|
7
17
|
- Define interface of the app extension's config [#2010](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2010)
|
|
8
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)
|
|
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)
|
|
32
|
+
|
|
33
|
+
## v3.8.0 (Oct 28, 2024)
|
|
34
|
+
- [Server Affinity] - Attach dwsid to SCAPI request headers [#2090](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2090)
|
|
35
|
+
- Create useOrigin hook to return an app origin that takes x-forwarded-host header into consideration. [#2050](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/2050)
|
|
36
|
+
|
|
9
37
|
## v3.7.0 (Aug 07, 2024)
|
|
10
38
|
- Add `beforeHydrate` option to withReactQuery component [#1912](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1912)
|
|
11
39
|
- Add server side rendering performance metrics via query parameter `__server_timing` or environment variable `SERVER_TIMING`, the metrics is available in the console logs and response header `server-timing`. [#1895](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1895)
|
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.
|
|
@@ -252,7 +267,7 @@ const render = exports.render = /*#__PURE__*/function () {
|
|
|
252
267
|
res.setHeader('Server-Timing', res.__performanceTimer.buildServerTimingHeader());
|
|
253
268
|
}
|
|
254
269
|
if (redirectUrl) {
|
|
255
|
-
res.redirect(302, redirectUrl);
|
|
270
|
+
res.redirect(routerContext.status || 302, redirectUrl);
|
|
256
271
|
} else {
|
|
257
272
|
res.status(status).send(html);
|
|
258
273
|
}
|
|
@@ -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)
|
|
@@ -58,6 +58,7 @@ jest.mock('../universal/routes', () => {
|
|
|
58
58
|
const React = require('react');
|
|
59
59
|
const PropTypes = require('prop-types');
|
|
60
60
|
const errors = require('../universal/errors');
|
|
61
|
+
const RedirectWithStatus = require('../universal/components/redirect-with-status').default;
|
|
61
62
|
const {
|
|
62
63
|
Redirect
|
|
63
64
|
} = require('react-router-dom');
|
|
@@ -175,6 +176,17 @@ jest.mock('../universal/routes', () => {
|
|
|
175
176
|
});
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
class RedirectWithStatusPage extends React.Component {
|
|
180
|
+
static getProps() {
|
|
181
|
+
return Promise.resolve();
|
|
182
|
+
}
|
|
183
|
+
render() {
|
|
184
|
+
return /*#__PURE__*/React.createElement(RedirectWithStatus, {
|
|
185
|
+
to: "/elsewhere/",
|
|
186
|
+
status: 301
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
178
190
|
class HelmetPage extends React.Component {
|
|
179
191
|
static getProps() {
|
|
180
192
|
return Promise.resolve();
|
|
@@ -289,6 +301,9 @@ jest.mock('../universal/routes', () => {
|
|
|
289
301
|
}, {
|
|
290
302
|
path: '/redirect/',
|
|
291
303
|
component: RedirectPage
|
|
304
|
+
}, {
|
|
305
|
+
path: '/redirectWithStatus/',
|
|
306
|
+
component: RedirectWithStatusPage
|
|
292
307
|
}, {
|
|
293
308
|
path: '/init-sets-status/',
|
|
294
309
|
component: InitSetsStatusPage
|
|
@@ -512,6 +527,14 @@ describe('The Node SSR Environment', () => {
|
|
|
512
527
|
assertions: res => {
|
|
513
528
|
expect(res.statusCode).toBe(302);
|
|
514
529
|
}
|
|
530
|
+
}, {
|
|
531
|
+
description: `can redirect with HTTP 301 status`,
|
|
532
|
+
req: {
|
|
533
|
+
url: '/redirectWithStatus/'
|
|
534
|
+
},
|
|
535
|
+
assertions: res => {
|
|
536
|
+
expect(res.statusCode).toBe(301);
|
|
537
|
+
}
|
|
515
538
|
}, {
|
|
516
539
|
description: `500 on unknown errors in getProps`,
|
|
517
540
|
req: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/ssr/universal/components/redirect-with-status/index.jsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactRouterDom = require("react-router-dom");
|
|
9
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
10
|
+
const _excluded = ["status", "staticContext"];
|
|
11
|
+
/*
|
|
12
|
+
* Copyright (c) 2024, Salesforce, Inc.
|
|
13
|
+
* All rights reserved.
|
|
14
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
15
|
+
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
16
|
+
*/
|
|
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 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
|
+
/**
|
|
21
|
+
* The `RedirectWithStatus` component is used to specify a different status code when redirecting via
|
|
22
|
+
* the Redirect component.
|
|
23
|
+
* The default redirect behavior when this component is not used is to set a 302 status.
|
|
24
|
+
*
|
|
25
|
+
* @param {number} status - The HTTP status code. Defaults to 302 if not specified
|
|
26
|
+
* @param {object} staticContext - The router context
|
|
27
|
+
* @param {string} to - The redirect's target path
|
|
28
|
+
*/
|
|
29
|
+
const RedirectWithStatus = _ref => {
|
|
30
|
+
let {
|
|
31
|
+
status = 302,
|
|
32
|
+
staticContext
|
|
33
|
+
} = _ref,
|
|
34
|
+
props = _objectWithoutProperties(_ref, _excluded);
|
|
35
|
+
// Handle server-side rendering
|
|
36
|
+
if (staticContext) {
|
|
37
|
+
staticContext.status = status;
|
|
38
|
+
}
|
|
39
|
+
return /*#__PURE__*/_react.default.createElement(_reactRouterDom.Redirect, props);
|
|
40
|
+
};
|
|
41
|
+
RedirectWithStatus.propTypes = {
|
|
42
|
+
status: _propTypes.default.number,
|
|
43
|
+
staticContext: _propTypes.default.object,
|
|
44
|
+
to: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object])
|
|
45
|
+
};
|
|
46
|
+
var _default = exports.default = (0, _reactRouterDom.withRouter)(RedirectWithStatus);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _react = _interopRequireDefault(require("react"));
|
|
4
|
+
var _react2 = require("@testing-library/react");
|
|
5
|
+
var _reactRouterDom = require("react-router-dom");
|
|
6
|
+
var _history = require("history");
|
|
7
|
+
var _index = _interopRequireDefault(require("./index"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
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
|
+
* Copyright (c) 2024, salesforce.com, 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
|
+
describe('RedirectWithStatus', () => {
|
|
17
|
+
test('Redirects if no status or context is provided', () => {
|
|
18
|
+
const targetUrl = '/target';
|
|
19
|
+
const history = (0, _history.createMemoryHistory)();
|
|
20
|
+
history.push('/redirect');
|
|
21
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_reactRouterDom.Router, {
|
|
22
|
+
history: history
|
|
23
|
+
}, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Route, {
|
|
24
|
+
path: "/redirect"
|
|
25
|
+
}, /*#__PURE__*/_react.default.createElement(_index.default, {
|
|
26
|
+
to: targetUrl
|
|
27
|
+
}))));
|
|
28
|
+
expect(history.location.pathname).toBe(targetUrl);
|
|
29
|
+
});
|
|
30
|
+
test('Redirect renders with correct status', /*#__PURE__*/_asyncToGenerator(function* () {
|
|
31
|
+
const context = {};
|
|
32
|
+
const status = 303;
|
|
33
|
+
const targetUrl = '/target';
|
|
34
|
+
(0, _react2.render)(/*#__PURE__*/_react.default.createElement(_reactRouterDom.StaticRouter, {
|
|
35
|
+
location: "/redirect",
|
|
36
|
+
context: context
|
|
37
|
+
}, /*#__PURE__*/_react.default.createElement(_reactRouterDom.Route, {
|
|
38
|
+
path: "/redirect"
|
|
39
|
+
}, /*#__PURE__*/_react.default.createElement(_index.default, {
|
|
40
|
+
status: status,
|
|
41
|
+
to: targetUrl
|
|
42
|
+
}))));
|
|
43
|
+
expect(context.status).toBe(status);
|
|
44
|
+
expect(context.url).toBe(targetUrl);
|
|
45
|
+
}));
|
|
46
|
+
});
|
|
@@ -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;
|