@tramvai/module-render 3.17.0 → 3.19.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.
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import type { ExtractDependencyType } from '@tinkoff/dippy';
|
|
2
2
|
import type { DI_TOKEN } from '@tramvai/core';
|
|
3
|
-
import type { CONTEXT_TOKEN, LOGGER_TOKEN } from '@tramvai/module-common';
|
|
4
|
-
import type { EXTEND_RENDER, CUSTOM_RENDER, REACT_SERVER_RENDER_MODE, WebpackStats } from '@tramvai/tokens-render';
|
|
3
|
+
import type { CONTEXT_TOKEN, DEFERRED_ACTIONS_MAP_TOKEN, LOGGER_TOKEN } from '@tramvai/module-common';
|
|
4
|
+
import type { EXTEND_RENDER, CUSTOM_RENDER, REACT_SERVER_RENDER_MODE, WebpackStats, REACT_STREAMING_RENDER_TIMEOUT } from '@tramvai/tokens-render';
|
|
5
5
|
import type { ChunkExtractor } from '@loadable/server';
|
|
6
6
|
import type { SERVER_RESPONSE_STREAM, SERVER_RESPONSE_TASK_MANAGER } from '@tramvai/tokens-server-private';
|
|
7
|
+
type StreamingTimeout = ExtractDependencyType<typeof REACT_STREAMING_RENDER_TIMEOUT>;
|
|
8
|
+
type DeferredActions = ExtractDependencyType<typeof DEFERRED_ACTIONS_MAP_TOKEN>;
|
|
7
9
|
export declare class ReactRenderServer {
|
|
8
10
|
customRender: typeof CUSTOM_RENDER;
|
|
9
11
|
extendRender: ExtractDependencyType<typeof EXTEND_RENDER>;
|
|
10
12
|
context: typeof CONTEXT_TOKEN;
|
|
13
|
+
deferredActions: DeferredActions;
|
|
11
14
|
di: typeof DI_TOKEN;
|
|
12
15
|
log: ReturnType<typeof LOGGER_TOKEN>;
|
|
13
16
|
responseTaskManager: typeof SERVER_RESPONSE_TASK_MANAGER;
|
|
14
17
|
responseStream: typeof SERVER_RESPONSE_STREAM;
|
|
18
|
+
streamingTimeout: StreamingTimeout;
|
|
15
19
|
renderMode: typeof REACT_SERVER_RENDER_MODE;
|
|
16
|
-
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, }: {
|
|
20
|
+
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, streamingTimeout, deferredActions, }: {
|
|
17
21
|
context: any;
|
|
18
22
|
customRender: any;
|
|
19
23
|
extendRender: any;
|
|
@@ -22,10 +26,13 @@ export declare class ReactRenderServer {
|
|
|
22
26
|
logger: any;
|
|
23
27
|
responseTaskManager: any;
|
|
24
28
|
responseStream: any;
|
|
29
|
+
streamingTimeout: any;
|
|
30
|
+
deferredActions: any;
|
|
25
31
|
});
|
|
26
32
|
render({ extractor, stats, }: {
|
|
27
33
|
extractor: ChunkExtractor;
|
|
28
34
|
stats: WebpackStats;
|
|
29
35
|
}): Promise<string>;
|
|
30
36
|
}
|
|
37
|
+
export {};
|
|
31
38
|
//# sourceMappingURL=ReactRenderServer.d.ts.map
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Writable } from 'stream';
|
|
2
|
+
import { AbortedDeferredError, AbortedStreamError } from '@tinkoff/errors';
|
|
2
3
|
import each from '@tinkoff/utils/array/each';
|
|
3
4
|
import { renderReact } from '../react/index.es.js';
|
|
4
5
|
import { flushFiles } from './blocks/utils/flushFiles.es.js';
|
|
5
6
|
|
|
6
|
-
// @todo customize
|
|
7
|
-
const RENDER_TIMEOUT = 30000;
|
|
8
7
|
class HtmlWritable extends Writable {
|
|
9
8
|
constructor({ responseTaskManager, responseStream, extractor, stats, }) {
|
|
10
9
|
super();
|
|
@@ -66,7 +65,7 @@ const Deferred = () => {
|
|
|
66
65
|
};
|
|
67
66
|
class ReactRenderServer {
|
|
68
67
|
// eslint-disable-next-line sort-class-members/sort-class-members
|
|
69
|
-
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, }) {
|
|
68
|
+
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, streamingTimeout, deferredActions, }) {
|
|
70
69
|
this.context = context;
|
|
71
70
|
this.customRender = customRender;
|
|
72
71
|
this.extendRender = extendRender;
|
|
@@ -75,6 +74,8 @@ class ReactRenderServer {
|
|
|
75
74
|
this.log = logger('module-render');
|
|
76
75
|
this.responseTaskManager = responseTaskManager;
|
|
77
76
|
this.responseStream = responseStream;
|
|
77
|
+
this.streamingTimeout = streamingTimeout;
|
|
78
|
+
this.deferredActions = deferredActions;
|
|
78
79
|
}
|
|
79
80
|
render({ extractor, stats, }) {
|
|
80
81
|
var _a;
|
|
@@ -110,6 +111,9 @@ class ReactRenderServer {
|
|
|
110
111
|
log.info({
|
|
111
112
|
event: 'streaming-render:start',
|
|
112
113
|
});
|
|
114
|
+
const timeout = this.streamingTimeout;
|
|
115
|
+
const unfinishedActions = [];
|
|
116
|
+
let isAborted = false;
|
|
113
117
|
const { pipe, abort } = renderToPipeableStream(renderResult, {
|
|
114
118
|
// we need to run hydration only after first chunk is sent to client
|
|
115
119
|
// https://github.com/reactwg/react-18/discussions/114
|
|
@@ -136,7 +140,12 @@ class ReactRenderServer {
|
|
|
136
140
|
// so this is a best place to error logging
|
|
137
141
|
log.error({
|
|
138
142
|
event: 'streaming-render:error',
|
|
139
|
-
error
|
|
143
|
+
error: isAborted
|
|
144
|
+
? new AbortedStreamError({
|
|
145
|
+
reason: `${timeout}ms timeout exceeded`,
|
|
146
|
+
unfinishedActions,
|
|
147
|
+
})
|
|
148
|
+
: error,
|
|
140
149
|
});
|
|
141
150
|
},
|
|
142
151
|
onShellError(error) {
|
|
@@ -144,10 +153,24 @@ class ReactRenderServer {
|
|
|
144
153
|
reject(error);
|
|
145
154
|
},
|
|
146
155
|
});
|
|
156
|
+
// global response stream timeo
|
|
147
157
|
setTimeout(() => {
|
|
158
|
+
isAborted = true;
|
|
159
|
+
// abort unfinished deferred actions
|
|
160
|
+
this.deferredActions.forEach((action, name) => {
|
|
161
|
+
if (action.isRejected() || action.isResolved()) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
unfinishedActions.push(name);
|
|
165
|
+
action.reject(new AbortedDeferredError());
|
|
166
|
+
});
|
|
167
|
+
// abort render stream
|
|
148
168
|
abort();
|
|
149
|
-
reject(new
|
|
150
|
-
|
|
169
|
+
reject(new AbortedStreamError({
|
|
170
|
+
reason: `${timeout}ms timeout exceeded`,
|
|
171
|
+
unfinishedActions,
|
|
172
|
+
}));
|
|
173
|
+
}, timeout);
|
|
151
174
|
});
|
|
152
175
|
}
|
|
153
176
|
const { renderToString } = require('react-dom/server');
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var stream = require('stream');
|
|
6
|
+
var errors = require('@tinkoff/errors');
|
|
6
7
|
var each = require('@tinkoff/utils/array/each');
|
|
7
8
|
var index = require('../react/index.js');
|
|
8
9
|
var flushFiles = require('./blocks/utils/flushFiles.js');
|
|
@@ -11,8 +12,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
11
12
|
|
|
12
13
|
var each__default = /*#__PURE__*/_interopDefaultLegacy(each);
|
|
13
14
|
|
|
14
|
-
// @todo customize
|
|
15
|
-
const RENDER_TIMEOUT = 30000;
|
|
16
15
|
class HtmlWritable extends stream.Writable {
|
|
17
16
|
constructor({ responseTaskManager, responseStream, extractor, stats, }) {
|
|
18
17
|
super();
|
|
@@ -74,7 +73,7 @@ const Deferred = () => {
|
|
|
74
73
|
};
|
|
75
74
|
class ReactRenderServer {
|
|
76
75
|
// eslint-disable-next-line sort-class-members/sort-class-members
|
|
77
|
-
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, }) {
|
|
76
|
+
constructor({ context, customRender, extendRender, di, renderMode, logger, responseTaskManager, responseStream, streamingTimeout, deferredActions, }) {
|
|
78
77
|
this.context = context;
|
|
79
78
|
this.customRender = customRender;
|
|
80
79
|
this.extendRender = extendRender;
|
|
@@ -83,6 +82,8 @@ class ReactRenderServer {
|
|
|
83
82
|
this.log = logger('module-render');
|
|
84
83
|
this.responseTaskManager = responseTaskManager;
|
|
85
84
|
this.responseStream = responseStream;
|
|
85
|
+
this.streamingTimeout = streamingTimeout;
|
|
86
|
+
this.deferredActions = deferredActions;
|
|
86
87
|
}
|
|
87
88
|
render({ extractor, stats, }) {
|
|
88
89
|
var _a;
|
|
@@ -118,6 +119,9 @@ class ReactRenderServer {
|
|
|
118
119
|
log.info({
|
|
119
120
|
event: 'streaming-render:start',
|
|
120
121
|
});
|
|
122
|
+
const timeout = this.streamingTimeout;
|
|
123
|
+
const unfinishedActions = [];
|
|
124
|
+
let isAborted = false;
|
|
121
125
|
const { pipe, abort } = renderToPipeableStream(renderResult, {
|
|
122
126
|
// we need to run hydration only after first chunk is sent to client
|
|
123
127
|
// https://github.com/reactwg/react-18/discussions/114
|
|
@@ -144,7 +148,12 @@ class ReactRenderServer {
|
|
|
144
148
|
// so this is a best place to error logging
|
|
145
149
|
log.error({
|
|
146
150
|
event: 'streaming-render:error',
|
|
147
|
-
error
|
|
151
|
+
error: isAborted
|
|
152
|
+
? new errors.AbortedStreamError({
|
|
153
|
+
reason: `${timeout}ms timeout exceeded`,
|
|
154
|
+
unfinishedActions,
|
|
155
|
+
})
|
|
156
|
+
: error,
|
|
148
157
|
});
|
|
149
158
|
},
|
|
150
159
|
onShellError(error) {
|
|
@@ -152,10 +161,24 @@ class ReactRenderServer {
|
|
|
152
161
|
reject(error);
|
|
153
162
|
},
|
|
154
163
|
});
|
|
164
|
+
// global response stream timeo
|
|
155
165
|
setTimeout(() => {
|
|
166
|
+
isAborted = true;
|
|
167
|
+
// abort unfinished deferred actions
|
|
168
|
+
this.deferredActions.forEach((action, name) => {
|
|
169
|
+
if (action.isRejected() || action.isResolved()) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
unfinishedActions.push(name);
|
|
173
|
+
action.reject(new errors.AbortedDeferredError());
|
|
174
|
+
});
|
|
175
|
+
// abort render stream
|
|
156
176
|
abort();
|
|
157
|
-
reject(new
|
|
158
|
-
|
|
177
|
+
reject(new errors.AbortedStreamError({
|
|
178
|
+
reason: `${timeout}ms timeout exceeded`,
|
|
179
|
+
unfinishedActions,
|
|
180
|
+
}));
|
|
181
|
+
}, timeout);
|
|
159
182
|
});
|
|
160
183
|
}
|
|
161
184
|
const { renderToString } = require('react-dom/server');
|
package/lib/server.es.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
2
|
import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
|
|
3
|
-
import { CREATE_CACHE_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/tokens-common';
|
|
3
|
+
import { CREATE_CACHE_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN, DEFERRED_ACTIONS_MAP_TOKEN } from '@tramvai/tokens-common';
|
|
4
4
|
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
5
5
|
import { ClientHintsModule, USER_AGENT_TOKEN } from '@tramvai/module-client-hints';
|
|
6
|
-
import { RESOURCES_REGISTRY, RESOURCE_INLINE_OPTIONS, BACK_FORWARD_CACHE_ENABLED, RENDER_SLOTS, POLYFILL_CONDITION, HTML_ATTRS, MODERN_SATISFIES_TOKEN, RENDER_FLOW_AFTER_TOKEN, FETCH_WEBPACK_STATS_TOKEN, REACT_SERVER_RENDER_MODE, CUSTOM_RENDER, EXTEND_RENDER, ResourceType } from '@tramvai/tokens-render';
|
|
6
|
+
import { RESOURCES_REGISTRY, RESOURCE_INLINE_OPTIONS, BACK_FORWARD_CACHE_ENABLED, RENDER_SLOTS, POLYFILL_CONDITION, HTML_ATTRS, MODERN_SATISFIES_TOKEN, RENDER_FLOW_AFTER_TOKEN, FETCH_WEBPACK_STATS_TOKEN, REACT_SERVER_RENDER_MODE, CUSTOM_RENDER, EXTEND_RENDER, REACT_STREAMING_RENDER_TIMEOUT, ResourceType } from '@tramvai/tokens-render';
|
|
7
7
|
export * from '@tramvai/tokens-render';
|
|
8
8
|
import { Scope, optional } from '@tinkoff/dippy';
|
|
9
9
|
import { satisfies } from '@tinkoff/user-agent';
|
|
@@ -213,6 +213,8 @@ Page Error Boundary will be rendered for the client`,
|
|
|
213
213
|
logger: LOGGER_TOKEN,
|
|
214
214
|
responseTaskManager: SERVER_RESPONSE_TASK_MANAGER,
|
|
215
215
|
responseStream: SERVER_RESPONSE_STREAM,
|
|
216
|
+
streamingTimeout: REACT_STREAMING_RENDER_TIMEOUT,
|
|
217
|
+
deferredActions: DEFERRED_ACTIONS_MAP_TOKEN,
|
|
216
218
|
},
|
|
217
219
|
}),
|
|
218
220
|
provide({
|
|
@@ -280,9 +282,8 @@ Page Error Boundary will be rendered for the client`,
|
|
|
280
282
|
provide({
|
|
281
283
|
provide: 'modernSatisfiesMemoryCache',
|
|
282
284
|
scope: Scope.SINGLETON,
|
|
283
|
-
// @todo - use larger `max` option and `memory-lfu` type after successful TCORE-4668 experiment
|
|
284
285
|
useFactory: ({ createCache }) => {
|
|
285
|
-
return createCache('memory', { max:
|
|
286
|
+
return createCache('memory', { max: 200 });
|
|
286
287
|
},
|
|
287
288
|
deps: {
|
|
288
289
|
createCache: CREATE_CACHE_TOKEN,
|
|
@@ -300,6 +301,10 @@ Page Error Boundary will be rendered for the client`,
|
|
|
300
301
|
provide: REACT_SERVER_RENDER_MODE,
|
|
301
302
|
useValue: 'sync',
|
|
302
303
|
}),
|
|
304
|
+
provide({
|
|
305
|
+
provide: REACT_STREAMING_RENDER_TIMEOUT,
|
|
306
|
+
useValue: 5000,
|
|
307
|
+
}),
|
|
303
308
|
],
|
|
304
309
|
})
|
|
305
310
|
], RenderModule);
|
package/lib/server.js
CHANGED
|
@@ -214,6 +214,8 @@ Page Error Boundary will be rendered for the client`,
|
|
|
214
214
|
logger: tokensCommon.LOGGER_TOKEN,
|
|
215
215
|
responseTaskManager: tokensServerPrivate.SERVER_RESPONSE_TASK_MANAGER,
|
|
216
216
|
responseStream: tokensServerPrivate.SERVER_RESPONSE_STREAM,
|
|
217
|
+
streamingTimeout: tokensRender.REACT_STREAMING_RENDER_TIMEOUT,
|
|
218
|
+
deferredActions: tokensCommon.DEFERRED_ACTIONS_MAP_TOKEN,
|
|
217
219
|
},
|
|
218
220
|
}),
|
|
219
221
|
core.provide({
|
|
@@ -281,9 +283,8 @@ Page Error Boundary will be rendered for the client`,
|
|
|
281
283
|
core.provide({
|
|
282
284
|
provide: 'modernSatisfiesMemoryCache',
|
|
283
285
|
scope: dippy.Scope.SINGLETON,
|
|
284
|
-
// @todo - use larger `max` option and `memory-lfu` type after successful TCORE-4668 experiment
|
|
285
286
|
useFactory: ({ createCache }) => {
|
|
286
|
-
return createCache('memory', { max:
|
|
287
|
+
return createCache('memory', { max: 200 });
|
|
287
288
|
},
|
|
288
289
|
deps: {
|
|
289
290
|
createCache: tokensCommon.CREATE_CACHE_TOKEN,
|
|
@@ -301,6 +302,10 @@ Page Error Boundary will be rendered for the client`,
|
|
|
301
302
|
provide: tokensRender.REACT_SERVER_RENDER_MODE,
|
|
302
303
|
useValue: 'sync',
|
|
303
304
|
}),
|
|
305
|
+
core.provide({
|
|
306
|
+
provide: tokensRender.REACT_STREAMING_RENDER_TIMEOUT,
|
|
307
|
+
useValue: 5000,
|
|
308
|
+
}),
|
|
304
309
|
],
|
|
305
310
|
})
|
|
306
311
|
], exports.RenderModule);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-render",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
"@loadable/server": "^5.15.0",
|
|
25
25
|
"@tinkoff/htmlpagebuilder": "0.6.1",
|
|
26
26
|
"@tinkoff/layout-factory": "0.4.1",
|
|
27
|
-
"@tinkoff/errors": "0.4.
|
|
27
|
+
"@tinkoff/errors": "0.4.2",
|
|
28
28
|
"@tinkoff/url": "0.9.2",
|
|
29
|
-
"@tinkoff/user-agent": "0.5.
|
|
30
|
-
"@tramvai/module-client-hints": "3.
|
|
31
|
-
"@tramvai/module-router": "3.
|
|
32
|
-
"@tramvai/react": "3.
|
|
29
|
+
"@tinkoff/user-agent": "0.5.46",
|
|
30
|
+
"@tramvai/module-client-hints": "3.19.0",
|
|
31
|
+
"@tramvai/module-router": "3.19.0",
|
|
32
|
+
"@tramvai/react": "3.19.0",
|
|
33
33
|
"@tramvai/safe-strings": "0.6.2",
|
|
34
|
-
"@tramvai/tokens-render": "3.
|
|
35
|
-
"@tramvai/experiments": "3.
|
|
34
|
+
"@tramvai/tokens-render": "3.19.0",
|
|
35
|
+
"@tramvai/experiments": "3.19.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.9.1",
|
|
41
41
|
"@tinkoff/utils": "^2.1.2",
|
|
42
42
|
"@tinkoff/react-hooks": "0.2.1",
|
|
43
|
-
"@tramvai/cli": "3.
|
|
44
|
-
"@tramvai/core": "3.
|
|
45
|
-
"@tramvai/module-common": "3.
|
|
46
|
-
"@tramvai/state": "3.
|
|
47
|
-
"@tramvai/test-helpers": "3.
|
|
48
|
-
"@tramvai/tokens-common": "3.
|
|
49
|
-
"@tramvai/tokens-router": "3.
|
|
50
|
-
"@tramvai/tokens-server-private": "3.
|
|
43
|
+
"@tramvai/cli": "3.19.0",
|
|
44
|
+
"@tramvai/core": "3.19.0",
|
|
45
|
+
"@tramvai/module-common": "3.19.0",
|
|
46
|
+
"@tramvai/state": "3.19.0",
|
|
47
|
+
"@tramvai/test-helpers": "3.19.0",
|
|
48
|
+
"@tramvai/tokens-common": "3.19.0",
|
|
49
|
+
"@tramvai/tokens-router": "3.19.0",
|
|
50
|
+
"@tramvai/tokens-server-private": "3.19.0",
|
|
51
51
|
"express": "^4.17.1",
|
|
52
52
|
"prop-types": "^15.6.2",
|
|
53
53
|
"react": ">=16.14.0",
|