@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.
|
@@ -853,8 +853,8 @@ const handleResponse = (request, response, content, send = 'send') => {
|
|
|
853
853
|
* @param response the express Response object
|
|
854
854
|
* @param stream all chunks are piped to this stream to add additional style elements to each streamed chunk
|
|
855
855
|
*/
|
|
856
|
-
const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
857
|
-
// Store timeout reference for cleanup
|
|
856
|
+
const renderStream = (getContextHtml, jsx, request, response, stream) => {
|
|
857
|
+
// Store timeout reference for cleanup on normal or abnormal termination
|
|
858
858
|
let timeoutId = null;
|
|
859
859
|
const disposeTimeout = () => {
|
|
860
860
|
if (timeoutId) {
|
|
@@ -862,6 +862,22 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
862
862
|
timeoutId = null;
|
|
863
863
|
}
|
|
864
864
|
};
|
|
865
|
+
|
|
866
|
+
// Only used for abnormal termination
|
|
867
|
+
const abortCleanup = err => {
|
|
868
|
+
disposeTimeout();
|
|
869
|
+
stream.destroy(err instanceof Error ? err : undefined);
|
|
870
|
+
abort();
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
// Guard against client disconnect
|
|
874
|
+
request.on('close', () => abortCleanup());
|
|
875
|
+
|
|
876
|
+
// Guard against transform errors
|
|
877
|
+
stream.on('error', err => {
|
|
878
|
+
abortCleanup(err);
|
|
879
|
+
if (!response.headersSent) response.destroy(err);
|
|
880
|
+
});
|
|
865
881
|
const {
|
|
866
882
|
abort,
|
|
867
883
|
pipe
|
|
@@ -870,8 +886,7 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
870
886
|
const html = getContextHtml(false);
|
|
871
887
|
if (!html) {
|
|
872
888
|
// this means we have finished with the response already
|
|
873
|
-
|
|
874
|
-
abort();
|
|
889
|
+
abortCleanup();
|
|
875
890
|
} else {
|
|
876
891
|
const header = html.split('{{APP}}')[0];
|
|
877
892
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
@@ -882,10 +897,10 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
882
897
|
onAllReady() {
|
|
883
898
|
const footer = getContextHtml(true).split('{{APP}}')[1];
|
|
884
899
|
stream.write(footer);
|
|
885
|
-
disposeTimeout(); //
|
|
900
|
+
disposeTimeout(); // Clear the timeout, let stream end naturally
|
|
886
901
|
},
|
|
887
902
|
onShellError(error) {
|
|
888
|
-
|
|
903
|
+
abortCleanup(error); // Abnormal - destroy everything
|
|
889
904
|
response.statusCode = 500;
|
|
890
905
|
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
891
906
|
response.send('<h1>Something went wrong</h1>');
|
|
@@ -899,10 +914,10 @@ const renderStream = (getContextHtml, jsx, response, stream) => {
|
|
|
899
914
|
// Abandon and switch to client rendering after 30s.
|
|
900
915
|
// Try lowering this to see the client recover.
|
|
901
916
|
timeoutId = setTimeout(() => {
|
|
902
|
-
timeoutId = null;
|
|
903
|
-
|
|
904
|
-
},
|
|
905
|
-
stream
|
|
917
|
+
timeoutId = null;
|
|
918
|
+
abortCleanup();
|
|
919
|
+
}, 30_000);
|
|
920
|
+
stream.pipe(response);
|
|
906
921
|
};
|
|
907
922
|
|
|
908
923
|
/**
|
|
@@ -942,6 +957,23 @@ const styledComponentsStream = sheet => {
|
|
|
942
957
|
this.push(styledCSS + renderedHtml);
|
|
943
958
|
}
|
|
944
959
|
callback();
|
|
960
|
+
},
|
|
961
|
+
destroy(err, callback) {
|
|
962
|
+
// Called on both stream.destroy() and natural end
|
|
963
|
+
// Stops the sheet intercepting styles & releases its references
|
|
964
|
+
|
|
965
|
+
// try/catch is required if sheet.seal() throws for any reason,
|
|
966
|
+
// callback(err) must still be called, as Node.js stream internals depend
|
|
967
|
+
// on it to complete teardown. Omitting it causes the stream to hang.
|
|
968
|
+
try {
|
|
969
|
+
sheet.seal();
|
|
970
|
+
} catch (sealErr) {
|
|
971
|
+
// Catch any errors from sealing the sheet, we MUST always call the
|
|
972
|
+
// callback to prevent hanging the stream
|
|
973
|
+
|
|
974
|
+
console.error('[styledComponentsStream] sheet.seal() failed - styles may leak:', sealErr);
|
|
975
|
+
}
|
|
976
|
+
callback(err);
|
|
945
977
|
}
|
|
946
978
|
});
|
|
947
979
|
return readerWriter;
|
|
@@ -1566,7 +1598,7 @@ const webApp = (app, ReactApp, config) => {
|
|
|
1566
1598
|
const responseHTML = getContextHtml(true, styleTags, html);
|
|
1567
1599
|
responseHandler(request, response, responseHTML);
|
|
1568
1600
|
} else {
|
|
1569
|
-
renderStream(getContextHtml, styledJsx, response, styledComponentsStream(sheet));
|
|
1601
|
+
renderStream(getContextHtml, styledJsx, request, response, styledComponentsStream(sheet));
|
|
1570
1602
|
}
|
|
1571
1603
|
} catch (err) {
|
|
1572
1604
|
console.info(err.message);
|