@zengenti/contensis-react-base 4.0.0-beta.59 → 4.0.0-beta.60
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.
|
@@ -835,8 +835,8 @@ const handleResponse = (request, response, content, send = 'send') => {
|
|
|
835
835
|
* @param response the express Response object
|
|
836
836
|
* @param stream all chunks are piped to this stream to add additional style elements to each streamed chunk
|
|
837
837
|
*/
|
|
838
|
-
const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
839
|
-
// Store timeout reference for cleanup
|
|
838
|
+
const renderStream = (getContextHtml, jsx, request, response, stream) => {
|
|
839
|
+
// Store timeout reference for cleanup on normal or abnormal termination
|
|
840
840
|
let timeoutId = null;
|
|
841
841
|
const disposeTimeout = () => {
|
|
842
842
|
if (timeoutId) {
|
|
@@ -844,6 +844,22 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
844
844
|
timeoutId = null;
|
|
845
845
|
}
|
|
846
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
|
+
});
|
|
847
863
|
const {
|
|
848
864
|
abort,
|
|
849
865
|
pipe
|
|
@@ -852,8 +868,7 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
852
868
|
const html = getContextHtml(false);
|
|
853
869
|
if (!html) {
|
|
854
870
|
// this means we have finished with the response already
|
|
855
|
-
|
|
856
|
-
abort();
|
|
871
|
+
abortCleanup();
|
|
857
872
|
} else {
|
|
858
873
|
const header = html.split('{{APP}}')[0];
|
|
859
874
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
@@ -864,10 +879,10 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
864
879
|
onAllReady() {
|
|
865
880
|
const footer = getContextHtml(true).split('{{APP}}')[1];
|
|
866
881
|
stream.write(footer);
|
|
867
|
-
disposeTimeout(); //
|
|
882
|
+
disposeTimeout(); // Clear the timeout, let stream end naturally
|
|
868
883
|
},
|
|
869
884
|
onShellError(error) {
|
|
870
|
-
|
|
885
|
+
abortCleanup(error); // Abnormal - destroy everything
|
|
871
886
|
response.statusCode = 500;
|
|
872
887
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
873
888
|
response.send('<h1>Something went wrong</h1>');
|
|
@@ -881,10 +896,10 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
881
896
|
// Abandon and switch to client rendering after 30s.
|
|
882
897
|
// Try lowering this to see the client recover.
|
|
883
898
|
timeoutId = setTimeout(() => {
|
|
884
|
-
timeoutId = null;
|
|
885
|
-
|
|
886
|
-
},
|
|
887
|
-
stream
|
|
899
|
+
timeoutId = null;
|
|
900
|
+
abortCleanup();
|
|
901
|
+
}, 30_000);
|
|
902
|
+
stream.pipe(response);
|
|
888
903
|
};
|
|
889
904
|
|
|
890
905
|
/**
|
|
@@ -924,6 +939,23 @@ const styledComponentsStream = sheet => {
|
|
|
924
939
|
this.push(styledCSS + renderedHtml);
|
|
925
940
|
}
|
|
926
941
|
callback();
|
|
942
|
+
},
|
|
943
|
+
destroy(err, callback) {
|
|
944
|
+
// Called on both stream.destroy() and natural end
|
|
945
|
+
// Stops the sheet intercepting styles & releases its references
|
|
946
|
+
|
|
947
|
+
// try/catch is required if sheet.seal() throws for any reason,
|
|
948
|
+
// callback(err) must still be called, as Node.js stream internals depend
|
|
949
|
+
// on it to complete teardown. Omitting it causes the stream to hang.
|
|
950
|
+
try {
|
|
951
|
+
sheet.seal();
|
|
952
|
+
} catch (sealErr) {
|
|
953
|
+
// Catch any errors from sealing the sheet, we MUST always call the
|
|
954
|
+
// callback to prevent hanging the stream
|
|
955
|
+
|
|
956
|
+
console.error('[styledComponentsStream] sheet.seal() failed - styles may leak:', sealErr);
|
|
957
|
+
}
|
|
958
|
+
callback(err);
|
|
927
959
|
}
|
|
928
960
|
});
|
|
929
961
|
return readerWriter;
|
|
@@ -1548,7 +1580,7 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1548
1580
|
const responseHTML = getContextHtml(true, styleTags, html);
|
|
1549
1581
|
responseHandler(request, response, responseHTML);
|
|
1550
1582
|
} else {
|
|
1551
|
-
renderStream(getContextHtml, styledJsx, response, styledComponentsStream(sheet));
|
|
1583
|
+
renderStream(getContextHtml, styledJsx, request, response, styledComponentsStream(sheet));
|
|
1552
1584
|
}
|
|
1553
1585
|
} catch (err) {
|
|
1554
1586
|
console.info(err.message);
|