@zengenti/contensis-react-base 3.3.2-beta.1 → 4.0.0-beta.10
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/cjs/{App-B2ohFzUt.js → App-vZrUfVgQ.js} +7 -20
- package/cjs/{App-B2ohFzUt.js.map → App-vZrUfVgQ.js.map} +1 -1
- package/cjs/{ChangePassword.container-Dup9_na7.js → ChangePassword.container-ECjEXixF.js} +2 -2
- package/cjs/{ChangePassword.container-Dup9_na7.js.map → ChangePassword.container-ECjEXixF.js.map} +1 -1
- package/cjs/CookieHelper.class-C3Eqoze9.js +471 -0
- package/cjs/CookieHelper.class-C3Eqoze9.js.map +1 -0
- package/cjs/{RouteLoader-De-dhkg-.js → RouteLoader-D5Yg7EB5.js} +143 -44
- package/cjs/RouteLoader-D5Yg7EB5.js.map +1 -0
- package/cjs/{SSRContext-DpnwQ2te.js → SSRContext-DVj_QAC1.js} +23 -9
- package/cjs/SSRContext-DVj_QAC1.js.map +1 -0
- package/cjs/ToJs-C9jwV7YB.js.map +1 -1
- package/cjs/VersionInfo-B_dKCubg.js +204 -0
- package/cjs/VersionInfo-B_dKCubg.js.map +1 -0
- package/cjs/client.js +53 -20
- package/cjs/client.js.map +1 -1
- package/cjs/contensis-react-base.js +409 -134
- package/cjs/contensis-react-base.js.map +1 -1
- package/cjs/fromJSLeaveImmer-Blvlk4t2.js.map +1 -1
- package/cjs/redux.js +3 -3
- package/cjs/routing.js +8 -7
- package/cjs/routing.js.map +1 -1
- package/cjs/{sagas-Ekfrk7xA.js → sagas-BVX4Ps1e.js} +326 -130
- package/cjs/sagas-BVX4Ps1e.js.map +1 -0
- package/cjs/search.js +3 -194
- package/cjs/search.js.map +1 -1
- package/cjs/selectors-wCs5fHD4.js.map +1 -1
- package/cjs/{store-BihH67lI.js → store-D07FOXvM.js} +6 -9
- package/cjs/store-D07FOXvM.js.map +1 -0
- package/cjs/user.js +2 -2
- package/cjs/user.js.map +1 -1
- package/cjs/util.js +17 -182
- package/cjs/util.js.map +1 -1
- package/cjs/{version-Cg79mdPg.js → version-B7XFkBhY.js} +2 -2
- package/{esm/version-BnnERhzW.js.map → cjs/version-B7XFkBhY.js.map} +1 -1
- package/cjs/version-CM-bJ62L.js.map +1 -1
- package/esm/{App-BPsH6nHc.js → App-DLZweVSp.js} +10 -23
- package/esm/{App-BPsH6nHc.js.map → App-DLZweVSp.js.map} +1 -1
- package/esm/{ChangePassword.container-Bcpef423.js → ChangePassword.container-BgzIy8dA.js} +5 -5
- package/esm/{ChangePassword.container-Bcpef423.js.map → ChangePassword.container-BgzIy8dA.js.map} +1 -1
- package/esm/CookieHelper.class-FTURFpz3.js +464 -0
- package/esm/CookieHelper.class-FTURFpz3.js.map +1 -0
- package/esm/{RouteLoader-CipkGOgr.js → RouteLoader-xeQBXywk.js} +143 -49
- package/esm/RouteLoader-xeQBXywk.js.map +1 -0
- package/esm/{SSRContext-3TvaCDn0.js → SSRContext-BE8ElZ3X.js} +26 -12
- package/esm/SSRContext-BE8ElZ3X.js.map +1 -0
- package/esm/{ToJs-B4MH53fx.js → ToJs-CNzfvyxJ.js} +3 -3
- package/esm/{ToJs-B4MH53fx.js.map → ToJs-CNzfvyxJ.js.map} +1 -1
- package/esm/VersionInfo-Cno7K0OA.js +193 -0
- package/esm/VersionInfo-Cno7K0OA.js.map +1 -0
- package/esm/client.js +57 -25
- package/esm/client.js.map +1 -1
- package/esm/contensis-react-base.js +407 -132
- package/esm/contensis-react-base.js.map +1 -1
- package/esm/fromJSLeaveImmer-C_YACmOf.js.map +1 -1
- package/esm/redux.js +8 -8
- package/esm/routing.js +7 -9
- package/esm/routing.js.map +1 -1
- package/esm/{sagas-Cd05ZBBH.js → sagas-JI51CS37.js} +311 -115
- package/esm/sagas-JI51CS37.js.map +1 -0
- package/esm/search.js +21 -212
- package/esm/search.js.map +1 -1
- package/esm/{selectors-BRzliwbK.js → selectors-DO2ocdOp.js} +2 -2
- package/esm/selectors-DO2ocdOp.js.map +1 -0
- package/esm/{store-f0WxNWUu.js → store-3u0RzHZ0.js} +7 -9
- package/esm/store-3u0RzHZ0.js.map +1 -0
- package/esm/user.js +6 -6
- package/esm/user.js.map +1 -1
- package/esm/util.js +14 -177
- package/esm/util.js.map +1 -1
- package/esm/{version-BnnERhzW.js → version-BlsI7hX2.js} +3 -3
- package/{cjs/version-Cg79mdPg.js.map → esm/version-BlsI7hX2.js.map} +1 -1
- package/esm/{version-78jjDnHU.js → version-wnf-TITV.js} +2 -2
- package/esm/{version-78jjDnHU.js.map → version-wnf-TITV.js.map} +1 -1
- package/models/app/App.d.ts +2 -2
- package/models/app/pages/VersionInfo/components/VersionInfo.d.ts +7 -2
- package/models/models/AppState.d.ts +4 -5
- package/models/models/GetRouteActionArgs.d.ts +2 -2
- package/models/models/MatchedRoute.d.ts +4 -0
- package/models/models/SSRContext.d.ts +23 -0
- package/models/models/StaticRoute.d.ts +8 -4
- package/models/models/config/AppConfig.d.ts +1 -0
- package/models/models/config/ServerConfig.d.ts +1 -0
- package/models/models/config/StateType.d.ts +1 -0
- package/models/models/index.d.ts +1 -0
- package/models/redux/store/history.d.ts +2 -2
- package/models/redux/store/injectors.d.ts +4 -4
- package/models/redux/store/store.d.ts +1 -1
- package/models/routing/components/Redirect.d.ts +5 -0
- package/models/routing/components/RouteLoader.d.ts +2 -2
- package/models/routing/components/StaticRouteLoader.d.ts +6 -0
- package/models/routing/httpContext.d.ts +7 -0
- package/models/routing/index.d.ts +3 -0
- package/models/routing/redux/actions.d.ts +2 -3
- package/models/search/containers/withListing.d.ts +4 -1
- package/models/search/containers/withSearch.d.ts +4 -1
- package/models/server/features/response-handler/render-stream.d.ts +26 -0
- package/models/server/util/html.d.ts +23 -0
- package/models/server/util/jsx.d.ts +55 -0
- package/models/user/hocs/withRegistration.d.ts +6 -3
- package/models/util/ContensisDeliveryApi.d.ts +1 -2
- package/models/util/SSRContext.d.ts +17 -6
- package/models/util/mergeStaticRoutes.d.ts +1 -0
- package/package.json +25 -30
- package/cjs/CookieHelper.class-CxeVo9EP.js +0 -489
- package/cjs/CookieHelper.class-CxeVo9EP.js.map +0 -1
- package/cjs/RouteLoader-De-dhkg-.js.map +0 -1
- package/cjs/SSRContext-DpnwQ2te.js.map +0 -1
- package/cjs/forms.js +0 -5673
- package/cjs/forms.js.map +0 -1
- package/cjs/sagas-Ekfrk7xA.js.map +0 -1
- package/cjs/store-BihH67lI.js.map +0 -1
- package/cjs/urls-DVIwGZmd.js +0 -25
- package/cjs/urls-DVIwGZmd.js.map +0 -1
- package/esm/CookieHelper.class-W_NNNJKT.js +0 -482
- package/esm/CookieHelper.class-W_NNNJKT.js.map +0 -1
- package/esm/RouteLoader-CipkGOgr.js.map +0 -1
- package/esm/SSRContext-3TvaCDn0.js.map +0 -1
- package/esm/forms.js +0 -5661
- package/esm/forms.js.map +0 -1
- package/esm/sagas-Cd05ZBBH.js.map +0 -1
- package/esm/selectors-BRzliwbK.js.map +0 -1
- package/esm/store-f0WxNWUu.js.map +0 -1
- package/esm/urls-DfCisos-.js +0 -22
- package/esm/urls-DfCisos-.js.map +0 -1
- package/models/forms/index.d.ts +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { c as cachedSearch,
|
|
1
|
+
import { c as cachedSearch, S as SSRContextProvider, d as deliveryApi } from './SSRContext-BE8ElZ3X.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
5
|
import mapJson from 'jsonpath-mapper';
|
|
6
|
+
import { a8 as defaultExpressions, a9 as termExpressions, aa as contentTypeIdExpression, ab as filterExpressions, ac as orderByExpression, ad as customWhereExpressions, ae as cloneDeep } from './sagas-JI51CS37.js';
|
|
6
7
|
import 'reselect';
|
|
7
|
-
import 'deepmerge';
|
|
8
|
-
import 'query-string';
|
|
9
|
-
import { a8 as defaultExpressions, a9 as contentTypeIdExpression, aa as filterExpressions, ab as termExpressions, ac as orderByExpression, ad as customWhereExpressions, ae as cloneDeep } from './sagas-Cd05ZBBH.js';
|
|
10
8
|
import 'immer';
|
|
11
9
|
import 'deep-equal';
|
|
10
|
+
import 'deepmerge';
|
|
11
|
+
import 'query-string';
|
|
12
12
|
import { Op, Query } from 'contensis-core-api';
|
|
13
|
-
import { s as setCachingHeaders, u as url } from './
|
|
13
|
+
import { s as setCachingHeaders, u as url } from './VersionInfo-Cno7K0OA.js';
|
|
14
14
|
import 'isomorphic-fetch';
|
|
15
15
|
import express from 'express';
|
|
16
16
|
import http from 'http';
|
|
@@ -18,39 +18,39 @@ import httpProxy from 'http-proxy';
|
|
|
18
18
|
import fs from 'fs';
|
|
19
19
|
import path from 'path';
|
|
20
20
|
import { path as path$1 } from 'app-root-path';
|
|
21
|
-
import { renderToString } from 'react-dom/server';
|
|
22
|
-
import {
|
|
23
|
-
import { matchRoutes } from 'react-router-config';
|
|
21
|
+
import { renderToPipeableStream, renderToString } from 'react-dom/server';
|
|
22
|
+
import { matchRoutes } from 'react-router-dom';
|
|
24
23
|
import { Helmet } from 'react-helmet';
|
|
25
24
|
import { ServerStyleSheet } from 'styled-components';
|
|
26
25
|
import serialize from 'serialize-javascript';
|
|
27
|
-
import
|
|
28
|
-
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server';
|
|
29
|
-
import { identity, noop } from 'lodash';
|
|
26
|
+
import { noop, identity } from 'lodash';
|
|
30
27
|
import { buildCleaner } from 'lodash-clean';
|
|
31
|
-
import {
|
|
32
|
-
import { a as Cookies } from './CookieHelper.class-W_NNNJKT.js';
|
|
28
|
+
import { a as Cookies } from './CookieHelper.class-FTURFpz3.js';
|
|
33
29
|
import cookiesMiddleware from 'universal-cookie-express';
|
|
34
|
-
import { c as createStore } from './store-
|
|
35
|
-
import { h as history, p as pickProject, r as rootSaga } from './App-
|
|
36
|
-
export { A as ReactApp } from './App-
|
|
37
|
-
import { s as setVersionStatus, d as setVersion } from './version-
|
|
38
|
-
import { a3 as selectSurrogateKeys, a4 as selectSsrApiCalls,
|
|
30
|
+
import { c as createStore } from './store-3u0RzHZ0.js';
|
|
31
|
+
import { h as history, p as pickProject, r as rootSaga } from './App-DLZweVSp.js';
|
|
32
|
+
export { A as ReactApp } from './App-DLZweVSp.js';
|
|
33
|
+
import { s as setVersionStatus, d as setVersion } from './version-BlsI7hX2.js';
|
|
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';
|
|
36
|
+
import { Transform } from 'stream';
|
|
37
|
+
import { ChunkExtractor, ChunkExtractorManager } from '@loadable/server';
|
|
39
38
|
import chalk from 'chalk';
|
|
39
|
+
import minifyCssString from 'minify-css-string';
|
|
40
|
+
import { CookiesProvider } from 'react-cookie';
|
|
41
|
+
import { StaticRouter } from 'react-router-dom/server';
|
|
40
42
|
import 'loglevel';
|
|
41
43
|
import '@redux-saga/core/effects';
|
|
42
44
|
import './_commonjsHelpers-BFTU3MAI.js';
|
|
45
|
+
import './version-wnf-TITV.js';
|
|
43
46
|
import 'redux';
|
|
44
47
|
import 'redux-thunk';
|
|
45
48
|
import 'redux-saga';
|
|
46
|
-
import 'redux-injectors';
|
|
49
|
+
import 'redux-injectors-19';
|
|
47
50
|
import 'history';
|
|
48
51
|
import 'await-to-js';
|
|
49
|
-
import './
|
|
50
|
-
import './
|
|
51
|
-
import './ToJs-B4MH53fx.js';
|
|
52
|
-
import 'react-hot-loader';
|
|
53
|
-
import './RouteLoader-CipkGOgr.js';
|
|
52
|
+
import './ChangePassword.container-BgzIy8dA.js';
|
|
53
|
+
import './ToJs-CNzfvyxJ.js';
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Util class holds our search results helper boilerplate methods
|
|
@@ -618,32 +618,29 @@ const assetProxy = httpProxy.createProxyServer();
|
|
|
618
618
|
const deliveryProxy = httpProxy.createProxyServer();
|
|
619
619
|
const reverseProxies = (app, reverseProxyPaths = []) => {
|
|
620
620
|
deliveryApiProxy(deliveryProxy, app);
|
|
621
|
-
app.all(reverseProxyPaths
|
|
621
|
+
app.all(reverseProxyPaths.map(proxyPath =>
|
|
622
|
+
// Patch to update paths for express v5
|
|
623
|
+
proxyPath.endsWith('/*') ? `${proxyPath.slice(0, -2)}/{*splat}` : proxyPath), (req, res) => {
|
|
622
624
|
const target = req.hostname.indexOf('preview-') || req.hostname.indexOf('preview.') || req.hostname === 'localhost' ? servers$1.previewIis || servers$1.iis : servers$1.iis;
|
|
623
625
|
assetProxy.web(req, res, {
|
|
624
626
|
target,
|
|
625
627
|
changeOrigin: true
|
|
626
628
|
});
|
|
627
629
|
assetProxy.on('error', e => {
|
|
628
|
-
/* eslint-disable no-console */
|
|
629
630
|
console.log(`Proxy Request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
630
|
-
/* eslint-enable no-console */
|
|
631
631
|
});
|
|
632
632
|
});
|
|
633
633
|
};
|
|
634
634
|
const deliveryApiProxy = (apiProxy, app) => {
|
|
635
635
|
// This is just here to stop cors requests on localhost. In Production this is mapped using varnish.
|
|
636
|
-
app.all(['/api/delivery
|
|
637
|
-
/* eslint-disable no-console */
|
|
636
|
+
app.all(['/api/delivery/{*splat}', '/api/forms/{*splat}', '/api/image/{*splat}', '/authenticate/{*splat}'], (req, res) => {
|
|
638
637
|
console.log(`Proxying api request to ${servers$1.alias}`);
|
|
639
638
|
apiProxy.web(req, res, {
|
|
640
639
|
target: deliveryApiHostname,
|
|
641
640
|
changeOrigin: true
|
|
642
641
|
});
|
|
643
642
|
apiProxy.on('error', e => {
|
|
644
|
-
/* eslint-disable no-console */
|
|
645
643
|
console.log(`Proxy request for ${req.path} HostName:${req.hostname} failed with ${e}`);
|
|
646
|
-
/* eslint-enable no-console */
|
|
647
644
|
});
|
|
648
645
|
});
|
|
649
646
|
};
|
|
@@ -794,6 +791,94 @@ const handleResponse = (request, response, content, send = 'send') => {
|
|
|
794
791
|
response[send](content);
|
|
795
792
|
};
|
|
796
793
|
|
|
794
|
+
/**
|
|
795
|
+
* Render React JSX (and surrounding HTML document) via React's
|
|
796
|
+
* renderToPipeableStream method
|
|
797
|
+
* @param getContextHtml a function to produce the correct HTML template that surrounds the JSX "App" with all available document assets injected
|
|
798
|
+
* @param jsx the JSX to render via a streamed response
|
|
799
|
+
* @param response the express Response object
|
|
800
|
+
* @param stream all chunks are piped to this stream to add additional style elements to each streamed chunk
|
|
801
|
+
*/
|
|
802
|
+
const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
803
|
+
const {
|
|
804
|
+
abort,
|
|
805
|
+
pipe
|
|
806
|
+
} = renderToPipeableStream(jsx, {
|
|
807
|
+
onShellReady() {
|
|
808
|
+
const html = getContextHtml(false);
|
|
809
|
+
if (!html) {
|
|
810
|
+
// this means we have finished with the response already
|
|
811
|
+
abort();
|
|
812
|
+
} else {
|
|
813
|
+
const header = html.split('{{APP}}')[0];
|
|
814
|
+
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
815
|
+
stream.write(header);
|
|
816
|
+
pipe(stream);
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
onAllReady() {
|
|
820
|
+
const footer = getContextHtml(true).split('{{APP}}')[1];
|
|
821
|
+
stream.write(footer);
|
|
822
|
+
},
|
|
823
|
+
onShellError(error) {
|
|
824
|
+
response.statusCode = 500;
|
|
825
|
+
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
826
|
+
response.send('<h1>Something went wrong</h1>');
|
|
827
|
+
console.error(`[renderToPipeableStream:onShellError]`, error);
|
|
828
|
+
},
|
|
829
|
+
onError(error) {
|
|
830
|
+
console.error(`[renderToPipeableStream:onError]`, error);
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
// Abandon and switch to client rendering if enough time passes.
|
|
835
|
+
// Try lowering this to see the client recover.
|
|
836
|
+
setTimeout(() => abort(), 30 * 1000);
|
|
837
|
+
stream === null || stream === void 0 || stream.pipe(response);
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Generate and add styled-components CSS to the streamed
|
|
842
|
+
* chunks of rendered HTML via renderToPipeableStream
|
|
843
|
+
*
|
|
844
|
+
* Workaround for Styled Components issue: React 18 Streaming SSR #3658
|
|
845
|
+
* https://github.com/styled-components/styled-components/issues/3658#issuecomment-2480721193
|
|
846
|
+
* credit: https://github.com/rurquia/styled-components-ssr-3658/blob/main/server/render.js
|
|
847
|
+
* @param sheet styled-components ServerStyleSheet
|
|
848
|
+
* @returns Transform Stream
|
|
849
|
+
*/
|
|
850
|
+
const styledComponentsStream = sheet => {
|
|
851
|
+
const readerWriter = new Transform({
|
|
852
|
+
objectMode: true,
|
|
853
|
+
transform(chunk, /* encoding */
|
|
854
|
+
_, callback) {
|
|
855
|
+
// Get the chunk and retrieve the sheet's CSS as an HTML chunk,
|
|
856
|
+
// then reset its rules so we get only new ones for the next chunk
|
|
857
|
+
const renderedHtml = typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk);
|
|
858
|
+
const styledCSS = sheet._emitSheetCSS();
|
|
859
|
+
const CLOSING_TAG_R = /<\/[a-z]*>/i;
|
|
860
|
+
sheet.instance.clearTag();
|
|
861
|
+
|
|
862
|
+
// prepend style html to chunk, unless the start of the chunk is a
|
|
863
|
+
// closing tag in which case append right after that
|
|
864
|
+
if (/<\/head>/.test(renderedHtml)) {
|
|
865
|
+
const replacedHtml = renderedHtml.replace('</head>', `${styledCSS}</head>`);
|
|
866
|
+
this.push(replacedHtml);
|
|
867
|
+
} else if (CLOSING_TAG_R.test(renderedHtml)) {
|
|
868
|
+
const execResult = CLOSING_TAG_R.exec(renderedHtml);
|
|
869
|
+
const endOfClosingTag = execResult.index + execResult.flat().length - 1;
|
|
870
|
+
const before = renderedHtml.slice(0, endOfClosingTag);
|
|
871
|
+
const after = renderedHtml.slice(endOfClosingTag);
|
|
872
|
+
this.push(before + styledCSS + after);
|
|
873
|
+
} else {
|
|
874
|
+
this.push(styledCSS + renderedHtml);
|
|
875
|
+
}
|
|
876
|
+
callback();
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
return readerWriter;
|
|
880
|
+
};
|
|
881
|
+
|
|
797
882
|
const readFileSync = path => fs.readFileSync(path, 'utf8');
|
|
798
883
|
const loadableBundleData = ({
|
|
799
884
|
stats,
|
|
@@ -841,7 +926,8 @@ const loadableChunkExtractors = () => {
|
|
|
841
926
|
statsFile: path.resolve('dist/legacy/loadable-stats.json')
|
|
842
927
|
});
|
|
843
928
|
} catch (e) {
|
|
844
|
-
|
|
929
|
+
// legacy bundling deprecated in v4
|
|
930
|
+
// console.info('@loadable/server legacy ChunkExtractor not available');
|
|
845
931
|
}
|
|
846
932
|
commonLoadableExtractor.addChunk = chunk => {
|
|
847
933
|
var _modern, _legacy, _legacy2;
|
|
@@ -919,6 +1005,36 @@ const getBundleTags = (loadableExtractor, scripts, staticRoutePath = 'static') =
|
|
|
919
1005
|
return startupTag;
|
|
920
1006
|
};
|
|
921
1007
|
|
|
1008
|
+
const getVersionInfo = staticFolderPath => {
|
|
1009
|
+
try {
|
|
1010
|
+
const versionData = fs.readFileSync(`dist/${staticFolderPath}/version.json`, 'utf8');
|
|
1011
|
+
const versionInfo = JSON.parse(versionData);
|
|
1012
|
+
return versionInfo;
|
|
1013
|
+
} catch (ex) {
|
|
1014
|
+
console.error(`Unable to read from "version.json"`, ex);
|
|
1015
|
+
return {};
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
/* eslint-disable no-console */
|
|
1020
|
+
|
|
1021
|
+
// Default exception types to add event listeners for
|
|
1022
|
+
const handleDefaultEvents = ['uncaughtException', 'unhandledRejection'];
|
|
1023
|
+
const unhandledExceptionHandler = (handleExceptions = handleDefaultEvents) => {
|
|
1024
|
+
const exceptionTypes = Array.isArray(handleExceptions) ? handleExceptions : handleExceptions === false ? [] : handleDefaultEvents;
|
|
1025
|
+
for (const type of exceptionTypes) {
|
|
1026
|
+
process.on(type, err => {
|
|
1027
|
+
if (err && err instanceof Error) {
|
|
1028
|
+
// Print a message to inform admins and developers the error should not be ignored
|
|
1029
|
+
console.log(`${`[contensis-react-base] ❌ ${chalk.red.bold(`${type} - ${err.message}`)}`}`);
|
|
1030
|
+
console.log(chalk.gray` - you are seeing this because we have tried to prevent the app from completely crashing - you should not ignore this problem`);
|
|
1031
|
+
// Log the error to server console
|
|
1032
|
+
console.error(err);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
922
1038
|
const addStandardHeaders = (state, response, packagejson, groups) => {
|
|
923
1039
|
if (state) {
|
|
924
1040
|
try {
|
|
@@ -964,39 +1080,111 @@ const addVarnishAuthenticationHeaders = (state, response, groups = {}) => {
|
|
|
964
1080
|
}
|
|
965
1081
|
};
|
|
966
1082
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1083
|
+
/**
|
|
1084
|
+
* Add assets to templateHTML in the positions represented
|
|
1085
|
+
* by replacing specific keys wrapped in handlebars depending
|
|
1086
|
+
* on the accessMethod(s) that have been set (or updated)
|
|
1087
|
+
* while processing the request
|
|
1088
|
+
*/
|
|
1089
|
+
const replaceHtml = ({
|
|
1090
|
+
bundleTags = '',
|
|
1091
|
+
html = '',
|
|
1092
|
+
htmlAttributes = '',
|
|
1093
|
+
metadata = '',
|
|
1094
|
+
state = '',
|
|
1095
|
+
styleTags = '',
|
|
1096
|
+
title = '',
|
|
1097
|
+
templateHTML = '',
|
|
1098
|
+
templateHTMLFragment = '',
|
|
1099
|
+
templateHTMLStatic = ''
|
|
1100
|
+
}, accessMethod) => {
|
|
1101
|
+
let responseHTML = '';
|
|
1102
|
+
// Serve a blank HTML page with client scripts to load the app in the browser
|
|
1103
|
+
if (accessMethod.DYNAMIC) {
|
|
1104
|
+
responseHTML = templateHTML.replace('{{TITLE}}', '').replace('{{SEO_CRITICAL_METADATA}}', '').replace('{{CRITICAL_CSS}}', '').replace('{{APP}}', '')
|
|
1105
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1106
|
+
.replace('{{REDUX_DATA}}', state);
|
|
975
1107
|
}
|
|
976
|
-
};
|
|
977
1108
|
|
|
978
|
-
|
|
1109
|
+
// Page fragment served with client scripts and redux data that hydrate the app client side
|
|
1110
|
+
else if (accessMethod.FRAGMENT && !accessMethod.STATIC) {
|
|
1111
|
+
responseHTML = templateHTMLFragment.replace('{{TITLE}}', title).replace('{{SEO_CRITICAL_METADATA}}', metadata).replace('{{CRITICAL_CSS}}', minifyCssString(styleTags))
|
|
1112
|
+
//.replace('{{APP}}', html)
|
|
1113
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1114
|
+
.replace('{{REDUX_DATA}}', state);
|
|
1115
|
+
}
|
|
979
1116
|
|
|
980
|
-
//
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1117
|
+
// Full HTML page served statically
|
|
1118
|
+
else if (!accessMethod.FRAGMENT && accessMethod.STATIC) {
|
|
1119
|
+
responseHTML = templateHTMLStatic.replace('{{TITLE}}', title).replace('{{SEO_CRITICAL_METADATA}}', metadata).replace('{{CRITICAL_CSS}}', minifyCssString(styleTags))
|
|
1120
|
+
//.replace('{{APP}}', html)
|
|
1121
|
+
.replace('{{LOADABLE_CHUNKS}}', '');
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Full HTML page served with client scripts and redux data that hydrate the app client side
|
|
1125
|
+
else if (!accessMethod.FRAGMENT && !accessMethod.STATIC) {
|
|
1126
|
+
responseHTML = templateHTML.replace('{{TITLE}}', title).replace('{{SEO_CRITICAL_METADATA}}', metadata).replace('{{CRITICAL_CSS}}', styleTags)
|
|
1127
|
+
//.replace('{{APP}}', html)
|
|
1128
|
+
// .replace('{{LOADABLE_CHUNKS}}', bundleTags)
|
|
1129
|
+
.replace('{{REDUX_DATA}}', state);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// If react-helmet htmlAttributes are being used,
|
|
1133
|
+
// replace the html tag with those attributes sepcified
|
|
1134
|
+
// e.g. (lang, dir etc.)
|
|
1135
|
+
if (htmlAttributes) {
|
|
1136
|
+
responseHTML = responseHTML.replace(/<html?.+?>/, `<html ${htmlAttributes}>`);
|
|
994
1137
|
}
|
|
1138
|
+
responseHTML = html ? responseHTML.replace('{{APP}}', html) : responseHTML;
|
|
1139
|
+
|
|
1140
|
+
// Only replace bundle tags at the very end when we have rendered and are
|
|
1141
|
+
// streaming out the HTML "footer"
|
|
1142
|
+
if (bundleTags) responseHTML = responseHTML.replace('{{LOADABLE_CHUNKS}}', bundleTags);
|
|
1143
|
+
return responseHTML;
|
|
1144
|
+
};
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Produce the JSX wrapped in the necessary Providers
|
|
1148
|
+
* to render the app in SSR
|
|
1149
|
+
* @param ReactApp the JSX to render
|
|
1150
|
+
* @param { providers, props, ssrAssets }
|
|
1151
|
+
* @returns the final JSX to render decorated with all Provider and App props
|
|
1152
|
+
*/
|
|
1153
|
+
const ssrJsxProducer = (ReactApp, {
|
|
1154
|
+
providers,
|
|
1155
|
+
props,
|
|
1156
|
+
ssrAssets
|
|
1157
|
+
}) => {
|
|
1158
|
+
var _providers$styledComp;
|
|
1159
|
+
// Recast ChunkExtractorManager to avoid TS error `Property 'children' does not exist on type...`
|
|
1160
|
+
const ChunkExtractor = ChunkExtractorManager;
|
|
1161
|
+
const jsx = /*#__PURE__*/React.createElement(ChunkExtractor, {
|
|
1162
|
+
extractor: providers.loadable.extractor
|
|
1163
|
+
}, /*#__PURE__*/React.createElement(CookiesProvider, {
|
|
1164
|
+
cookies: providers.cookies
|
|
1165
|
+
}, /*#__PURE__*/React.createElement(Provider, {
|
|
1166
|
+
store: providers.redux
|
|
1167
|
+
}, /*#__PURE__*/React.createElement(HttpContext.Provider, {
|
|
1168
|
+
value: providers.httpContext
|
|
1169
|
+
}, /*#__PURE__*/React.createElement(StaticRouter, {
|
|
1170
|
+
location: providers.router.url
|
|
1171
|
+
}, /*#__PURE__*/React.createElement(SSRContextProvider, {
|
|
1172
|
+
accessMethod: providers.ssrContext.accessMethod,
|
|
1173
|
+
request: providers.ssrContext.request,
|
|
1174
|
+
response: providers.ssrContext.response,
|
|
1175
|
+
ssrAssets: ssrAssets
|
|
1176
|
+
}, /*#__PURE__*/React.createElement(ReactApp, {
|
|
1177
|
+
routes: props.routes,
|
|
1178
|
+
withEvents: props.withEvents
|
|
1179
|
+
})))))));
|
|
1180
|
+
|
|
1181
|
+
// Wrap the JSX in a StyleSheetManager if a ServerStyleSheet is provided
|
|
1182
|
+
return !((_providers$styledComp = providers.styledComponents) !== null && _providers$styledComp !== void 0 && _providers$styledComp.sheet) ? jsx : providers.styledComponents.sheet.collectStyles(jsx);
|
|
995
1183
|
};
|
|
996
1184
|
|
|
997
1185
|
const webApp = (app, ReactApp, config) => {
|
|
998
1186
|
const {
|
|
999
|
-
stateType = '
|
|
1187
|
+
stateType = 'js',
|
|
1000
1188
|
routes,
|
|
1001
1189
|
withReducers,
|
|
1002
1190
|
withSagas,
|
|
@@ -1013,18 +1201,26 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1013
1201
|
handleExceptions = true
|
|
1014
1202
|
} = config;
|
|
1015
1203
|
const staticRoutePath = config.staticRoutePath || staticFolderPath;
|
|
1204
|
+
let isRenderingJsxToString = config.renderToString || false;
|
|
1016
1205
|
const bundleData = getBundleData(config, staticRoutePath);
|
|
1017
1206
|
const attributes = stringifyAttributes(scripts.attributes);
|
|
1018
1207
|
scripts.startup = scripts.startup || startupScriptFilename;
|
|
1019
|
-
|
|
1208
|
+
let responseHandler = handleResponse;
|
|
1209
|
+
if (typeof handleResponses === 'function') {
|
|
1210
|
+
responseHandler = handleResponses;
|
|
1211
|
+
isRenderingJsxToString = true;
|
|
1212
|
+
}
|
|
1020
1213
|
if (handleExceptions !== false) unhandledExceptionHandler(handleExceptions); // Create `process.on` event handlers for unhandled exceptions (Node v15+)
|
|
1021
1214
|
|
|
1022
1215
|
const versionInfo = getVersionInfo(staticFolderPath);
|
|
1023
|
-
app.get('
|
|
1216
|
+
app.get('/{*splat}', cookiesMiddleware(), async (request, response) => {
|
|
1024
1217
|
const url = encodeURI(request.url);
|
|
1025
|
-
const matchedStaticRoute =
|
|
1026
|
-
const isStaticRoute =
|
|
1027
|
-
|
|
1218
|
+
const matchedStaticRoute = matchRoutes(routes.StaticRoutes, request.path);
|
|
1219
|
+
const isStaticRoute = matchedStaticRoute && matchedStaticRoute.length > 0;
|
|
1220
|
+
if (isStaticRoute) {
|
|
1221
|
+
mergeStaticRoutes(matchedStaticRoute);
|
|
1222
|
+
}
|
|
1223
|
+
const staticRoute = isStaticRoute ? matchedStaticRoute.pop() || null : null;
|
|
1028
1224
|
|
|
1029
1225
|
// Allow certain routes to avoid SSR
|
|
1030
1226
|
const onlyDynamic = staticRoute && staticRoute.route.ssr === false;
|
|
@@ -1046,9 +1242,6 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1046
1242
|
static: value
|
|
1047
1243
|
}) => normaliseQs(value) || onlySSR
|
|
1048
1244
|
});
|
|
1049
|
-
const context = {};
|
|
1050
|
-
// Track the current statusCode via the response object
|
|
1051
|
-
response.status(200);
|
|
1052
1245
|
|
|
1053
1246
|
// Create a store (with a memory history) from our current url
|
|
1054
1247
|
const store = await createStore(withReducers, {}, history({
|
|
@@ -1074,22 +1267,38 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1074
1267
|
request.universalCookies :
|
|
1075
1268
|
// this is a stub cookie collection so cookie methods can be used in code
|
|
1076
1269
|
new Cookies();
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1270
|
+
|
|
1271
|
+
// Track the current statusCode via the response object
|
|
1272
|
+
response.status(200);
|
|
1273
|
+
|
|
1274
|
+
// Create the context we will pass to JSX HttpContext.Provider
|
|
1275
|
+
// and read back any context props set by the ReactApp
|
|
1276
|
+
const context = {};
|
|
1277
|
+
|
|
1278
|
+
// Amalgamate all props for the various Providers we wrap the ReactApp with
|
|
1279
|
+
const jsxProviderProps = {
|
|
1280
|
+
loadable: {
|
|
1281
|
+
extractor: loadableExtractor.commonLoadableExtractor
|
|
1282
|
+
},
|
|
1283
|
+
cookies: ssrCookies,
|
|
1284
|
+
redux: store,
|
|
1285
|
+
httpContext: context,
|
|
1286
|
+
router: {
|
|
1287
|
+
url
|
|
1288
|
+
},
|
|
1289
|
+
ssrContext: {
|
|
1290
|
+
accessMethod,
|
|
1291
|
+
request,
|
|
1292
|
+
response
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
// These are the props we will pass to the ReactApp itself
|
|
1296
|
+
const jsxReactAppProps = {
|
|
1297
|
+
routes,
|
|
1298
|
+
withEvents
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
// Get the configured HTML templates provided by the consumer
|
|
1093
1302
|
const {
|
|
1094
1303
|
templateHTML = '',
|
|
1095
1304
|
templateHTMLFragment = '',
|
|
@@ -1099,13 +1308,28 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1099
1308
|
// Serve a blank HTML page with client scripts to load the app in the browser
|
|
1100
1309
|
if (accessMethod.DYNAMIC) {
|
|
1101
1310
|
// Dynamic doesn't need sagas
|
|
1311
|
+
// or styles, or any split component bundles
|
|
1312
|
+
// nor are we streaming responses
|
|
1313
|
+
const isDynamicHints = `<script ${attributes}>window.versionStatus = "${versionStatus}"; window.isDynamic = true;</script>`;
|
|
1314
|
+
const jsx = ssrJsxProducer(ReactApp, {
|
|
1315
|
+
providers: jsxProviderProps,
|
|
1316
|
+
props: jsxReactAppProps,
|
|
1317
|
+
ssrAssets: {
|
|
1318
|
+
serializedState: isDynamicHints
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1102
1321
|
renderToString(jsx);
|
|
1103
1322
|
|
|
1104
1323
|
// Dynamic page render has only the necessary bundles to start up the app
|
|
1105
1324
|
// and does not include any react-loadable code-split bundles
|
|
1106
1325
|
const bundleTags = getBundleTags(loadableExtractor, scripts, staticRoutePath);
|
|
1107
|
-
const
|
|
1108
|
-
|
|
1326
|
+
const responseHtmlDynamic = replaceHtml({
|
|
1327
|
+
bundleTags,
|
|
1328
|
+
state: isDynamicHints,
|
|
1329
|
+
templateHTML,
|
|
1330
|
+
templateHTMLFragment
|
|
1331
|
+
}, accessMethod);
|
|
1332
|
+
|
|
1109
1333
|
// Dynamic pages always return a 200 so we can run
|
|
1110
1334
|
// the app and serve up all errors inside the client
|
|
1111
1335
|
response.setHeader('Surrogate-Control', `max-age=${getCacheDuration(200)}`);
|
|
@@ -1116,22 +1340,7 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1116
1340
|
if (!accessMethod.DYNAMIC) {
|
|
1117
1341
|
store.runSaga(rootSaga(withSagas)).toPromise().then(() => {
|
|
1118
1342
|
var _selectCurrentSearch;
|
|
1119
|
-
const sheet = new ServerStyleSheet();
|
|
1120
|
-
const html = renderToString(sheet.collectStyles(jsx));
|
|
1121
|
-
const helmet = Helmet.renderStatic();
|
|
1122
|
-
Helmet.rewind();
|
|
1123
|
-
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
1124
|
-
let title = helmet.title.toString();
|
|
1125
|
-
const metadata = helmet.meta.toString().concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1126
|
-
if (context.url) {
|
|
1127
|
-
return response.redirect(context.statusCode || 302, context.url);
|
|
1128
|
-
}
|
|
1129
1343
|
const reduxState = store.getState();
|
|
1130
|
-
const styleTags = sheet.getStyleTags();
|
|
1131
|
-
|
|
1132
|
-
// After running rootSaga there should be an additional react-loadable
|
|
1133
|
-
// code-split bundles for any page components as well as core app bundles
|
|
1134
|
-
const bundleTags = getBundleTags(loadableExtractor, scripts, staticRoutePath);
|
|
1135
1344
|
let clonedState = buildCleaner({
|
|
1136
1345
|
isArray: identity,
|
|
1137
1346
|
isBoolean: identity,
|
|
@@ -1172,48 +1381,108 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1172
1381
|
serialisedReduxData = `<script ${attributes}>window.versionStatus = "${versionStatus}"; window.REDUX_DATA = ${serialisedReduxData}</script>`;
|
|
1173
1382
|
}
|
|
1174
1383
|
}
|
|
1175
|
-
if ((context.statusCode || 200) >= 404) {
|
|
1176
|
-
accessMethod.STATIC = true;
|
|
1177
|
-
}
|
|
1178
1384
|
|
|
1179
1385
|
// Responses
|
|
1180
|
-
|
|
1181
|
-
|
|
1386
|
+
addStandardHeaders(reduxState, response, packagejson, {
|
|
1387
|
+
allowedGroups,
|
|
1388
|
+
globalGroups
|
|
1389
|
+
});
|
|
1182
1390
|
|
|
1183
|
-
//
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1391
|
+
// // Produce the ssr jsx one time so we can get any style tags to pass back in
|
|
1392
|
+
// ssrJsxProducer(ReactApp, {
|
|
1393
|
+
// providers: { ...jsxProviderProps, styledComponents: { sheet } },
|
|
1394
|
+
// props: jsxReactAppProps,
|
|
1395
|
+
// });
|
|
1187
1396
|
|
|
1188
|
-
//
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1397
|
+
// // After running rootSaga (and rendering subsquent children)
|
|
1398
|
+
// // there should be additional react-loadable
|
|
1399
|
+
// // code-split bundles for any page components as well as core app bundles
|
|
1400
|
+
// const bundleTags = getBundleTags(
|
|
1401
|
+
// loadableExtractor,
|
|
1402
|
+
// scripts,
|
|
1403
|
+
// staticRoutePath
|
|
1404
|
+
// );
|
|
1192
1405
|
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1406
|
+
const sheet = new ServerStyleSheet();
|
|
1407
|
+
const styledJsx = ssrJsxProducer(ReactApp, {
|
|
1408
|
+
providers: {
|
|
1409
|
+
...jsxProviderProps,
|
|
1410
|
+
styledComponents: {
|
|
1411
|
+
sheet
|
|
1412
|
+
}
|
|
1413
|
+
},
|
|
1414
|
+
props: jsxReactAppProps,
|
|
1415
|
+
ssrAssets: {
|
|
1416
|
+
// bundleTags,
|
|
1417
|
+
// htmlAttributes,
|
|
1418
|
+
// metadata,
|
|
1419
|
+
// title,
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1197
1422
|
|
|
1198
|
-
//
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1423
|
+
// We have to call renderToString() in order for all components to have
|
|
1424
|
+
// had chance to set the helmet metadata
|
|
1425
|
+
const html = renderToString(styledJsx);
|
|
1426
|
+
// Helmet.renderStatic() has to be called synchronously immediately after calling renderToString()
|
|
1427
|
+
// as it is not thread-safe (or specifically scoped to only this request)
|
|
1428
|
+
const helmet = Helmet.renderStatic();
|
|
1202
1429
|
|
|
1203
|
-
//
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1430
|
+
// Because we have had to call renderToString() here to reliably gather all helmet metadata
|
|
1431
|
+
// We could potentially call sheet.getStyleTags() here too and avoid piping a react-rendered
|
|
1432
|
+
// stream to a second stream to inject styled-components CSS
|
|
1433
|
+
|
|
1434
|
+
const htmlAttributes = helmet.htmlAttributes.toString();
|
|
1435
|
+
let title = helmet.title.toString();
|
|
1436
|
+
const metadata = helmet.meta.toString().concat(helmet.base.toString()).concat(helmet.link.toString()).concat(helmet.script.toString()).concat(helmet.noscript.toString());
|
|
1209
1437
|
try {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1438
|
+
/**
|
|
1439
|
+
* Loads all page assets into the provided templateHTML
|
|
1440
|
+
*
|
|
1441
|
+
* Is callable after the JSX has been rendered, as
|
|
1442
|
+
* JSX components may update the context via the
|
|
1443
|
+
* HttpContext.Provider which can influence whether
|
|
1444
|
+
* we render the page as STATIC or render nothing
|
|
1445
|
+
* if the context has requested a redirect
|
|
1446
|
+
* */
|
|
1447
|
+
const getContextHtml = (isFinal = false, styleTags, renderedJsxMarkup) => {
|
|
1448
|
+
if (context.url) {
|
|
1449
|
+
response.redirect(context.statusCode || 302, context.url);
|
|
1450
|
+
return '';
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
// Make the page render statically if there is an error status code
|
|
1454
|
+
if ((context.statusCode || 200) >= 404) {
|
|
1455
|
+
accessMethod.STATIC = true;
|
|
1456
|
+
}
|
|
1457
|
+
if (context.statusCode === 404) title = '<title>404 page not found</title>';
|
|
1458
|
+
|
|
1459
|
+
// Set response.status from React StaticRouter
|
|
1460
|
+
if (typeof context.statusCode === 'number') response.status(context.statusCode);
|
|
1461
|
+
const bundleTags = isFinal ? getBundleTags(loadableExtractor, scripts, staticRoutePath) : '';
|
|
1462
|
+
const html = replaceHtml({
|
|
1463
|
+
bundleTags,
|
|
1464
|
+
html: renderedJsxMarkup,
|
|
1465
|
+
htmlAttributes,
|
|
1466
|
+
metadata,
|
|
1467
|
+
state: serialisedReduxData,
|
|
1468
|
+
styleTags,
|
|
1469
|
+
title,
|
|
1470
|
+
templateHTML,
|
|
1471
|
+
templateHTMLFragment,
|
|
1472
|
+
templateHTMLStatic
|
|
1473
|
+
}, accessMethod);
|
|
1474
|
+
return html;
|
|
1475
|
+
};
|
|
1476
|
+
if (isRenderingJsxToString) {
|
|
1477
|
+
// We have already (begrudgingly) rendered the JSX to a string above
|
|
1478
|
+
// so we can get all of the Helmet metadata out from any rendered component
|
|
1479
|
+
// const html = renderToString(styledJsx);
|
|
1480
|
+
const styleTags = sheet.getStyleTags();
|
|
1481
|
+
const responseHTML = getContextHtml(true, styleTags, html);
|
|
1482
|
+
responseHandler(request, response, responseHTML);
|
|
1483
|
+
} else {
|
|
1484
|
+
renderStream(getContextHtml, styledJsx, response, styledComponentsStream(sheet));
|
|
1215
1485
|
}
|
|
1216
|
-
responseHandler(request, response, responseHTML);
|
|
1217
1486
|
} catch (err) {
|
|
1218
1487
|
console.info(err.message);
|
|
1219
1488
|
}
|
|
@@ -1224,7 +1493,13 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1224
1493
|
response.status(500);
|
|
1225
1494
|
responseHandler(request, response, `Error occurred: <br />${err.stack} <br />${JSON.stringify(err)}`);
|
|
1226
1495
|
});
|
|
1227
|
-
|
|
1496
|
+
|
|
1497
|
+
// If this is removed we don't get the redux state populated
|
|
1498
|
+
// with the result of the actions RouteLoader component has dispatched
|
|
1499
|
+
renderToString(ssrJsxProducer(ReactApp, {
|
|
1500
|
+
providers: jsxProviderProps,
|
|
1501
|
+
props: jsxReactAppProps
|
|
1502
|
+
}));
|
|
1228
1503
|
store.close();
|
|
1229
1504
|
}
|
|
1230
1505
|
});
|