@zengenti/contensis-react-base 4.0.0-beta.8 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/cjs/{App-vZrUfVgQ.js → App-CNylISW7.js} +546 -104
- package/cjs/App-CNylISW7.js.map +1 -0
- package/cjs/{ChangePassword.container-ECjEXixF.js → ChangePassword.container-C4Du3Wb1.js} +57 -50
- package/cjs/ChangePassword.container-C4Du3Wb1.js.map +1 -0
- package/cjs/{SSRContext-DVj_QAC1.js → ContensisDeliveryApi-MfcvdfDR.js} +32 -74
- package/cjs/ContensisDeliveryApi-MfcvdfDR.js.map +1 -0
- package/cjs/CookieConstants-DfPiWCRZ.js +12 -0
- package/cjs/CookieConstants-DfPiWCRZ.js.map +1 -0
- package/{esm/CookieHelper.class-FTURFpz3.js → cjs/CookieHelper.class-Det3qfdU.js} +4 -6
- package/cjs/CookieHelper.class-Det3qfdU.js.map +1 -0
- package/cjs/{RouteLoader-D5Yg7EB5.js → RouteLoader-DJeM8cym.js} +17 -9
- package/cjs/RouteLoader-DJeM8cym.js.map +1 -0
- package/cjs/SSRContext-tMufQDHY.js +116 -0
- package/cjs/SSRContext-tMufQDHY.js.map +1 -0
- package/cjs/ToJs-BsWqWjdm.js +23 -0
- package/cjs/ToJs-BsWqWjdm.js.map +1 -0
- package/cjs/{VersionInfo-B_dKCubg.js → VersionInfo-zFPsvS8q.js} +3 -25
- package/cjs/VersionInfo-zFPsvS8q.js.map +1 -0
- package/cjs/client.js +63 -65
- package/cjs/client.js.map +1 -1
- package/cjs/contensis-react-base.js +223 -132
- package/cjs/contensis-react-base.js.map +1 -1
- package/cjs/i18n.js +75 -0
- package/cjs/i18n.js.map +1 -0
- package/cjs/{ToJs-C9jwV7YB.js → matchGroups-dqONU-vY.js} +2 -22
- package/cjs/matchGroups-dqONU-vY.js.map +1 -0
- package/cjs/redux.js +8 -6
- package/cjs/redux.js.map +1 -1
- package/cjs/routing.js +15 -7
- package/cjs/routing.js.map +1 -1
- package/cjs/{sagas-CbZhaRNd.js → sagas-BCy9u6zA.js} +523 -370
- package/cjs/sagas-BCy9u6zA.js.map +1 -0
- package/cjs/search.js +54 -29
- package/cjs/search.js.map +1 -1
- package/cjs/{selectors-wCs5fHD4.js → selectors-BrxJ8-F8.js} +27 -6
- package/cjs/selectors-BrxJ8-F8.js.map +1 -0
- package/cjs/selectors-DAQR0uZa.js +18 -0
- package/cjs/selectors-DAQR0uZa.js.map +1 -0
- package/cjs/slice-5xJMH24n.js +69 -0
- package/cjs/slice-5xJMH24n.js.map +1 -0
- package/cjs/{store-D07FOXvM.js → store-B7SJs5Hf.js} +64 -5
- package/cjs/store-B7SJs5Hf.js.map +1 -0
- package/cjs/urls-DGZlAs0y.js +25 -0
- package/cjs/urls-DGZlAs0y.js.map +1 -0
- package/cjs/user.js +20 -17
- package/cjs/user.js.map +1 -1
- package/cjs/util-eOjxDjxF.js +148 -0
- package/cjs/util-eOjxDjxF.js.map +1 -0
- package/cjs/util.js +80 -22
- package/cjs/util.js.map +1 -1
- package/cjs/{version-CM-bJ62L.js → version-rFG9Y6_B.js} +2 -2
- package/cjs/{version-CM-bJ62L.js.map → version-rFG9Y6_B.js.map} +1 -1
- package/cjs/{version-B7XFkBhY.js → version-yjHMrfVz.js} +15 -16
- package/cjs/version-yjHMrfVz.js.map +1 -0
- package/esm/{App-DLZweVSp.js → App-Bvs7Km54.js} +507 -66
- package/esm/App-Bvs7Km54.js.map +1 -0
- package/esm/{ChangePassword.container-BgzIy8dA.js → ChangePassword.container-CUBtn82K.js} +19 -13
- package/esm/ChangePassword.container-CUBtn82K.js.map +1 -0
- package/esm/{SSRContext-BE8ElZ3X.js → ContensisDeliveryApi-LWYXevZ1.js} +30 -67
- package/esm/ContensisDeliveryApi-LWYXevZ1.js.map +1 -0
- package/esm/CookieConstants-DEmbwzYr.js +7 -0
- package/esm/CookieConstants-DEmbwzYr.js.map +1 -0
- package/{cjs/CookieHelper.class-C3Eqoze9.js → esm/CookieHelper.class-C6rTRl_1.js} +2 -14
- package/esm/CookieHelper.class-C6rTRl_1.js.map +1 -0
- package/esm/{RouteLoader-xeQBXywk.js → RouteLoader-CzrlySZf.js} +14 -6
- package/esm/RouteLoader-CzrlySZf.js.map +1 -0
- package/esm/SSRContext-Bxtg1KGv.js +106 -0
- package/esm/SSRContext-Bxtg1KGv.js.map +1 -0
- package/esm/ToJs-BnRRHk6f.js +17 -0
- package/esm/ToJs-BnRRHk6f.js.map +1 -0
- package/esm/{VersionInfo-Cno7K0OA.js → VersionInfo-By2ZCZOh.js} +4 -24
- package/esm/VersionInfo-By2ZCZOh.js.map +1 -0
- package/esm/client.js +63 -64
- package/esm/client.js.map +1 -1
- package/esm/contensis-react-base.js +216 -127
- package/esm/contensis-react-base.js.map +1 -1
- package/esm/i18n.js +64 -0
- package/esm/i18n.js.map +1 -0
- package/esm/{ToJs-CNzfvyxJ.js → matchGroups-_w8BwzCC.js} +3 -18
- package/esm/matchGroups-_w8BwzCC.js.map +1 -0
- package/esm/redux.js +11 -8
- package/esm/redux.js.map +1 -1
- package/esm/routing.js +14 -7
- package/esm/routing.js.map +1 -1
- package/esm/{sagas-xJU-zOpn.js → sagas-Fr9yRduO.js} +511 -357
- package/esm/sagas-Fr9yRduO.js.map +1 -0
- package/esm/search.js +73 -47
- package/esm/search.js.map +1 -1
- package/esm/{selectors-DO2ocdOp.js → selectors-8ROQrTd7.js} +25 -7
- package/esm/selectors-8ROQrTd7.js.map +1 -0
- package/esm/selectors-DcmvOeX2.js +10 -0
- package/esm/selectors-DcmvOeX2.js.map +1 -0
- package/esm/slice-C6JLQik8.js +63 -0
- package/esm/slice-C6JLQik8.js.map +1 -0
- package/esm/{store-3u0RzHZ0.js → store-B4IrBYHm.js} +64 -6
- package/esm/store-B4IrBYHm.js.map +1 -0
- package/esm/urls-tLxo_skx.js +22 -0
- package/esm/urls-tLxo_skx.js.map +1 -0
- package/esm/user.js +9 -6
- package/esm/user.js.map +1 -1
- package/esm/util-Bl2u6LpY.js +136 -0
- package/esm/util-Bl2u6LpY.js.map +1 -0
- package/esm/util.js +58 -14
- package/esm/util.js.map +1 -1
- package/esm/{version-wnf-TITV.js → version-BQAL8sQO.js} +2 -2
- package/esm/{version-wnf-TITV.js.map → version-BQAL8sQO.js.map} +1 -1
- package/esm/{version-BlsI7hX2.js → version-CA9Mdm3A.js} +16 -16
- package/esm/version-CA9Mdm3A.js.map +1 -0
- package/i18n/package.json +5 -0
- package/models/app/pages/VersionInfo/components/VersionInfo.d.ts +1 -1
- package/models/app/pages/VersionInfo/components/VersionInfo.styled.d.ts +1 -2
- package/models/i18n/index.d.ts +5 -0
- package/models/i18n/redux/sagas.d.ts +19 -0
- package/models/i18n/redux/selectors.d.ts +11 -0
- package/models/i18n/redux/slice.d.ts +198 -0
- package/models/i18n/routes.d.ts +8 -0
- package/models/i18n/useI18n.hook.d.ts +20 -0
- package/models/index.d.ts +1 -0
- package/models/models/AppState.d.ts +2 -0
- package/models/models/ContentTypeMapping.d.ts +6 -1
- package/models/models/EntryMapper.d.ts +2 -1
- package/models/models/Locales.d.ts +11 -0
- package/models/models/MatchedRoute.d.ts +5 -1
- package/models/models/RouteComponent.d.ts +0 -1
- package/models/models/RouteNode.d.ts +4 -2
- package/models/models/SSRContext.d.ts +4 -4
- package/models/models/StaticRoute.d.ts +12 -1
- package/models/models/WithEvents.d.ts +8 -0
- package/models/models/config/AppConfig.d.ts +2 -0
- package/models/models/config/I18n.d.ts +38 -0
- package/models/models/config/ServerConfig.d.ts +14 -0
- package/models/redux/index.d.ts +2 -1
- package/models/redux/sagas/index.d.ts +3 -1
- package/models/redux/sagas/injector.d.ts +13 -0
- package/models/redux/store/injectors/index.d.ts +26 -0
- package/models/redux/store/injectors/inject.d.ts +24 -0
- package/models/redux/store/injectors/util.d.ts +2 -0
- package/models/redux/store/store.d.ts +13 -4
- package/models/redux/util.d.ts +1 -1
- package/models/routing/components/RouteLoader.d.ts +3 -3
- package/models/routing/httpContext.d.ts +0 -1
- package/models/routing/index.d.ts +1 -0
- package/models/routing/redux/actions.d.ts +1 -1
- package/models/routing/redux/invokeSearch.d.ts +22 -0
- package/models/routing/redux/selectors.d.ts +47 -4
- package/models/routing/util/expressions.d.ts +1 -1
- package/models/routing/util/find-contenttype-mapping.d.ts +3 -1
- package/models/search/containers/withListing.d.ts +1 -1
- package/models/search/containers/withSearch.d.ts +1 -1
- package/models/search/models/Queries.d.ts +3 -5
- package/models/search/models/Search.d.ts +43 -13
- package/models/search/models/SearchActions.d.ts +61 -18
- package/models/search/models/SearchProps.d.ts +11 -10
- package/models/search/models/SearchState.d.ts +23 -2
- package/models/search/models/SearchUtil.d.ts +3 -3
- package/models/search/redux/getIn.d.ts +2 -2
- package/models/search/redux/reducers.d.ts +3 -4
- package/models/search/redux/sagas.d.ts +13 -14
- package/models/search/redux/schema.d.ts +3 -3
- package/models/search/redux/selectors.d.ts +64 -42
- package/models/search/redux/util.d.ts +10 -1
- package/models/search/search/ContensisDeliveryApi.d.ts +6 -26
- package/models/search/search/expressions.d.ts +6 -4
- package/models/search/search/util.d.ts +9 -7
- package/models/search/transformations/state-to-queryparams.mapper.d.ts +1 -1
- package/models/server/features/linkdepth-api/search.d.ts +1 -1
- package/models/server/features/response-handler/render-stream.d.ts +2 -4
- package/models/server/features/static-assets/index.d.ts +4 -3
- package/models/server/internalServer.d.ts +1 -2
- package/models/server/middleware/subsiteDebug.d.ts +11 -0
- package/models/server/root.d.ts +3 -0
- package/models/server/util/bundles.d.ts +9 -9
- package/models/server/util/jsx.d.ts +2 -14
- package/models/user/components.styled/Login.styled.d.ts +1 -1
- package/models/user/components.styled/LoginForm.styled.d.ts +1 -1
- package/models/user/hocs/withRegistration.d.ts +1 -1
- package/models/util/CachedDeliveryApi.d.ts +8 -2
- package/models/util/ContensisDeliveryApi.d.ts +2 -4
- package/models/util/NoSSR.d.ts +6 -0
- package/models/util/SSRContext.d.ts +3 -19
- package/models/util/donotuse_useHistory.d.ts +6 -0
- package/models/util/errors.d.ts +16 -0
- package/models/util/index.d.ts +7 -2
- package/models/util/subsite.d.ts +12 -0
- package/models/util/urls.d.ts +1 -2
- package/models/util/useIsClient.d.ts +6 -0
- package/package.json +37 -39
- package/cjs/App-vZrUfVgQ.js.map +0 -1
- package/cjs/ChangePassword.container-ECjEXixF.js.map +0 -1
- package/cjs/CookieHelper.class-C3Eqoze9.js.map +0 -1
- package/cjs/RouteLoader-D5Yg7EB5.js.map +0 -1
- package/cjs/SSRContext-DVj_QAC1.js.map +0 -1
- package/cjs/ToJs-C9jwV7YB.js.map +0 -1
- package/cjs/VersionInfo-B_dKCubg.js.map +0 -1
- package/cjs/sagas-CbZhaRNd.js.map +0 -1
- package/cjs/selectors-wCs5fHD4.js.map +0 -1
- package/cjs/store-D07FOXvM.js.map +0 -1
- package/cjs/version-B7XFkBhY.js.map +0 -1
- package/esm/App-DLZweVSp.js.map +0 -1
- package/esm/ChangePassword.container-BgzIy8dA.js.map +0 -1
- package/esm/CookieHelper.class-FTURFpz3.js.map +0 -1
- package/esm/RouteLoader-xeQBXywk.js.map +0 -1
- package/esm/SSRContext-BE8ElZ3X.js.map +0 -1
- package/esm/ToJs-CNzfvyxJ.js.map +0 -1
- package/esm/VersionInfo-Cno7K0OA.js.map +0 -1
- package/esm/sagas-xJU-zOpn.js.map +0 -1
- package/esm/selectors-DO2ocdOp.js.map +0 -1
- package/esm/store-3u0RzHZ0.js.map +0 -1
- package/esm/version-BlsI7hX2.js.map +0 -1
- package/models/redux/store/injectors.d.ts +0 -31
- package/models/search/search/ToJs.d.ts +0 -4
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
import { c as cachedSearch,
|
|
1
|
+
import { c as cachedSearch, d as deliveryApi } from './ContensisDeliveryApi-LWYXevZ1.js';
|
|
2
2
|
import { Query as Query$1 } from 'contensis-delivery-api';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { Provider } from 'react-redux';
|
|
5
|
+
import { a as actions } from './slice-C6JLQik8.js';
|
|
5
6
|
import mapJson from 'jsonpath-mapper';
|
|
6
|
-
import {
|
|
7
|
+
import { a7 as defaultExpressions, a8 as termExpressions, a9 as contentTypeIdExpression, aa as filterExpressions, ab as orderByExpression, ac as customWhereExpressions, ad as cloneDeep } from './sagas-Fr9yRduO.js';
|
|
7
8
|
import 'reselect';
|
|
8
9
|
import 'immer';
|
|
9
10
|
import 'deep-equal';
|
|
10
11
|
import 'deepmerge';
|
|
11
12
|
import 'query-string';
|
|
12
13
|
import { Op, Query } from 'contensis-core-api';
|
|
13
|
-
import { s as setCachingHeaders, u as
|
|
14
|
+
import { s as setCachingHeaders, u as urls } from './urls-tLxo_skx.js';
|
|
14
15
|
import 'isomorphic-fetch';
|
|
15
16
|
import express from 'express';
|
|
16
17
|
import http from 'http';
|
|
17
18
|
import httpProxy from 'http-proxy';
|
|
19
|
+
import { s as shorten, c as createLocaleRoutes, h as history, p as pickProject, r as rootSaga } from './App-Bvs7Km54.js';
|
|
20
|
+
export { A as ReactApp } from './App-Bvs7Km54.js';
|
|
18
21
|
import fs from 'fs';
|
|
19
22
|
import path from 'path';
|
|
20
|
-
import
|
|
23
|
+
import appRootPath from 'app-root-path';
|
|
21
24
|
import { renderToPipeableStream, renderToString } from 'react-dom/server';
|
|
22
25
|
import { matchRoutes } from 'react-router-dom';
|
|
23
26
|
import { Helmet } from 'react-helmet';
|
|
@@ -25,32 +28,38 @@ import { ServerStyleSheet } from 'styled-components';
|
|
|
25
28
|
import serialize from 'serialize-javascript';
|
|
26
29
|
import { noop, identity } from 'lodash';
|
|
27
30
|
import { buildCleaner } from 'lodash-clean';
|
|
28
|
-
import { a as Cookies } from './CookieHelper.class-
|
|
31
|
+
import { a as Cookies } from './CookieHelper.class-C6rTRl_1.js';
|
|
29
32
|
import cookiesMiddleware from 'universal-cookie-express';
|
|
30
|
-
import { c as createStore } from './store-
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
import {
|
|
34
|
-
import { a3 as selectSurrogateKeys, a4 as selectSsrApiCalls, h as selectRouteEntry, n as selectCurrentProject, g as getImmutableOrJS, d as setCurrentProject, K as selectCurrentSearch } from './selectors-DO2ocdOp.js';
|
|
35
|
-
import { H as HttpContext, m as mergeStaticRoutes } from './RouteLoader-xeQBXywk.js';
|
|
33
|
+
import { c as createStore } from './store-B4IrBYHm.js';
|
|
34
|
+
import { s as setVersionStatus, c as setVersion } from './version-CA9Mdm3A.js';
|
|
35
|
+
import { a6 as selectSurrogateKeys, a7 as selectSsrApiCalls, j as selectRouteEntry, f as selectCurrentProject, g as getImmutableOrJS, s as setCurrentProject, F as selectCurrentSearch } from './selectors-8ROQrTd7.js';
|
|
36
|
+
import { H as HttpContext, m as mergeStaticRoutes } from './RouteLoader-CzrlySZf.js';
|
|
36
37
|
import { Transform } from 'stream';
|
|
37
38
|
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server';
|
|
38
39
|
import chalk from 'chalk';
|
|
39
40
|
import minifyCssString from 'minify-css-string';
|
|
40
41
|
import { CookiesProvider } from 'react-cookie';
|
|
42
|
+
import { HelmetProvider } from 'react-helmet-async';
|
|
41
43
|
import { StaticRouter } from 'react-router-dom/server';
|
|
44
|
+
import { S as SSRContextProvider, g as getSubsitePath } from './SSRContext-Bxtg1KGv.js';
|
|
45
|
+
import './VersionInfo-By2ZCZOh.js';
|
|
46
|
+
import './CookieConstants-DEmbwzYr.js';
|
|
47
|
+
import '@reduxjs/toolkit';
|
|
42
48
|
import 'loglevel';
|
|
43
49
|
import '@redux-saga/core/effects';
|
|
50
|
+
import './version-BQAL8sQO.js';
|
|
51
|
+
import './util-Bl2u6LpY.js';
|
|
52
|
+
import './selectors-DcmvOeX2.js';
|
|
44
53
|
import './_commonjsHelpers-BFTU3MAI.js';
|
|
45
|
-
import '
|
|
54
|
+
import 'history';
|
|
55
|
+
import 'await-to-js';
|
|
56
|
+
import 'redux-saga';
|
|
57
|
+
import './ChangePassword.container-CUBtn82K.js';
|
|
58
|
+
import './matchGroups-_w8BwzCC.js';
|
|
59
|
+
import './ToJs-BnRRHk6f.js';
|
|
46
60
|
import 'redux';
|
|
47
61
|
import 'redux-thunk';
|
|
48
|
-
import 'redux-saga';
|
|
49
62
|
import 'redux-injectors-19';
|
|
50
|
-
import 'history';
|
|
51
|
-
import 'await-to-js';
|
|
52
|
-
import './ChangePassword.container-BgzIy8dA.js';
|
|
53
|
-
import './ToJs-CNzfvyxJ.js';
|
|
54
63
|
|
|
55
64
|
/**
|
|
56
65
|
* Util class holds our search results helper boilerplate methods
|
|
@@ -610,42 +619,66 @@ const makeLinkDepthMiddleware = ({
|
|
|
610
619
|
}
|
|
611
620
|
};
|
|
612
621
|
|
|
622
|
+
/**
|
|
623
|
+
* Development proxy for Subsite PoC
|
|
624
|
+
* Catch all routes before they hit CRB handlers
|
|
625
|
+
* and rewrite them to include the subsite base path,
|
|
626
|
+
* this allows us to run the subsite in a subfolder in development
|
|
627
|
+
* In production we will handle this with a path rewrite in the Cloud Dashboard site configuration,
|
|
628
|
+
* @param subsitePath the content base path we will rewrite to
|
|
629
|
+
* @param exceptions an array of path prefixes to ignore when rewriting, useful for ignoring assets that do not live in the subsite base path
|
|
630
|
+
*/
|
|
631
|
+
const subsiteDebugMiddleware = (subsitePath, exceptions = []) => (req, res, next) => {
|
|
632
|
+
if (!subsitePath || req.hostname !== 'localhost' || req.path.startsWith('/api/') || exceptions.some(exception => req.path.startsWith(exception))) return next();
|
|
633
|
+
if (!req.path.startsWith(`${subsitePath}/`)) {
|
|
634
|
+
console.warn(`[subsite-debug-middleware] Rewriting (${subsitePath})${req.url}`);
|
|
635
|
+
if (req.path === '/' || req.path === subsitePath) req.url = subsitePath;else req.url = `${subsitePath}${req.url}`;
|
|
636
|
+
res.setHeader('x-crb-subsite-content-path', req.url);
|
|
637
|
+
|
|
638
|
+
// Important to set the subsite_path header as this drives the subsite-scoped routing logic
|
|
639
|
+
req.headers['subsite_path'] = subsitePath;
|
|
640
|
+
}
|
|
641
|
+
next();
|
|
642
|
+
};
|
|
643
|
+
|
|
613
644
|
const servers$1 = SERVERS; /* global SERVERS */
|
|
614
645
|
const project = PROJECT; /* global PROJECT */
|
|
615
646
|
const alias$1 = ALIAS; /* global ALIAS */
|
|
616
|
-
const deliveryApiHostname =
|
|
647
|
+
const deliveryApiHostname = urls(alias$1, project).api;
|
|
648
|
+
const proxyTimeoutMs = 45_000;
|
|
617
649
|
const assetProxy = httpProxy.createProxyServer();
|
|
618
650
|
const deliveryProxy = httpProxy.createProxyServer();
|
|
619
651
|
const reverseProxies = (app, reverseProxyPaths = []) => {
|
|
620
652
|
deliveryApiProxy(deliveryProxy, app);
|
|
621
|
-
app.all(reverseProxyPaths
|
|
622
|
-
|
|
653
|
+
app.all(reverseProxyPaths.map(proxyPath =>
|
|
654
|
+
// Patch to update paths for express v5
|
|
655
|
+
proxyPath.endsWith('/*') ? `${proxyPath.slice(0, -2)}/{*splat}` : proxyPath.endsWith('/**') ? `${proxyPath.slice(0, -3)}/{*splat}` : proxyPath), (req, res) => {
|
|
656
|
+
const target = req.hostname.includes('preview-') || req.hostname.includes('preview.') || req.hostname === 'localhost' ? servers$1.previewIis || servers$1.iis : servers$1.iis;
|
|
623
657
|
assetProxy.web(req, res, {
|
|
624
658
|
target,
|
|
625
|
-
changeOrigin: true
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
/* eslint-disable no-console */
|
|
629
|
-
console.log(`Proxy Request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
630
|
-
/* eslint-enable no-console */
|
|
659
|
+
changeOrigin: true,
|
|
660
|
+
proxyTimeout: proxyTimeoutMs,
|
|
661
|
+
timeout: proxyTimeoutMs
|
|
631
662
|
});
|
|
632
663
|
});
|
|
664
|
+
assetProxy.on('error', (e, req) => {
|
|
665
|
+
console.log(`[assetProxy] "${req.method} ${req.url}" host: ${req.headers.host} failed with ${e}`);
|
|
666
|
+
});
|
|
633
667
|
};
|
|
634
668
|
const deliveryApiProxy = (apiProxy, app) => {
|
|
635
669
|
// This is just here to stop cors requests on localhost. In Production this is mapped using varnish.
|
|
636
|
-
app.all(['/api/delivery
|
|
637
|
-
|
|
638
|
-
console.log(`Proxying api request to ${servers$1.alias}`);
|
|
670
|
+
app.all(['/api/delivery/{*splat}', '/api/forms/{*splat}', '/api/image/{*splat}', '/authenticate/{*splat}'], (req, res) => {
|
|
671
|
+
console.log(`[apiProxy] "${req.method} ${shorten(req.url)}" target: ${servers$1.alias}`);
|
|
639
672
|
apiProxy.web(req, res, {
|
|
640
673
|
target: deliveryApiHostname,
|
|
641
|
-
changeOrigin: true
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
/* eslint-disable no-console */
|
|
645
|
-
console.log(`Proxy request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
646
|
-
/* eslint-enable no-console */
|
|
674
|
+
changeOrigin: true,
|
|
675
|
+
proxyTimeout: proxyTimeoutMs,
|
|
676
|
+
timeout: proxyTimeoutMs
|
|
647
677
|
});
|
|
648
678
|
});
|
|
679
|
+
apiProxy.on('error', (e, req) => {
|
|
680
|
+
console.log(`[apiProxy] "${req.method} ${req.url}" host: ${req.headers.host} failed with ${e}`);
|
|
681
|
+
});
|
|
649
682
|
};
|
|
650
683
|
|
|
651
684
|
const CacheDuration = {
|
|
@@ -720,9 +753,8 @@ const resolveStartupMiddleware = ({
|
|
|
720
753
|
if (maxage) res.set('Cache-Control', `public, max-age=${maxage}`);
|
|
721
754
|
res.sendFile(startupFileLocation);
|
|
722
755
|
} catch (sendFileError) {
|
|
723
|
-
// eslint-disable-next-line no-console
|
|
724
756
|
console.log(`Unable to send file startup.js at '${startupFileLocation}'`, sendFileError);
|
|
725
|
-
|
|
757
|
+
res.status(404).send();
|
|
726
758
|
}
|
|
727
759
|
} else {
|
|
728
760
|
next();
|
|
@@ -730,8 +762,11 @@ const resolveStartupMiddleware = ({
|
|
|
730
762
|
};
|
|
731
763
|
|
|
732
764
|
// Serving static assets
|
|
765
|
+
const {
|
|
766
|
+
path: appPath
|
|
767
|
+
} = appRootPath;
|
|
733
768
|
const staticAssets = (app, {
|
|
734
|
-
appRootPath =
|
|
769
|
+
appRootPath = appPath,
|
|
735
770
|
scripts = {},
|
|
736
771
|
startupScriptFilename = 'startup.js',
|
|
737
772
|
staticFolderPath = 'static',
|
|
@@ -750,9 +785,7 @@ const staticAssets = (app, {
|
|
|
750
785
|
maxage: CacheDuration.static,
|
|
751
786
|
startupScriptFilename: scripts.startup || startupScriptFilename,
|
|
752
787
|
staticFolderPath
|
|
753
|
-
}),
|
|
754
|
-
// eslint-disable-next-line import/no-named-as-default-member
|
|
755
|
-
express.static(`dist/${staticFolderPath}`, {
|
|
788
|
+
}), express.static(`dist/${staticFolderPath}`, {
|
|
756
789
|
// these maxage values are different in config but the same in runtime,
|
|
757
790
|
// this one is somehow converted and should end up being the same as CacheDuration.static
|
|
758
791
|
maxAge: CacheDuration.expressStatic
|
|
@@ -802,7 +835,31 @@ const handleResponse = (request, response, content, send = 'send') => {
|
|
|
802
835
|
* @param response the express Response object
|
|
803
836
|
* @param stream all chunks are piped to this stream to add additional style elements to each streamed chunk
|
|
804
837
|
*/
|
|
805
|
-
const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
838
|
+
const renderStream = (getContextHtml, jsx, request, response, stream) => {
|
|
839
|
+
// Store timeout reference for cleanup on normal or abnormal termination
|
|
840
|
+
let timeoutId = null;
|
|
841
|
+
const disposeTimeout = () => {
|
|
842
|
+
if (timeoutId) {
|
|
843
|
+
clearTimeout(timeoutId);
|
|
844
|
+
timeoutId = null;
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// Only used for abnormal termination
|
|
849
|
+
const abortCleanup = err => {
|
|
850
|
+
disposeTimeout();
|
|
851
|
+
stream.destroy(err instanceof Error ? err : undefined);
|
|
852
|
+
abort();
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
// Guard against client disconnect
|
|
856
|
+
request.on('close', () => abortCleanup());
|
|
857
|
+
|
|
858
|
+
// Guard against transform errors
|
|
859
|
+
stream.on('error', err => {
|
|
860
|
+
abortCleanup(err);
|
|
861
|
+
if (!response.headersSent) response.destroy(err);
|
|
862
|
+
});
|
|
806
863
|
const {
|
|
807
864
|
abort,
|
|
808
865
|
pipe
|
|
@@ -811,7 +868,7 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
811
868
|
const html = getContextHtml(false);
|
|
812
869
|
if (!html) {
|
|
813
870
|
// this means we have finished with the response already
|
|
814
|
-
|
|
871
|
+
abortCleanup();
|
|
815
872
|
} else {
|
|
816
873
|
const header = html.split('{{APP}}')[0];
|
|
817
874
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
@@ -822,11 +879,15 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
822
879
|
onAllReady() {
|
|
823
880
|
const footer = getContextHtml(true).split('{{APP}}')[1];
|
|
824
881
|
stream.write(footer);
|
|
882
|
+
disposeTimeout(); // Clear the timeout, let stream end naturally
|
|
825
883
|
},
|
|
826
884
|
onShellError(error) {
|
|
827
|
-
|
|
828
|
-
response.
|
|
829
|
-
|
|
885
|
+
abortCleanup(error); // Abnormal - destroy everything
|
|
886
|
+
if (!response.headersSent) {
|
|
887
|
+
response.statusCode = 500;
|
|
888
|
+
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
889
|
+
response.send('<h1>Something went wrong</h1>');
|
|
890
|
+
}
|
|
830
891
|
console.error(`[renderToPipeableStream:onShellError]`, error);
|
|
831
892
|
},
|
|
832
893
|
onError(error) {
|
|
@@ -834,10 +895,13 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
834
895
|
}
|
|
835
896
|
});
|
|
836
897
|
|
|
837
|
-
// Abandon and switch to client rendering
|
|
898
|
+
// Abandon and switch to client rendering after 30s.
|
|
838
899
|
// Try lowering this to see the client recover.
|
|
839
|
-
setTimeout(() =>
|
|
840
|
-
|
|
900
|
+
timeoutId = setTimeout(() => {
|
|
901
|
+
timeoutId = null;
|
|
902
|
+
abortCleanup();
|
|
903
|
+
}, 30_000);
|
|
904
|
+
stream.pipe(response);
|
|
841
905
|
};
|
|
842
906
|
|
|
843
907
|
/**
|
|
@@ -877,6 +941,23 @@ const styledComponentsStream = sheet => {
|
|
|
877
941
|
this.push(styledCSS + renderedHtml);
|
|
878
942
|
}
|
|
879
943
|
callback();
|
|
944
|
+
},
|
|
945
|
+
destroy(err, callback) {
|
|
946
|
+
// Called on both stream.destroy() and natural end
|
|
947
|
+
// Stops the sheet intercepting styles & releases its references
|
|
948
|
+
|
|
949
|
+
// try/catch is required if sheet.seal() throws for any reason,
|
|
950
|
+
// callback(err) must still be called, as Node.js stream internals depend
|
|
951
|
+
// on it to complete teardown. Omitting it causes the stream to hang.
|
|
952
|
+
try {
|
|
953
|
+
sheet.seal();
|
|
954
|
+
} catch (sealErr) {
|
|
955
|
+
// Catch any errors from sealing the sheet, we MUST always call the
|
|
956
|
+
// callback to prevent hanging the stream
|
|
957
|
+
|
|
958
|
+
console.error('[styledComponentsStream] sheet.seal() failed - styles may leak:', sealErr);
|
|
959
|
+
}
|
|
960
|
+
callback(err);
|
|
880
961
|
}
|
|
881
962
|
});
|
|
882
963
|
return readerWriter;
|
|
@@ -1038,6 +1119,7 @@ const unhandledExceptionHandler = (handleExceptions = handleDefaultEvents) => {
|
|
|
1038
1119
|
}
|
|
1039
1120
|
};
|
|
1040
1121
|
|
|
1122
|
+
const logPrefix = '[addHeaders]';
|
|
1041
1123
|
const addStandardHeaders = (state, response, packagejson, groups) => {
|
|
1042
1124
|
if (state) {
|
|
1043
1125
|
try {
|
|
@@ -1051,14 +1133,14 @@ const addStandardHeaders = (state, response, packagejson, groups) => {
|
|
|
1051
1133
|
// - add `any-update` header that will indiscriminately
|
|
1052
1134
|
// invalidate the SSR page cache when any content is updated
|
|
1053
1135
|
const addAnyUpdateHeader = routingSurrogateKeys.length >= 2000 || response.statusCode >= 400 || anyApiError;
|
|
1054
|
-
console.info(
|
|
1136
|
+
console.info(`${logPrefix} ${addAnyUpdateHeader ? anyUpdateHeader : routingSurrogateKeys.length} surrogate keys for ${response.req.url}`);
|
|
1055
1137
|
const surrogateKeys = addAnyUpdateHeader ? anyUpdateHeader : routingSurrogateKeys.join(' ');
|
|
1056
1138
|
const surrogateKeyHeader = `${packagejson.name}-app ${surrogateKeys}`;
|
|
1057
1139
|
response.setHeader('surrogate-key', surrogateKeyHeader);
|
|
1058
1140
|
addVarnishAuthenticationHeaders(state, response, groups);
|
|
1059
1141
|
response.setHeader('surrogate-control', `max-age=${getCacheDuration(response.statusCode)}`);
|
|
1060
1142
|
} catch (e) {
|
|
1061
|
-
console.info(
|
|
1143
|
+
console.info(`${logPrefix} Error adding headers`, e.message);
|
|
1062
1144
|
}
|
|
1063
1145
|
}
|
|
1064
1146
|
};
|
|
@@ -1071,14 +1153,13 @@ const addVarnishAuthenticationHeaders = (state, response, groups = {}) => {
|
|
|
1071
1153
|
globalGroups,
|
|
1072
1154
|
allowedGroups
|
|
1073
1155
|
} = groups;
|
|
1074
|
-
// console.info(globalGroups, allowedGroups);
|
|
1075
1156
|
let allGroups = Array.from(globalGroups && globalGroups[project] || {});
|
|
1076
1157
|
if (stateEntry && getImmutableOrJS(stateEntry, ['authentication', 'isLoginRequired']) && allowedGroups && allowedGroups[project]) {
|
|
1077
1158
|
allGroups = [...allGroups, ...allowedGroups[project]];
|
|
1078
1159
|
}
|
|
1079
1160
|
response.header('x-contensis-viewer-groups', allGroups.join('|'));
|
|
1080
1161
|
} catch (e) {
|
|
1081
|
-
console.info(
|
|
1162
|
+
console.info(`${logPrefix} Error adding authentication header`, e);
|
|
1082
1163
|
}
|
|
1083
1164
|
}
|
|
1084
1165
|
};
|
|
@@ -1155,13 +1236,15 @@ const replaceHtml = ({
|
|
|
1155
1236
|
*/
|
|
1156
1237
|
const ssrJsxProducer = (ReactApp, {
|
|
1157
1238
|
providers,
|
|
1158
|
-
props
|
|
1159
|
-
ssrAssets
|
|
1239
|
+
props
|
|
1240
|
+
// ssrAssets,
|
|
1160
1241
|
}) => {
|
|
1161
1242
|
var _providers$styledComp;
|
|
1162
1243
|
// Recast ChunkExtractorManager to avoid TS error `Property 'children' does not exist on type...`
|
|
1163
1244
|
const ChunkExtractor = ChunkExtractorManager;
|
|
1164
|
-
const jsx = /*#__PURE__*/React.createElement(
|
|
1245
|
+
const jsx = /*#__PURE__*/React.createElement(HelmetProvider, {
|
|
1246
|
+
context: providers.helmet
|
|
1247
|
+
}, /*#__PURE__*/React.createElement(ChunkExtractor, {
|
|
1165
1248
|
extractor: providers.loadable.extractor
|
|
1166
1249
|
}, /*#__PURE__*/React.createElement(CookiesProvider, {
|
|
1167
1250
|
cookies: providers.cookies
|
|
@@ -1170,16 +1253,20 @@ const ssrJsxProducer = (ReactApp, {
|
|
|
1170
1253
|
}, /*#__PURE__*/React.createElement(HttpContext.Provider, {
|
|
1171
1254
|
value: providers.httpContext
|
|
1172
1255
|
}, /*#__PURE__*/React.createElement(StaticRouter, {
|
|
1173
|
-
location: providers.router.url
|
|
1256
|
+
location: providers.router.url,
|
|
1257
|
+
future: {
|
|
1258
|
+
v7_startTransition: true,
|
|
1259
|
+
v7_relativeSplatPath: true
|
|
1260
|
+
}
|
|
1174
1261
|
}, /*#__PURE__*/React.createElement(SSRContextProvider, {
|
|
1175
1262
|
accessMethod: providers.ssrContext.accessMethod,
|
|
1176
1263
|
request: providers.ssrContext.request,
|
|
1177
|
-
response: providers.ssrContext.response
|
|
1178
|
-
|
|
1264
|
+
response: providers.ssrContext.response
|
|
1265
|
+
// ssrAssets={ssrAssets}
|
|
1179
1266
|
}, /*#__PURE__*/React.createElement(ReactApp, {
|
|
1180
1267
|
routes: props.routes,
|
|
1181
1268
|
withEvents: props.withEvents
|
|
1182
|
-
})))))));
|
|
1269
|
+
}))))))));
|
|
1183
1270
|
|
|
1184
1271
|
// Wrap the JSX in a StyleSheetManager if a ServerStyleSheet is provided
|
|
1185
1272
|
return !((_providers$styledComp = providers.styledComponents) !== null && _providers$styledComp !== void 0 && _providers$styledComp.sheet) ? jsx : providers.styledComponents.sheet.collectStyles(jsx);
|
|
@@ -1201,8 +1288,12 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1201
1288
|
disableSsrRedux,
|
|
1202
1289
|
enableSsrCookies,
|
|
1203
1290
|
handleResponses,
|
|
1204
|
-
handleExceptions = true
|
|
1291
|
+
handleExceptions = true,
|
|
1292
|
+
i18n
|
|
1205
1293
|
} = config;
|
|
1294
|
+
|
|
1295
|
+
// process locales in static routes for i18n
|
|
1296
|
+
const localeRoutes = createLocaleRoutes(routes);
|
|
1206
1297
|
const staticRoutePath = config.staticRoutePath || staticFolderPath;
|
|
1207
1298
|
let isRenderingJsxToString = config.renderToString || false;
|
|
1208
1299
|
const bundleData = getBundleData(config, staticRoutePath);
|
|
@@ -1216,8 +1307,16 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1216
1307
|
if (handleExceptions !== false) unhandledExceptionHandler(handleExceptions); // Create `process.on` event handlers for unhandled exceptions (Node v15+)
|
|
1217
1308
|
|
|
1218
1309
|
const versionInfo = getVersionInfo(staticFolderPath);
|
|
1219
|
-
app.get('
|
|
1220
|
-
|
|
1310
|
+
app.get('/{*splat}', cookiesMiddleware(), async (request, response) => {
|
|
1311
|
+
/*
|
|
1312
|
+
* Do not inject url directly into HTML as it can lead to XSS attacks
|
|
1313
|
+
* CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
|
|
1314
|
+
* CWE-96: Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)
|
|
1315
|
+
* Removed URL encoding as it causes inconsistencies when routes contain encoded characters in SSR
|
|
1316
|
+
* e.g. /search?category=sport%20and%20wellbeing becomes /search?category=sport%2520and%2520wellbeing
|
|
1317
|
+
* // const url = encodeURI(request.url);
|
|
1318
|
+
*/
|
|
1319
|
+
const url = request.url;
|
|
1221
1320
|
const matchedStaticRoute = matchRoutes(routes.StaticRoutes, request.path);
|
|
1222
1321
|
const isStaticRoute = matchedStaticRoute && matchedStaticRoute.length > 0;
|
|
1223
1322
|
if (isStaticRoute) {
|
|
@@ -1257,25 +1356,22 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1257
1356
|
// In server-side blocks world, the hostname requested by the client resides in the x-orig-host header
|
|
1258
1357
|
// Because of this, we prioritize x-orig-host when setting our hostname
|
|
1259
1358
|
const hostname = request.headers['x-orig-host'] || request.hostname;
|
|
1260
|
-
|
|
1359
|
+
const subsitePath = getSubsitePath(request);
|
|
1360
|
+
const subsitePathScript = subsitePath ? `window.subsitePath = ${serialize(subsitePath)};` : '';
|
|
1361
|
+
console.info(`[webApp] "${request.method} ${request.path}" hostname: ${hostname} versionStatus: ${versionStatus}`);
|
|
1261
1362
|
store.dispatch(setVersionStatus(versionStatus));
|
|
1262
1363
|
store.dispatch(setVersion(versionInfo.commitRef, versionInfo.buildNo));
|
|
1263
1364
|
const project = pickProject(hostname, request.query);
|
|
1264
1365
|
const groups = allowedGroups && allowedGroups[project];
|
|
1265
1366
|
store.dispatch(setCurrentProject(project, groups, hostname));
|
|
1367
|
+
if (i18n) {
|
|
1368
|
+
store.dispatch(actions.INIT_LOCALES({
|
|
1369
|
+
locales: {},
|
|
1370
|
+
routes: localeRoutes,
|
|
1371
|
+
...i18n
|
|
1372
|
+
}));
|
|
1373
|
+
}
|
|
1266
1374
|
const loadableExtractor = loadableChunkExtractors();
|
|
1267
|
-
|
|
1268
|
-
// type ChunkExtractorManagerPropsForReact18 = ChunkExtractorManagerProps & {
|
|
1269
|
-
// children?: React.ReactNode;
|
|
1270
|
-
// };
|
|
1271
|
-
|
|
1272
|
-
// // Recast ChunkExtractorManager to avoid TS error `Property 'children' does not exist on type...`
|
|
1273
|
-
// const ChunkExtractor = ChunkExtractorManager as ClassType<
|
|
1274
|
-
// ChunkExtractorManagerPropsForReact18,
|
|
1275
|
-
// Component<ChunkExtractorManagerPropsForReact18>,
|
|
1276
|
-
// ComponentClass<ChunkExtractorManagerPropsForReact18>
|
|
1277
|
-
// >;
|
|
1278
|
-
|
|
1279
1375
|
const ssrCookies = enableSsrCookies ?
|
|
1280
1376
|
// these cookies are managed by the cookiesMiddleware and contain listeners
|
|
1281
1377
|
// when cookies are read or written in ssr can be added to the `set-cookie` response header
|
|
@@ -1290,12 +1386,17 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1290
1386
|
// and read back any context props set by the ReactApp
|
|
1291
1387
|
const context = {};
|
|
1292
1388
|
|
|
1389
|
+
// Per-request helmet context object — populated by HelmetProvider during renderToString
|
|
1390
|
+
// Using a fresh object per request ensures thread safety under concurrent SSR requests
|
|
1391
|
+
const helmetContext = {};
|
|
1392
|
+
|
|
1293
1393
|
// Amalgamate all props for the various Providers we wrap the ReactApp with
|
|
1294
1394
|
const jsxProviderProps = {
|
|
1295
1395
|
loadable: {
|
|
1296
1396
|
extractor: loadableExtractor.commonLoadableExtractor
|
|
1297
1397
|
},
|
|
1298
1398
|
cookies: ssrCookies,
|
|
1399
|
+
helmet: helmetContext,
|
|
1299
1400
|
redux: store,
|
|
1300
1401
|
httpContext: context,
|
|
1301
1402
|
router: {
|
|
@@ -1325,13 +1426,10 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1325
1426
|
// Dynamic doesn't need sagas
|
|
1326
1427
|
// or styles, or any split component bundles
|
|
1327
1428
|
// nor are we streaming responses
|
|
1328
|
-
const isDynamicHints = `<script ${attributes}>window.
|
|
1429
|
+
const isDynamicHints = `<script ${attributes}>window.isDynamic = true; ${subsitePathScript}</script>`;
|
|
1329
1430
|
const jsx = ssrJsxProducer(ReactApp, {
|
|
1330
1431
|
providers: jsxProviderProps,
|
|
1331
|
-
props: jsxReactAppProps
|
|
1332
|
-
ssrAssets: {
|
|
1333
|
-
serializedState: isDynamicHints
|
|
1334
|
-
}
|
|
1432
|
+
props: jsxReactAppProps
|
|
1335
1433
|
});
|
|
1336
1434
|
renderToString(jsx);
|
|
1337
1435
|
|
|
@@ -1390,10 +1488,7 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1390
1488
|
return true;
|
|
1391
1489
|
}
|
|
1392
1490
|
if (!disableSsrRedux) {
|
|
1393
|
-
|
|
1394
|
-
// where a consumer may not be using the contensisVersionStatus in redux and calling
|
|
1395
|
-
// the `getClientSideVersionStatus()` method directly
|
|
1396
|
-
serialisedReduxData = `<script ${attributes}>window.versionStatus = "${versionStatus}"; window.REDUX_DATA = ${serialisedReduxData}</script>`;
|
|
1491
|
+
serialisedReduxData = `<script ${attributes}>${subsitePathScript} window.__USE_HYDRATE__ = true; window.REDUX_DATA = ${serialisedReduxData}</script>`;
|
|
1397
1492
|
}
|
|
1398
1493
|
}
|
|
1399
1494
|
|
|
@@ -1403,32 +1498,6 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1403
1498
|
globalGroups
|
|
1404
1499
|
});
|
|
1405
1500
|
const sheet = new ServerStyleSheet();
|
|
1406
|
-
const helmet = Helmet.renderStatic();
|
|
1407
|
-
Helmet.rewind();
|
|
1408
|
-
// const htmlAttributes = helmet.htmlAttributes.toString();
|
|
1409
|
-
// let title = helmet.title.toString();
|
|
1410
|
-
// const metadata = helmet.meta
|
|
1411
|
-
// .toString()
|
|
1412
|
-
// .concat(helmet.base.toString())
|
|
1413
|
-
// .concat(helmet.link.toString())
|
|
1414
|
-
// .concat(helmet.script.toString())
|
|
1415
|
-
// .concat(helmet.noscript.toString());
|
|
1416
|
-
|
|
1417
|
-
// // Produce the ssr jsx one time so we can get any style tags to pass back in
|
|
1418
|
-
// ssrJsxProducer(ReactApp, {
|
|
1419
|
-
// providers: { ...jsxProviderProps, styledComponents: { sheet } },
|
|
1420
|
-
// props: jsxReactAppProps,
|
|
1421
|
-
// });
|
|
1422
|
-
|
|
1423
|
-
// // After running rootSaga (and rendering subsquent children)
|
|
1424
|
-
// // there should be additional react-loadable
|
|
1425
|
-
// // code-split bundles for any page components as well as core app bundles
|
|
1426
|
-
// const bundleTags = getBundleTags(
|
|
1427
|
-
// loadableExtractor,
|
|
1428
|
-
// scripts,
|
|
1429
|
-
// staticRoutePath
|
|
1430
|
-
// );
|
|
1431
|
-
|
|
1432
1501
|
const styledJsx = ssrJsxProducer(ReactApp, {
|
|
1433
1502
|
providers: {
|
|
1434
1503
|
...jsxProviderProps,
|
|
@@ -1436,14 +1505,31 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1436
1505
|
sheet
|
|
1437
1506
|
}
|
|
1438
1507
|
},
|
|
1439
|
-
props: jsxReactAppProps
|
|
1440
|
-
ssrAssets: {
|
|
1441
|
-
// bundleTags,
|
|
1442
|
-
// htmlAttributes,
|
|
1443
|
-
// metadata,
|
|
1444
|
-
// title,
|
|
1445
|
-
}
|
|
1508
|
+
props: jsxReactAppProps
|
|
1446
1509
|
});
|
|
1510
|
+
|
|
1511
|
+
// We have to call renderToString() in order for all components to have
|
|
1512
|
+
// had chance to set the helmet metadata
|
|
1513
|
+
const html = renderToString(styledJsx);
|
|
1514
|
+
// Helmet.renderStatic() has to be called synchronously immediately after calling renderToString()
|
|
1515
|
+
// as it is not thread-safe (or specifically scoped to only this request)
|
|
1516
|
+
// TODO: deprecate `react-helmet`
|
|
1517
|
+
const helmet = Helmet.renderStatic();
|
|
1518
|
+
|
|
1519
|
+
// helmetContext is populated synchronously by HelmetProvider during renderToString()
|
|
1520
|
+
// It is scoped per-request via the helmetContext object, making this thread-safe
|
|
1521
|
+
// under concurrent SSR requests (unlike the previous Helmet.renderStatic() global singleton)
|
|
1522
|
+
const {
|
|
1523
|
+
helmet: helmetAsync
|
|
1524
|
+
} = helmetContext;
|
|
1525
|
+
|
|
1526
|
+
// Because we have had to call renderToString() here to reliably gather all helmet metadata
|
|
1527
|
+
// We could potentially call sheet.getStyleTags() here too and avoid piping a react-rendered
|
|
1528
|
+
// stream to a second stream to inject styled-components CSS
|
|
1529
|
+
|
|
1530
|
+
const htmlAttributes = helmetAsync.htmlAttributes.toString() || helmet.htmlAttributes.toString();
|
|
1531
|
+
let title = helmet.title.toString().includes('><') ? helmetAsync.title.toString() : helmet.title.toString();
|
|
1532
|
+
const metadata = helmetAsync.meta.toString().concat(helmetAsync.base.toString()).concat(helmetAsync.priority.toString()).concat(helmetAsync.link.toString()).concat(helmetAsync.script.toString()).concat(helmetAsync.noscript.toString()).concat(helmet.meta.toString()).concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1447
1533
|
try {
|
|
1448
1534
|
/**
|
|
1449
1535
|
* Loads all page assets into the provided templateHTML
|
|
@@ -1455,6 +1541,7 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1455
1541
|
* if the context has requested a redirect
|
|
1456
1542
|
* */
|
|
1457
1543
|
const getContextHtml = (isFinal = false, styleTags, renderedJsxMarkup) => {
|
|
1544
|
+
var _loadableExtractor$mo;
|
|
1458
1545
|
if (context.url) {
|
|
1459
1546
|
response.redirect(context.statusCode || 302, context.url);
|
|
1460
1547
|
return '';
|
|
@@ -1464,23 +1551,23 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1464
1551
|
if ((context.statusCode || 200) >= 404) {
|
|
1465
1552
|
accessMethod.STATIC = true;
|
|
1466
1553
|
}
|
|
1467
|
-
|
|
1468
|
-
// Title and metadata can be blank
|
|
1469
|
-
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
1470
|
-
let title = helmet.title.toString();
|
|
1471
|
-
const metadata = helmet.meta.toString().concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1472
1554
|
if (context.statusCode === 404) title = '<title>404 page not found</title>';
|
|
1473
1555
|
|
|
1474
1556
|
// Set response.status from React StaticRouter
|
|
1475
1557
|
if (typeof context.statusCode === 'number') response.status(context.statusCode);
|
|
1476
1558
|
const bundleTags = isFinal ? getBundleTags(loadableExtractor, scripts, staticRoutePath) : '';
|
|
1559
|
+
|
|
1560
|
+
// Getting style tags generated by "CSS Modules" because they will be
|
|
1561
|
+
// available to loadable stats if we have built parts of the app with CSS
|
|
1562
|
+
// plugins that are not within styled-components
|
|
1563
|
+
const styles = loadableExtractor === null || loadableExtractor === void 0 || (_loadableExtractor$mo = loadableExtractor.modern) === null || _loadableExtractor$mo === void 0 ? void 0 : _loadableExtractor$mo.getStyleTags();
|
|
1477
1564
|
const html = replaceHtml({
|
|
1478
1565
|
bundleTags,
|
|
1479
1566
|
html: renderedJsxMarkup,
|
|
1480
1567
|
htmlAttributes,
|
|
1481
1568
|
metadata,
|
|
1482
1569
|
state: serialisedReduxData,
|
|
1483
|
-
styleTags
|
|
1570
|
+
styleTags: `${styleTags || ''}${styles || ''}`,
|
|
1484
1571
|
title,
|
|
1485
1572
|
templateHTML,
|
|
1486
1573
|
templateHTMLFragment,
|
|
@@ -1489,12 +1576,14 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1489
1576
|
return html;
|
|
1490
1577
|
};
|
|
1491
1578
|
if (isRenderingJsxToString) {
|
|
1492
|
-
|
|
1579
|
+
// We have already (begrudgingly) rendered the JSX to a string above
|
|
1580
|
+
// so we can get all of the Helmet metadata out from any rendered component
|
|
1581
|
+
// const html = renderToString(styledJsx);
|
|
1493
1582
|
const styleTags = sheet.getStyleTags();
|
|
1494
1583
|
const responseHTML = getContextHtml(true, styleTags, html);
|
|
1495
1584
|
responseHandler(request, response, responseHTML);
|
|
1496
1585
|
} else {
|
|
1497
|
-
renderStream(getContextHtml, styledJsx, response, styledComponentsStream(sheet));
|
|
1586
|
+
renderStream(getContextHtml, styledJsx, request, response, styledComponentsStream(sheet));
|
|
1498
1587
|
}
|
|
1499
1588
|
} catch (err) {
|
|
1500
1589
|
console.info(err.message);
|
|
@@ -1556,5 +1645,5 @@ var internalServer = {
|
|
|
1556
1645
|
start
|
|
1557
1646
|
};
|
|
1558
1647
|
|
|
1559
|
-
export { internalServer as default, makeLinkDepthApi as linkDepthApi };
|
|
1648
|
+
export { subsiteDebugMiddleware as DO_NOT_COMMIT_subsiteDebugMiddleware, internalServer as default, makeLinkDepthApi as linkDepthApi };
|
|
1560
1649
|
//# sourceMappingURL=contensis-react-base.js.map
|