@tramvai/module-render 2.33.3 → 2.34.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/lib/server/ReactRenderServer.d.ts +7 -3
- package/lib/server.es.js +67 -2
- package/lib/server.js +67 -2
- package/package.json +15 -15
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ExtractDependencyType } from '@tinkoff/dippy';
|
|
2
2
|
import type { DI_TOKEN } from '@tramvai/core';
|
|
3
|
-
import type { CONTEXT_TOKEN } from '@tramvai/module-common';
|
|
4
|
-
import type { EXTEND_RENDER, CUSTOM_RENDER } from '@tramvai/tokens-render';
|
|
3
|
+
import type { CONTEXT_TOKEN, LOGGER_TOKEN } from '@tramvai/module-common';
|
|
4
|
+
import type { EXTEND_RENDER, CUSTOM_RENDER, REACT_SERVER_RENDER_MODE } from '@tramvai/tokens-render';
|
|
5
5
|
import type { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
6
6
|
import type { ChunkExtractor } from '@loadable/server';
|
|
7
7
|
export declare class ReactRenderServer {
|
|
@@ -10,12 +10,16 @@ export declare class ReactRenderServer {
|
|
|
10
10
|
context: typeof CONTEXT_TOKEN;
|
|
11
11
|
pageService: typeof PAGE_SERVICE_TOKEN;
|
|
12
12
|
di: typeof DI_TOKEN;
|
|
13
|
-
|
|
13
|
+
log: ReturnType<typeof LOGGER_TOKEN>;
|
|
14
|
+
renderMode: typeof REACT_SERVER_RENDER_MODE;
|
|
15
|
+
constructor({ pageService, context, customRender, extendRender, di, renderMode, logger }: {
|
|
14
16
|
pageService: any;
|
|
15
17
|
context: any;
|
|
16
18
|
customRender: any;
|
|
17
19
|
extendRender: any;
|
|
18
20
|
di: any;
|
|
21
|
+
renderMode: any;
|
|
22
|
+
logger: any;
|
|
19
23
|
});
|
|
20
24
|
render(extractor: ChunkExtractor): Promise<string>;
|
|
21
25
|
}
|
package/lib/server.es.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core'
|
|
|
5
5
|
import { COMBINE_REDUCERS, CREATE_CACHE_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/tokens-common';
|
|
6
6
|
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
7
7
|
import { ClientHintsModule, USER_AGENT_TOKEN } from '@tramvai/module-client-hints';
|
|
8
|
-
import { ResourceType, ResourceSlot, DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, TRAMVAI_RENDER_MODE, RESOURCES_REGISTRY, RESOURCE_INLINE_OPTIONS, RENDER_SLOTS, POLYFILL_CONDITION, HTML_ATTRS, MODERN_SATISFIES_TOKEN, RENDER_FLOW_AFTER_TOKEN, CUSTOM_RENDER, EXTEND_RENDER } from '@tramvai/tokens-render';
|
|
8
|
+
import { ResourceType, ResourceSlot, DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, TRAMVAI_RENDER_MODE, RESOURCES_REGISTRY, RESOURCE_INLINE_OPTIONS, RENDER_SLOTS, POLYFILL_CONDITION, HTML_ATTRS, MODERN_SATISFIES_TOKEN, RENDER_FLOW_AFTER_TOKEN, CUSTOM_RENDER, EXTEND_RENDER, REACT_SERVER_RENDER_MODE } from '@tramvai/tokens-render';
|
|
9
9
|
export * from '@tramvai/tokens-render';
|
|
10
10
|
import { createToken, Scope } from '@tinkoff/dippy';
|
|
11
11
|
import { WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN } from '@tramvai/tokens-server-private';
|
|
@@ -29,6 +29,7 @@ import * as path from 'path';
|
|
|
29
29
|
import each from '@tinkoff/utils/array/each';
|
|
30
30
|
import path$1 from '@tinkoff/utils/object/path';
|
|
31
31
|
import { o as onload } from './server_inline.inline.es.js';
|
|
32
|
+
import { Writable } from 'stream';
|
|
32
33
|
import { jsx } from 'react/jsx-runtime';
|
|
33
34
|
import { createEvent, createReducer, useStore, Provider } from '@tramvai/state';
|
|
34
35
|
import { useRoute, useUrl } from '@tramvai/module-router';
|
|
@@ -702,13 +703,35 @@ function renderReact({ pageService, di }, context) {
|
|
|
702
703
|
return (jsx(Provider, { context: context, serverState: serverState, children: jsx(DIContext.Provider, { value: di, children: jsx(PageErrorBoundary, { pageService: pageService, children: jsx(Root, { pageService: pageService }) }) }) }));
|
|
703
704
|
}
|
|
704
705
|
|
|
706
|
+
const RENDER_TIMEOUT = 500;
|
|
707
|
+
class HtmlWritable extends Writable {
|
|
708
|
+
constructor() {
|
|
709
|
+
super(...arguments);
|
|
710
|
+
this.chunks = [];
|
|
711
|
+
this.html = '';
|
|
712
|
+
}
|
|
713
|
+
getHtml() {
|
|
714
|
+
return this.html;
|
|
715
|
+
}
|
|
716
|
+
_write(chunk, encoding, callback) {
|
|
717
|
+
this.chunks.push(chunk);
|
|
718
|
+
callback();
|
|
719
|
+
}
|
|
720
|
+
_final(callback) {
|
|
721
|
+
this.html = Buffer.concat(this.chunks).toString();
|
|
722
|
+
callback();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
705
725
|
class ReactRenderServer {
|
|
706
|
-
|
|
726
|
+
// eslint-disable-next-line sort-class-members/sort-class-members
|
|
727
|
+
constructor({ pageService, context, customRender, extendRender, di, renderMode, logger }) {
|
|
707
728
|
this.pageService = pageService;
|
|
708
729
|
this.context = context;
|
|
709
730
|
this.customRender = customRender;
|
|
710
731
|
this.extendRender = extendRender;
|
|
711
732
|
this.di = di;
|
|
733
|
+
this.renderMode = renderMode;
|
|
734
|
+
this.log = logger('module-render');
|
|
712
735
|
}
|
|
713
736
|
render(extractor) {
|
|
714
737
|
var _a;
|
|
@@ -720,6 +743,46 @@ class ReactRenderServer {
|
|
|
720
743
|
if (this.customRender) {
|
|
721
744
|
return this.customRender(renderResult);
|
|
722
745
|
}
|
|
746
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES && this.renderMode === 'streaming') {
|
|
747
|
+
return new Promise((resolve, reject) => {
|
|
748
|
+
const { renderToPipeableStream } = require('react-dom/server');
|
|
749
|
+
const htmlWritable = new HtmlWritable();
|
|
750
|
+
htmlWritable.on('finish', () => {
|
|
751
|
+
resolve(htmlWritable.getHtml());
|
|
752
|
+
});
|
|
753
|
+
const start = Date.now();
|
|
754
|
+
const { log } = this;
|
|
755
|
+
log.info({
|
|
756
|
+
event: 'streaming-render:start',
|
|
757
|
+
});
|
|
758
|
+
const { pipe, abort } = renderToPipeableStream(renderResult, {
|
|
759
|
+
onAllReady() {
|
|
760
|
+
log.info({
|
|
761
|
+
event: 'streaming-render:complete',
|
|
762
|
+
duration: Date.now() - start,
|
|
763
|
+
});
|
|
764
|
+
// here `write` will be called only once
|
|
765
|
+
pipe(htmlWritable);
|
|
766
|
+
},
|
|
767
|
+
onError(error) {
|
|
768
|
+
// error can be inside Suspense boundaries, this is not critical, continue rendering
|
|
769
|
+
log.error({
|
|
770
|
+
event: 'streaming-render:error',
|
|
771
|
+
error,
|
|
772
|
+
});
|
|
773
|
+
},
|
|
774
|
+
onShellError(error) {
|
|
775
|
+
// always critical error, abort rendering
|
|
776
|
+
reject(error);
|
|
777
|
+
},
|
|
778
|
+
});
|
|
779
|
+
setTimeout(() => {
|
|
780
|
+
abort();
|
|
781
|
+
reject(new Error('React renderToPipeableStream timeout exceeded'));
|
|
782
|
+
}, RENDER_TIMEOUT);
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
const { renderToString } = require('react-dom/server');
|
|
723
786
|
return Promise.resolve(renderToString(renderResult));
|
|
724
787
|
}
|
|
725
788
|
}
|
|
@@ -906,6 +969,8 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
906
969
|
customRender: { token: CUSTOM_RENDER, optional: true },
|
|
907
970
|
extendRender: { token: EXTEND_RENDER, optional: true },
|
|
908
971
|
di: DI_TOKEN,
|
|
972
|
+
renderMode: { token: REACT_SERVER_RENDER_MODE, optional: true },
|
|
973
|
+
logger: LOGGER_TOKEN,
|
|
909
974
|
},
|
|
910
975
|
}),
|
|
911
976
|
provide({
|
package/lib/server.js
CHANGED
|
@@ -32,6 +32,7 @@ var path = require('path');
|
|
|
32
32
|
var each = require('@tinkoff/utils/array/each');
|
|
33
33
|
var path$1 = require('@tinkoff/utils/object/path');
|
|
34
34
|
var inline_inline = require('./server_inline.inline.js');
|
|
35
|
+
var stream = require('stream');
|
|
35
36
|
var jsxRuntime = require('react/jsx-runtime');
|
|
36
37
|
var state = require('@tramvai/state');
|
|
37
38
|
var moduleRouter = require('@tramvai/module-router');
|
|
@@ -738,13 +739,35 @@ function renderReact({ pageService, di }, context) {
|
|
|
738
739
|
return (jsxRuntime.jsx(state.Provider, { context: context, serverState: serverState, children: jsxRuntime.jsx(react$1.DIContext.Provider, { value: di, children: jsxRuntime.jsx(PageErrorBoundary, { pageService: pageService, children: jsxRuntime.jsx(Root, { pageService: pageService }) }) }) }));
|
|
739
740
|
}
|
|
740
741
|
|
|
742
|
+
const RENDER_TIMEOUT = 500;
|
|
743
|
+
class HtmlWritable extends stream.Writable {
|
|
744
|
+
constructor() {
|
|
745
|
+
super(...arguments);
|
|
746
|
+
this.chunks = [];
|
|
747
|
+
this.html = '';
|
|
748
|
+
}
|
|
749
|
+
getHtml() {
|
|
750
|
+
return this.html;
|
|
751
|
+
}
|
|
752
|
+
_write(chunk, encoding, callback) {
|
|
753
|
+
this.chunks.push(chunk);
|
|
754
|
+
callback();
|
|
755
|
+
}
|
|
756
|
+
_final(callback) {
|
|
757
|
+
this.html = Buffer.concat(this.chunks).toString();
|
|
758
|
+
callback();
|
|
759
|
+
}
|
|
760
|
+
}
|
|
741
761
|
class ReactRenderServer {
|
|
742
|
-
|
|
762
|
+
// eslint-disable-next-line sort-class-members/sort-class-members
|
|
763
|
+
constructor({ pageService, context, customRender, extendRender, di, renderMode, logger }) {
|
|
743
764
|
this.pageService = pageService;
|
|
744
765
|
this.context = context;
|
|
745
766
|
this.customRender = customRender;
|
|
746
767
|
this.extendRender = extendRender;
|
|
747
768
|
this.di = di;
|
|
769
|
+
this.renderMode = renderMode;
|
|
770
|
+
this.log = logger('module-render');
|
|
748
771
|
}
|
|
749
772
|
render(extractor) {
|
|
750
773
|
var _a;
|
|
@@ -756,7 +779,47 @@ class ReactRenderServer {
|
|
|
756
779
|
if (this.customRender) {
|
|
757
780
|
return this.customRender(renderResult);
|
|
758
781
|
}
|
|
759
|
-
|
|
782
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES && this.renderMode === 'streaming') {
|
|
783
|
+
return new Promise((resolve, reject) => {
|
|
784
|
+
const { renderToPipeableStream } = require('react-dom/server');
|
|
785
|
+
const htmlWritable = new HtmlWritable();
|
|
786
|
+
htmlWritable.on('finish', () => {
|
|
787
|
+
resolve(htmlWritable.getHtml());
|
|
788
|
+
});
|
|
789
|
+
const start = Date.now();
|
|
790
|
+
const { log } = this;
|
|
791
|
+
log.info({
|
|
792
|
+
event: 'streaming-render:start',
|
|
793
|
+
});
|
|
794
|
+
const { pipe, abort } = renderToPipeableStream(renderResult, {
|
|
795
|
+
onAllReady() {
|
|
796
|
+
log.info({
|
|
797
|
+
event: 'streaming-render:complete',
|
|
798
|
+
duration: Date.now() - start,
|
|
799
|
+
});
|
|
800
|
+
// here `write` will be called only once
|
|
801
|
+
pipe(htmlWritable);
|
|
802
|
+
},
|
|
803
|
+
onError(error) {
|
|
804
|
+
// error can be inside Suspense boundaries, this is not critical, continue rendering
|
|
805
|
+
log.error({
|
|
806
|
+
event: 'streaming-render:error',
|
|
807
|
+
error,
|
|
808
|
+
});
|
|
809
|
+
},
|
|
810
|
+
onShellError(error) {
|
|
811
|
+
// always critical error, abort rendering
|
|
812
|
+
reject(error);
|
|
813
|
+
},
|
|
814
|
+
});
|
|
815
|
+
setTimeout(() => {
|
|
816
|
+
abort();
|
|
817
|
+
reject(new Error('React renderToPipeableStream timeout exceeded'));
|
|
818
|
+
}, RENDER_TIMEOUT);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
const { renderToString } = require('react-dom/server');
|
|
822
|
+
return Promise.resolve(renderToString(renderResult));
|
|
760
823
|
}
|
|
761
824
|
}
|
|
762
825
|
|
|
@@ -942,6 +1005,8 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
942
1005
|
customRender: { token: tokensRender.CUSTOM_RENDER, optional: true },
|
|
943
1006
|
extendRender: { token: tokensRender.EXTEND_RENDER, optional: true },
|
|
944
1007
|
di: core.DI_TOKEN,
|
|
1008
|
+
renderMode: { token: tokensRender.REACT_SERVER_RENDER_MODE, optional: true },
|
|
1009
|
+
logger: tokensCommon.LOGGER_TOKEN,
|
|
945
1010
|
},
|
|
946
1011
|
}),
|
|
947
1012
|
core.provide({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-render",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.34.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"@tinkoff/htmlpagebuilder": "0.5.5",
|
|
27
27
|
"@tinkoff/layout-factory": "0.3.4",
|
|
28
28
|
"@tinkoff/url": "0.8.4",
|
|
29
|
-
"@tinkoff/user-agent": "0.4.
|
|
30
|
-
"@tramvai/module-client-hints": "2.
|
|
31
|
-
"@tramvai/module-router": "2.
|
|
32
|
-
"@tramvai/react": "2.
|
|
29
|
+
"@tinkoff/user-agent": "0.4.77",
|
|
30
|
+
"@tramvai/module-client-hints": "2.34.0",
|
|
31
|
+
"@tramvai/module-router": "2.34.0",
|
|
32
|
+
"@tramvai/react": "2.34.0",
|
|
33
33
|
"@tramvai/safe-strings": "0.5.5",
|
|
34
|
-
"@tramvai/tokens-render": "2.
|
|
35
|
-
"@tramvai/experiments": "2.
|
|
34
|
+
"@tramvai/tokens-render": "2.34.0",
|
|
35
|
+
"@tramvai/experiments": "2.34.0",
|
|
36
36
|
"@types/loadable__server": "^5.12.6",
|
|
37
37
|
"node-fetch": "^2.6.1"
|
|
38
38
|
},
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
"@tinkoff/dippy": "0.8.8",
|
|
41
41
|
"@tinkoff/utils": "^2.1.2",
|
|
42
42
|
"@tinkoff/react-hooks": "0.1.4",
|
|
43
|
-
"@tramvai/cli": "2.
|
|
44
|
-
"@tramvai/core": "2.
|
|
45
|
-
"@tramvai/module-common": "2.
|
|
46
|
-
"@tramvai/state": "2.
|
|
47
|
-
"@tramvai/test-helpers": "2.
|
|
48
|
-
"@tramvai/tokens-common": "2.
|
|
49
|
-
"@tramvai/tokens-router": "2.
|
|
50
|
-
"@tramvai/tokens-server-private": "2.
|
|
43
|
+
"@tramvai/cli": "2.34.0",
|
|
44
|
+
"@tramvai/core": "2.34.0",
|
|
45
|
+
"@tramvai/module-common": "2.34.0",
|
|
46
|
+
"@tramvai/state": "2.34.0",
|
|
47
|
+
"@tramvai/test-helpers": "2.34.0",
|
|
48
|
+
"@tramvai/tokens-common": "2.34.0",
|
|
49
|
+
"@tramvai/tokens-router": "2.34.0",
|
|
50
|
+
"@tramvai/tokens-server-private": "2.34.0",
|
|
51
51
|
"express": "^4.17.1",
|
|
52
52
|
"prop-types": "^15.6.2",
|
|
53
53
|
"react": ">=16.14.0",
|