@tramvai/module-server 2.134.0 → 2.137.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/taskManager.d.ts +9 -0
- package/lib/server/taskManager.es.js +32 -0
- package/lib/server/taskManager.js +36 -0
- package/lib/server/webApp.d.ts +1 -1
- package/lib/server/webApp.es.js +29 -4
- package/lib/server/webApp.js +27 -2
- package/lib/server.es.js +13 -1
- package/lib/server.js +12 -0
- package/package.json +14 -14
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ServerResponseTaskManager as IServerResponseTaskManager, ServerResponseTask } from '@tramvai/tokens-server-private';
|
|
2
|
+
export declare class ServerResponseTaskManager implements IServerResponseTaskManager {
|
|
3
|
+
private tasks;
|
|
4
|
+
private processedTasks;
|
|
5
|
+
private status;
|
|
6
|
+
push(task: ServerResponseTask): void;
|
|
7
|
+
processQueue(): void;
|
|
8
|
+
closeQueue(): Promise<any[]>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
class ServerResponseTaskManager {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.tasks = [];
|
|
4
|
+
this.processedTasks = [];
|
|
5
|
+
this.status = 'idle';
|
|
6
|
+
}
|
|
7
|
+
push(task) {
|
|
8
|
+
if (this.status === 'closed') {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
this.tasks.push(task);
|
|
12
|
+
if (this.status === 'running') {
|
|
13
|
+
this.processQueue();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
processQueue() {
|
|
17
|
+
if (this.status === 'closed') {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.status = 'running';
|
|
21
|
+
while (this.tasks.length > 0 && this.status === 'running') {
|
|
22
|
+
const task = this.tasks.shift();
|
|
23
|
+
this.processedTasks.push(task());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
closeQueue() {
|
|
27
|
+
this.status = 'closed';
|
|
28
|
+
return Promise.all(this.processedTasks);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { ServerResponseTaskManager };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
class ServerResponseTaskManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.tasks = [];
|
|
8
|
+
this.processedTasks = [];
|
|
9
|
+
this.status = 'idle';
|
|
10
|
+
}
|
|
11
|
+
push(task) {
|
|
12
|
+
if (this.status === 'closed') {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
this.tasks.push(task);
|
|
16
|
+
if (this.status === 'running') {
|
|
17
|
+
this.processQueue();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
processQueue() {
|
|
21
|
+
if (this.status === 'closed') {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
this.status = 'running';
|
|
25
|
+
while (this.tasks.length > 0 && this.status === 'running') {
|
|
26
|
+
const task = this.tasks.shift();
|
|
27
|
+
this.processedTasks.push(task());
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
closeQueue() {
|
|
31
|
+
this.status = 'closed';
|
|
32
|
+
return Promise.all(this.processedTasks);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
exports.ServerResponseTaskManager = ServerResponseTaskManager;
|
package/lib/server/webApp.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { EXECUTION_CONTEXT_MANAGER_TOKEN, LOGGER_TOKEN } from '@tramvai/tok
|
|
|
2
2
|
import type { COMMAND_LINE_RUNNER_TOKEN } from '@tramvai/core';
|
|
3
3
|
import type { SERVER_TOKEN } from '@tramvai/tokens-server';
|
|
4
4
|
import type { WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_AFTER_INIT_TOKEN, WEB_FASTIFY_APP_BEFORE_INIT_TOKEN, WEB_FASTIFY_APP_INIT_TOKEN, WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN, WEB_FASTIFY_APP_AFTER_ERROR_TOKEN, WEB_FASTIFY_APP_METRICS_TOKEN } from '@tramvai/tokens-server-private';
|
|
5
|
-
import type
|
|
5
|
+
import { type FETCH_WEBPACK_STATS_TOKEN } from '@tramvai/tokens-render';
|
|
6
6
|
import type { ExtractDependencyType } from '@tinkoff/dippy';
|
|
7
7
|
export declare const webAppFactory: ({ server }: {
|
|
8
8
|
server: typeof SERVER_TOKEN;
|
package/lib/server/webApp.es.js
CHANGED
|
@@ -3,8 +3,9 @@ import { fastifyCookie } from '@fastify/cookie';
|
|
|
3
3
|
import fastifyFormBody from '@fastify/formbody';
|
|
4
4
|
import { ROOT_EXECUTION_CONTEXT_TOKEN, RESPONSE_MANAGER_TOKEN } from '@tramvai/tokens-common';
|
|
5
5
|
import { Scope } from '@tramvai/core';
|
|
6
|
-
import { FASTIFY_REQUEST, FASTIFY_RESPONSE } from '@tramvai/tokens-server-private';
|
|
7
|
-
import {
|
|
6
|
+
import { FASTIFY_REQUEST, FASTIFY_RESPONSE, SERVER_RESPONSE_STREAM, SERVER_RESPONSE_TASK_MANAGER } from '@tramvai/tokens-server-private';
|
|
7
|
+
import { REACT_SERVER_RENDER_MODE } from '@tramvai/tokens-render';
|
|
8
|
+
import { provide, optional } from '@tinkoff/dippy';
|
|
8
9
|
import { errorHandler } from './error.es.js';
|
|
9
10
|
|
|
10
11
|
const webAppFactory = ({ server }) => {
|
|
@@ -65,7 +66,11 @@ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextMan
|
|
|
65
66
|
useValue: reply,
|
|
66
67
|
},
|
|
67
68
|
]);
|
|
69
|
+
const serverResponseStream = di.get(SERVER_RESPONSE_STREAM);
|
|
70
|
+
const serverResponseTaskManager = di.get(SERVER_RESPONSE_TASK_MANAGER);
|
|
68
71
|
const responseManager = di.get(RESPONSE_MANAGER_TOKEN);
|
|
72
|
+
// @todo incorrect type inference for optional provider
|
|
73
|
+
const renderMode = di.get(optional(REACT_SERVER_RENDER_MODE));
|
|
69
74
|
if (reply.sent) {
|
|
70
75
|
log.debug({
|
|
71
76
|
event: 'response-ended',
|
|
@@ -77,8 +82,28 @@ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextMan
|
|
|
77
82
|
reply
|
|
78
83
|
.header('content-type', 'text/html')
|
|
79
84
|
.headers(responseManager.getHeaders())
|
|
80
|
-
.status(responseManager.getStatus())
|
|
81
|
-
|
|
85
|
+
.status(responseManager.getStatus());
|
|
86
|
+
if (renderMode === 'streaming') {
|
|
87
|
+
const appHtmlsAttrs = di.get('tramvai app html attributes');
|
|
88
|
+
// split HTML for sequential React HTML chunks streaming inside .application tag
|
|
89
|
+
const [headAndBodyStart, bodyEnd] = responseManager.getBody().split(`<div ${appHtmlsAttrs}></div>`);
|
|
90
|
+
// https://fastify.dev/docs/latest/Reference/Reply/#streams
|
|
91
|
+
reply.send(serverResponseStream);
|
|
92
|
+
// send head and start of body tags immediately
|
|
93
|
+
serverResponseStream.push(`${headAndBodyStart}<div ${appHtmlsAttrs}>`);
|
|
94
|
+
// run all tasks, chunks for renderToPipeableStream will be sent here
|
|
95
|
+
// in future, it can be done earlier, e.g. as Early Hints module
|
|
96
|
+
serverResponseTaskManager.processQueue();
|
|
97
|
+
// wait all tasks
|
|
98
|
+
await serverResponseTaskManager.closeQueue();
|
|
99
|
+
// writing the end of body
|
|
100
|
+
serverResponseStream.push(`</div>${bodyEnd}`);
|
|
101
|
+
// end response
|
|
102
|
+
serverResponseStream.push(null);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
reply.send(responseManager.getBody());
|
|
106
|
+
}
|
|
82
107
|
}
|
|
83
108
|
});
|
|
84
109
|
}
|
package/lib/server/webApp.js
CHANGED
|
@@ -8,6 +8,7 @@ var fastifyFormBody = require('@fastify/formbody');
|
|
|
8
8
|
var tokensCommon = require('@tramvai/tokens-common');
|
|
9
9
|
var core = require('@tramvai/core');
|
|
10
10
|
var tokensServerPrivate = require('@tramvai/tokens-server-private');
|
|
11
|
+
var tokensRender = require('@tramvai/tokens-render');
|
|
11
12
|
var dippy = require('@tinkoff/dippy');
|
|
12
13
|
var error = require('./error.js');
|
|
13
14
|
|
|
@@ -74,7 +75,11 @@ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextMan
|
|
|
74
75
|
useValue: reply,
|
|
75
76
|
},
|
|
76
77
|
]);
|
|
78
|
+
const serverResponseStream = di.get(tokensServerPrivate.SERVER_RESPONSE_STREAM);
|
|
79
|
+
const serverResponseTaskManager = di.get(tokensServerPrivate.SERVER_RESPONSE_TASK_MANAGER);
|
|
77
80
|
const responseManager = di.get(tokensCommon.RESPONSE_MANAGER_TOKEN);
|
|
81
|
+
// @todo incorrect type inference for optional provider
|
|
82
|
+
const renderMode = di.get(dippy.optional(tokensRender.REACT_SERVER_RENDER_MODE));
|
|
78
83
|
if (reply.sent) {
|
|
79
84
|
log.debug({
|
|
80
85
|
event: 'response-ended',
|
|
@@ -86,8 +91,28 @@ const webAppInitCommand = ({ app, logger, commandLineRunner, executionContextMan
|
|
|
86
91
|
reply
|
|
87
92
|
.header('content-type', 'text/html')
|
|
88
93
|
.headers(responseManager.getHeaders())
|
|
89
|
-
.status(responseManager.getStatus())
|
|
90
|
-
|
|
94
|
+
.status(responseManager.getStatus());
|
|
95
|
+
if (renderMode === 'streaming') {
|
|
96
|
+
const appHtmlsAttrs = di.get('tramvai app html attributes');
|
|
97
|
+
// split HTML for sequential React HTML chunks streaming inside .application tag
|
|
98
|
+
const [headAndBodyStart, bodyEnd] = responseManager.getBody().split(`<div ${appHtmlsAttrs}></div>`);
|
|
99
|
+
// https://fastify.dev/docs/latest/Reference/Reply/#streams
|
|
100
|
+
reply.send(serverResponseStream);
|
|
101
|
+
// send head and start of body tags immediately
|
|
102
|
+
serverResponseStream.push(`${headAndBodyStart}<div ${appHtmlsAttrs}>`);
|
|
103
|
+
// run all tasks, chunks for renderToPipeableStream will be sent here
|
|
104
|
+
// in future, it can be done earlier, e.g. as Early Hints module
|
|
105
|
+
serverResponseTaskManager.processQueue();
|
|
106
|
+
// wait all tasks
|
|
107
|
+
await serverResponseTaskManager.closeQueue();
|
|
108
|
+
// writing the end of body
|
|
109
|
+
serverResponseStream.push(`</div>${bodyEnd}`);
|
|
110
|
+
// end response
|
|
111
|
+
serverResponseStream.push(null);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
reply.send(responseManager.getBody());
|
|
115
|
+
}
|
|
91
116
|
}
|
|
92
117
|
});
|
|
93
118
|
}
|
package/lib/server.es.js
CHANGED
|
@@ -5,11 +5,12 @@ import { Module, provide, Scope, commandLineListTokens, COMMAND_LINE_RUNNER_TOKE
|
|
|
5
5
|
import { SERVER_TOKEN } from '@tramvai/tokens-server';
|
|
6
6
|
export * from '@tramvai/tokens-server';
|
|
7
7
|
import { FETCH_WEBPACK_STATS_TOKEN } from '@tramvai/tokens-render';
|
|
8
|
-
import { SERVER_FACTORY_TOKEN, WEB_FASTIFY_APP_FACTORY_TOKEN, WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_BEFORE_INIT_TOKEN, WEB_FASTIFY_APP_INIT_TOKEN, WEB_FASTIFY_APP_AFTER_INIT_TOKEN, WEB_FASTIFY_APP_METRICS_TOKEN, WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN, WEB_FASTIFY_APP_AFTER_ERROR_TOKEN } from '@tramvai/tokens-server-private';
|
|
8
|
+
import { SERVER_FACTORY_TOKEN, WEB_FASTIFY_APP_FACTORY_TOKEN, WEB_FASTIFY_APP_TOKEN, WEB_FASTIFY_APP_BEFORE_INIT_TOKEN, WEB_FASTIFY_APP_INIT_TOKEN, WEB_FASTIFY_APP_AFTER_INIT_TOKEN, WEB_FASTIFY_APP_METRICS_TOKEN, WEB_FASTIFY_APP_LIMITER_TOKEN, WEB_FASTIFY_APP_BEFORE_ERROR_TOKEN, WEB_FASTIFY_APP_AFTER_ERROR_TOKEN, SERVER_RESPONSE_STREAM, SERVER_RESPONSE_TASK_MANAGER } from '@tramvai/tokens-server-private';
|
|
9
9
|
import { LOGGER_TOKEN, EXECUTION_CONTEXT_MANAGER_TOKEN, ENV_MANAGER_TOKEN, ENV_USED_TOKEN } from '@tramvai/tokens-common';
|
|
10
10
|
import { MetricsModule } from '@tramvai/module-metrics';
|
|
11
11
|
import { CacheWarmupModule } from '@tramvai/module-cache-warmup';
|
|
12
12
|
import { ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN } from '@tramvai/react';
|
|
13
|
+
import { PassThrough } from 'stream';
|
|
13
14
|
import { serverFactory, serverListenCommand } from './server/server.es.js';
|
|
14
15
|
import { webAppFactory, webAppInitCommand } from './server/webApp.es.js';
|
|
15
16
|
import { staticAppCommand } from './server/static.es.js';
|
|
@@ -25,6 +26,7 @@ import { UtilityServerModule } from './modules/utilityServer.es.js';
|
|
|
25
26
|
import { KeepAliveModule } from './modules/keepAlive.es.js';
|
|
26
27
|
import { ServerTimingModule } from './modules/serverTiming.es.js';
|
|
27
28
|
import { EarlyHintsModule } from './modules/earlyHints/index.es.js';
|
|
29
|
+
import { ServerResponseTaskManager } from './server/taskManager.es.js';
|
|
28
30
|
|
|
29
31
|
if (typeof setDefaultResultOrder === 'function') {
|
|
30
32
|
setDefaultResultOrder('ipv4first');
|
|
@@ -165,6 +167,16 @@ ServerModule = __decorate([
|
|
|
165
167
|
appInfo: APP_INFO_TOKEN,
|
|
166
168
|
},
|
|
167
169
|
},
|
|
170
|
+
provide({
|
|
171
|
+
provide: SERVER_RESPONSE_STREAM,
|
|
172
|
+
scope: Scope.REQUEST,
|
|
173
|
+
useFactory: () => new PassThrough(),
|
|
174
|
+
}),
|
|
175
|
+
provide({
|
|
176
|
+
provide: SERVER_RESPONSE_TASK_MANAGER,
|
|
177
|
+
scope: Scope.REQUEST,
|
|
178
|
+
useClass: ServerResponseTaskManager,
|
|
179
|
+
}),
|
|
168
180
|
],
|
|
169
181
|
})
|
|
170
182
|
], ServerModule);
|
package/lib/server.js
CHANGED
|
@@ -13,6 +13,7 @@ var tokensCommon = require('@tramvai/tokens-common');
|
|
|
13
13
|
var moduleMetrics = require('@tramvai/module-metrics');
|
|
14
14
|
var moduleCacheWarmup = require('@tramvai/module-cache-warmup');
|
|
15
15
|
var react = require('@tramvai/react');
|
|
16
|
+
var stream = require('stream');
|
|
16
17
|
var server = require('./server/server.js');
|
|
17
18
|
var webApp = require('./server/webApp.js');
|
|
18
19
|
var _static = require('./server/static.js');
|
|
@@ -28,6 +29,7 @@ var utilityServer = require('./modules/utilityServer.js');
|
|
|
28
29
|
var keepAlive = require('./modules/keepAlive.js');
|
|
29
30
|
var serverTiming = require('./modules/serverTiming.js');
|
|
30
31
|
var index = require('./modules/earlyHints/index.js');
|
|
32
|
+
var taskManager = require('./server/taskManager.js');
|
|
31
33
|
|
|
32
34
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
33
35
|
|
|
@@ -172,6 +174,16 @@ exports.ServerModule = tslib.__decorate([
|
|
|
172
174
|
appInfo: core.APP_INFO_TOKEN,
|
|
173
175
|
},
|
|
174
176
|
},
|
|
177
|
+
core.provide({
|
|
178
|
+
provide: tokensServerPrivate.SERVER_RESPONSE_STREAM,
|
|
179
|
+
scope: core.Scope.REQUEST,
|
|
180
|
+
useFactory: () => new stream.PassThrough(),
|
|
181
|
+
}),
|
|
182
|
+
core.provide({
|
|
183
|
+
provide: tokensServerPrivate.SERVER_RESPONSE_TASK_MANAGER,
|
|
184
|
+
scope: core.Scope.REQUEST,
|
|
185
|
+
useClass: taskManager.ServerResponseTaskManager,
|
|
186
|
+
}),
|
|
175
187
|
],
|
|
176
188
|
})
|
|
177
189
|
], exports.ServerModule);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.137.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"@tinkoff/monkeypatch": "2.0.5",
|
|
26
26
|
"@tinkoff/terminus": "0.1.9",
|
|
27
27
|
"@tinkoff/url": "0.8.6",
|
|
28
|
-
"@tramvai/module-cache-warmup": "2.
|
|
29
|
-
"@tramvai/module-metrics": "2.
|
|
30
|
-
"@tramvai/papi": "2.
|
|
31
|
-
"@tramvai/tokens-server": "2.
|
|
32
|
-
"@tramvai/tokens-server-private": "2.
|
|
28
|
+
"@tramvai/module-cache-warmup": "2.137.0",
|
|
29
|
+
"@tramvai/module-metrics": "2.137.0",
|
|
30
|
+
"@tramvai/papi": "2.137.0",
|
|
31
|
+
"@tramvai/tokens-server": "2.137.0",
|
|
32
|
+
"@tramvai/tokens-server-private": "2.137.0",
|
|
33
33
|
"@tramvai/safe-strings": "0.5.11",
|
|
34
34
|
"fastify": "^4.14.1",
|
|
35
35
|
"@fastify/cookie": "^8.3.0",
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@tinkoff/dippy": "0.8.15",
|
|
44
44
|
"@tinkoff/utils": "^2.1.2",
|
|
45
|
-
"@tramvai/cli": "2.
|
|
46
|
-
"@tramvai/core": "2.
|
|
47
|
-
"@tramvai/react": "2.
|
|
48
|
-
"@tramvai/module-common": "2.
|
|
49
|
-
"@tramvai/module-environment": "2.
|
|
50
|
-
"@tramvai/tokens-common": "2.
|
|
51
|
-
"@tramvai/tokens-core-private": "2.
|
|
52
|
-
"@tramvai/tokens-render": "2.
|
|
45
|
+
"@tramvai/cli": "2.137.0",
|
|
46
|
+
"@tramvai/core": "2.137.0",
|
|
47
|
+
"@tramvai/react": "2.137.0",
|
|
48
|
+
"@tramvai/module-common": "2.137.0",
|
|
49
|
+
"@tramvai/module-environment": "2.137.0",
|
|
50
|
+
"@tramvai/tokens-common": "2.137.0",
|
|
51
|
+
"@tramvai/tokens-core-private": "2.137.0",
|
|
52
|
+
"@tramvai/tokens-render": "2.137.0",
|
|
53
53
|
"react": ">=16.14.0",
|
|
54
54
|
"react-dom": ">=16.14.0",
|
|
55
55
|
"tslib": "^2.4.0"
|