@tramvai/module-render 2.20.0 → 2.21.1
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.es.js +47 -16
- package/lib/server.js +47 -16
- package/package.json +18 -16
- package/tests.d.ts +13 -0
- package/tests.js +267 -0
package/lib/server.es.js
CHANGED
|
@@ -824,24 +824,38 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
824
824
|
html = await htmlBuilder.flow();
|
|
825
825
|
}
|
|
826
826
|
catch (error) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
error,
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
html = await htmlBuilder.flow();
|
|
827
|
+
// assuming that there was an error when rendering the page, try to render again with ErrorBoundary
|
|
828
|
+
try {
|
|
829
|
+
log.info({ event: 'render-page-boundary-start' });
|
|
830
|
+
context.dispatch(setPageErrorEvent(error));
|
|
831
|
+
html = await htmlBuilder.flow();
|
|
832
|
+
log.info({ event: 'render-page-boundary-success' });
|
|
833
|
+
}
|
|
834
|
+
catch (e) {
|
|
835
|
+
log.warn({ event: 'render-page-boundary-error', error: e });
|
|
836
|
+
// pass page render error to default error handler,
|
|
837
|
+
// send-server-error event will be logged with this error
|
|
838
|
+
throw error;
|
|
839
|
+
}
|
|
841
840
|
}
|
|
842
841
|
const pageRenderError = context.getState(PageErrorStore);
|
|
842
|
+
// log send-server-error only after successful Page Boundary render,
|
|
843
|
+
// otherwise this event will be logged in default error handler
|
|
843
844
|
if (pageRenderError) {
|
|
844
845
|
const status = pageRenderError.status || pageRenderError.httpStatus || 500;
|
|
846
|
+
if (status >= 500) {
|
|
847
|
+
const requestInfo = {
|
|
848
|
+
ip: requestManager.getClientIp(),
|
|
849
|
+
requestId: requestManager.getHeader('x-request-id'),
|
|
850
|
+
url: requestManager.getUrl(),
|
|
851
|
+
};
|
|
852
|
+
log.error({
|
|
853
|
+
event: 'send-server-error',
|
|
854
|
+
message: 'Page render error, switch to page boundary',
|
|
855
|
+
error: deserializeError(pageRenderError),
|
|
856
|
+
requestInfo,
|
|
857
|
+
});
|
|
858
|
+
}
|
|
845
859
|
responseManager.setStatus(status);
|
|
846
860
|
}
|
|
847
861
|
// Проставляем не кэширующие заголовки
|
|
@@ -940,9 +954,26 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
940
954
|
}
|
|
941
955
|
let body;
|
|
942
956
|
try {
|
|
943
|
-
log.info({ event: 'render-root-boundary' });
|
|
957
|
+
log.info({ event: 'render-root-boundary-start' });
|
|
944
958
|
body = renderToString(createElement(RootErrorBoundary, { error, url: parse(request.url) }));
|
|
945
|
-
|
|
959
|
+
log.info({ event: 'render-root-boundary-success' });
|
|
960
|
+
const status = error.status || error.httpStatus || 500;
|
|
961
|
+
// log send-server-error only after successful Root Boundary render,
|
|
962
|
+
// otherwise this event will be logged in default error handler
|
|
963
|
+
if (status >= 500) {
|
|
964
|
+
const requestInfo = {
|
|
965
|
+
ip: request.headers['x-real-ip'],
|
|
966
|
+
requestId: request.headers['x-request-id'],
|
|
967
|
+
url: request.url,
|
|
968
|
+
};
|
|
969
|
+
log.error({
|
|
970
|
+
event: 'send-server-error',
|
|
971
|
+
message: 'Page render error, switch to root boundary',
|
|
972
|
+
error,
|
|
973
|
+
requestInfo,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
reply.status(status);
|
|
946
977
|
reply.header('Content-Type', 'text/html; charset=utf-8');
|
|
947
978
|
reply.header('Content-Length', Buffer.byteLength(body, 'utf8'));
|
|
948
979
|
reply.header('Cache-Control', 'no-cache, no-store, must-revalidate');
|
package/lib/server.js
CHANGED
|
@@ -860,24 +860,38 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
860
860
|
html = await htmlBuilder.flow();
|
|
861
861
|
}
|
|
862
862
|
catch (error) {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
error,
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
html = await htmlBuilder.flow();
|
|
863
|
+
// assuming that there was an error when rendering the page, try to render again with ErrorBoundary
|
|
864
|
+
try {
|
|
865
|
+
log.info({ event: 'render-page-boundary-start' });
|
|
866
|
+
context.dispatch(setPageErrorEvent(error));
|
|
867
|
+
html = await htmlBuilder.flow();
|
|
868
|
+
log.info({ event: 'render-page-boundary-success' });
|
|
869
|
+
}
|
|
870
|
+
catch (e) {
|
|
871
|
+
log.warn({ event: 'render-page-boundary-error', error: e });
|
|
872
|
+
// pass page render error to default error handler,
|
|
873
|
+
// send-server-error event will be logged with this error
|
|
874
|
+
throw error;
|
|
875
|
+
}
|
|
877
876
|
}
|
|
878
877
|
const pageRenderError = context.getState(PageErrorStore);
|
|
878
|
+
// log send-server-error only after successful Page Boundary render,
|
|
879
|
+
// otherwise this event will be logged in default error handler
|
|
879
880
|
if (pageRenderError) {
|
|
880
881
|
const status = pageRenderError.status || pageRenderError.httpStatus || 500;
|
|
882
|
+
if (status >= 500) {
|
|
883
|
+
const requestInfo = {
|
|
884
|
+
ip: requestManager.getClientIp(),
|
|
885
|
+
requestId: requestManager.getHeader('x-request-id'),
|
|
886
|
+
url: requestManager.getUrl(),
|
|
887
|
+
};
|
|
888
|
+
log.error({
|
|
889
|
+
event: 'send-server-error',
|
|
890
|
+
message: 'Page render error, switch to page boundary',
|
|
891
|
+
error: deserializeError(pageRenderError),
|
|
892
|
+
requestInfo,
|
|
893
|
+
});
|
|
894
|
+
}
|
|
881
895
|
responseManager.setStatus(status);
|
|
882
896
|
}
|
|
883
897
|
// Проставляем не кэширующие заголовки
|
|
@@ -976,9 +990,26 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
976
990
|
}
|
|
977
991
|
let body;
|
|
978
992
|
try {
|
|
979
|
-
log.info({ event: 'render-root-boundary' });
|
|
993
|
+
log.info({ event: 'render-root-boundary-start' });
|
|
980
994
|
body = server$1.renderToString(react.createElement(RootErrorBoundary, { error, url: url.parse(request.url) }));
|
|
981
|
-
|
|
995
|
+
log.info({ event: 'render-root-boundary-success' });
|
|
996
|
+
const status = error.status || error.httpStatus || 500;
|
|
997
|
+
// log send-server-error only after successful Root Boundary render,
|
|
998
|
+
// otherwise this event will be logged in default error handler
|
|
999
|
+
if (status >= 500) {
|
|
1000
|
+
const requestInfo = {
|
|
1001
|
+
ip: request.headers['x-real-ip'],
|
|
1002
|
+
requestId: request.headers['x-request-id'],
|
|
1003
|
+
url: request.url,
|
|
1004
|
+
};
|
|
1005
|
+
log.error({
|
|
1006
|
+
event: 'send-server-error',
|
|
1007
|
+
message: 'Page render error, switch to root boundary',
|
|
1008
|
+
error,
|
|
1009
|
+
requestInfo,
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
reply.status(status);
|
|
982
1013
|
reply.header('Content-Type', 'text/html; charset=utf-8');
|
|
983
1014
|
reply.header('Content-Length', Buffer.byteLength(body, 'utf8'));
|
|
984
1015
|
reply.header('Cache-Control', 'no-cache, no-store, must-revalidate');
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-render",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.21.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
7
7
|
"typings": "lib/server.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"lib",
|
|
10
|
-
"__migrations__"
|
|
10
|
+
"__migrations__",
|
|
11
|
+
"tests.js",
|
|
12
|
+
"tests.d.ts"
|
|
11
13
|
],
|
|
12
14
|
"sideEffects": false,
|
|
13
15
|
"repository": {
|
|
@@ -24,13 +26,13 @@
|
|
|
24
26
|
"@tinkoff/htmlpagebuilder": "0.5.2",
|
|
25
27
|
"@tinkoff/layout-factory": "0.3.2",
|
|
26
28
|
"@tinkoff/url": "0.8.2",
|
|
27
|
-
"@tinkoff/user-agent": "0.4.
|
|
28
|
-
"@tramvai/module-client-hints": "2.
|
|
29
|
-
"@tramvai/module-router": "2.
|
|
30
|
-
"@tramvai/react": "2.
|
|
29
|
+
"@tinkoff/user-agent": "0.4.54",
|
|
30
|
+
"@tramvai/module-client-hints": "2.21.1",
|
|
31
|
+
"@tramvai/module-router": "2.21.1",
|
|
32
|
+
"@tramvai/react": "2.21.1",
|
|
31
33
|
"@tramvai/safe-strings": "0.5.2",
|
|
32
|
-
"@tramvai/tokens-render": "2.
|
|
33
|
-
"@tramvai/experiments": "2.
|
|
34
|
+
"@tramvai/tokens-render": "2.21.1",
|
|
35
|
+
"@tramvai/experiments": "2.21.1",
|
|
34
36
|
"@types/loadable__server": "^5.12.6",
|
|
35
37
|
"node-fetch": "^2.6.1"
|
|
36
38
|
},
|
|
@@ -38,14 +40,14 @@
|
|
|
38
40
|
"@tinkoff/dippy": "0.8.2",
|
|
39
41
|
"@tinkoff/utils": "^2.1.2",
|
|
40
42
|
"@tinkoff/react-hooks": "0.1.2",
|
|
41
|
-
"@tramvai/cli": "2.
|
|
42
|
-
"@tramvai/core": "2.
|
|
43
|
-
"@tramvai/module-common": "2.
|
|
44
|
-
"@tramvai/state": "2.
|
|
45
|
-
"@tramvai/test-helpers": "2.
|
|
46
|
-
"@tramvai/tokens-common": "2.
|
|
47
|
-
"@tramvai/tokens-router": "2.
|
|
48
|
-
"@tramvai/tokens-server-private": "2.
|
|
43
|
+
"@tramvai/cli": "2.21.1",
|
|
44
|
+
"@tramvai/core": "2.21.1",
|
|
45
|
+
"@tramvai/module-common": "2.21.1",
|
|
46
|
+
"@tramvai/state": "2.21.1",
|
|
47
|
+
"@tramvai/test-helpers": "2.21.1",
|
|
48
|
+
"@tramvai/tokens-common": "2.21.1",
|
|
49
|
+
"@tramvai/tokens-router": "2.21.1",
|
|
50
|
+
"@tramvai/tokens-server-private": "2.21.1",
|
|
49
51
|
"express": "^4.17.1",
|
|
50
52
|
"prop-types": "^15.6.2",
|
|
51
53
|
"react": ">=16.14.0",
|
package/tests.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getDiWrapper } from "@tramvai/test-helpers";
|
|
2
|
+
type Options = Parameters<typeof getDiWrapper>[0];
|
|
3
|
+
declare const testPageResources: (options: Options) => {
|
|
4
|
+
render: () => {
|
|
5
|
+
parsed: import("node-html-parser").HTMLElement;
|
|
6
|
+
body: string;
|
|
7
|
+
head: string;
|
|
8
|
+
application: string;
|
|
9
|
+
};
|
|
10
|
+
di: import("@tinkoff/dippy").Container;
|
|
11
|
+
runLine: (line: import("@tinkoff/dippy").MultiTokenInterface<import("@tramvai/core").Command>) => Promise<any[]>;
|
|
12
|
+
};
|
|
13
|
+
export { testPageResources };
|
package/tests.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var flatten = require('@tinkoff/utils/array/flatten');
|
|
6
|
+
var testHelpers = require('@tramvai/test-helpers');
|
|
7
|
+
var core = require('@tramvai/core');
|
|
8
|
+
var tokensRender = require('@tramvai/tokens-render');
|
|
9
|
+
var htmlpagebuilder = require('@tinkoff/htmlpagebuilder');
|
|
10
|
+
var toArray = require('@tinkoff/utils/array/toArray');
|
|
11
|
+
require('@tinkoff/utils/is/undefined');
|
|
12
|
+
require('@tinkoff/utils/is/empty');
|
|
13
|
+
require('@tinkoff/url');
|
|
14
|
+
require('node-fetch');
|
|
15
|
+
require('@tinkoff/utils/string/startsWith');
|
|
16
|
+
var dippy = require('@tinkoff/dippy');
|
|
17
|
+
require('@tramvai/safe-strings');
|
|
18
|
+
require('@loadable/server');
|
|
19
|
+
require('@tinkoff/utils/object/has');
|
|
20
|
+
require('@tinkoff/utils/array/last');
|
|
21
|
+
require('@tramvai/experiments');
|
|
22
|
+
require('@tinkoff/utils/array/uniq');
|
|
23
|
+
var path = require('path');
|
|
24
|
+
require('@tinkoff/utils/array/each');
|
|
25
|
+
require('@tinkoff/utils/object/path');
|
|
26
|
+
|
|
27
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
28
|
+
|
|
29
|
+
function _interopNamespace(e) {
|
|
30
|
+
if (e && e.__esModule) return e;
|
|
31
|
+
var n = Object.create(null);
|
|
32
|
+
if (e) {
|
|
33
|
+
Object.keys(e).forEach(function (k) {
|
|
34
|
+
if (k !== 'default') {
|
|
35
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
36
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () { return e[k]; }
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
n["default"] = e;
|
|
44
|
+
return n;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
48
|
+
var toArray__default = /*#__PURE__*/_interopDefaultLegacy(toArray);
|
|
49
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
50
|
+
|
|
51
|
+
class ResourcesRegistry {
|
|
52
|
+
constructor({ resourceInliner }) {
|
|
53
|
+
this.resources = new Set();
|
|
54
|
+
this.resourceInliner = resourceInliner;
|
|
55
|
+
}
|
|
56
|
+
register(resourceOrResources) {
|
|
57
|
+
toArray__default["default"](resourceOrResources).forEach((resource) => {
|
|
58
|
+
this.resources.add(resource);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
getPageResources() {
|
|
62
|
+
return Array.from(this.resources.values())
|
|
63
|
+
.reduce((acc, resource) => {
|
|
64
|
+
if (this.resourceInliner.shouldInline(resource)) {
|
|
65
|
+
Array.prototype.push.apply(acc, this.resourceInliner.inlineResource(resource));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
acc.push(resource);
|
|
69
|
+
}
|
|
70
|
+
return acc;
|
|
71
|
+
}, [])
|
|
72
|
+
.filter((resource) => this.resourceInliner.shouldAddResource(resource));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
process.env.NODE_ENV === 'development' &&
|
|
77
|
+
(process.env.ASSETS_PREFIX === 'static' || !process.env.ASSETS_PREFIX)
|
|
78
|
+
? `http://localhost:${process.env.PORT_STATIC}/dist/`
|
|
79
|
+
: process.env.ASSETS_PREFIX;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @description
|
|
83
|
+
* Инлайнер ресурсов - используется на сервере для регистрации файлов, которые должны быть вставлены
|
|
84
|
+
* в итоговую html-страницу в виде ссылки на файл или заинлайнеными полностью
|
|
85
|
+
*/
|
|
86
|
+
const RESOURCE_INLINER = dippy.createToken('resourceInliner');
|
|
87
|
+
/**
|
|
88
|
+
* @description
|
|
89
|
+
* Кэш загруженных ресурсов.
|
|
90
|
+
*/
|
|
91
|
+
dippy.createToken('resourcesRegistryCache');
|
|
92
|
+
|
|
93
|
+
const requireFunc =
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
|
|
96
|
+
|
|
97
|
+
let appConfig;
|
|
98
|
+
try {
|
|
99
|
+
appConfig = require('@tramvai/cli/lib/external/config').appConfig;
|
|
100
|
+
}
|
|
101
|
+
catch (e) { }
|
|
102
|
+
if (process.env.NODE_ENV === 'development') ;
|
|
103
|
+
if (process.env.NODE_ENV === 'test') ;
|
|
104
|
+
if (process.env.NODE_ENV === 'production') {
|
|
105
|
+
const SEARCH_PATHS = [process.cwd(), __dirname];
|
|
106
|
+
const webpackStats = (fileName) => {
|
|
107
|
+
let stats;
|
|
108
|
+
for (const dir of SEARCH_PATHS) {
|
|
109
|
+
try {
|
|
110
|
+
const statsPath = path__namespace.resolve(dir, fileName);
|
|
111
|
+
stats = requireFunc(statsPath);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
// ignore errors as this function is used to load stats for several optional destinations
|
|
116
|
+
// and these destinations may not have stats file
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!stats) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (!process.env.ASSETS_PREFIX) {
|
|
123
|
+
if (process.env.STATIC_PREFIX) {
|
|
124
|
+
throw new Error('Required env variable "ASSETS_PREFIX" is not set. Instead of using "STATIC_PREFIX" env please define "ASSETS_PREFIX: STATIC_PREFIX + /compiled"');
|
|
125
|
+
}
|
|
126
|
+
throw new Error('Required env variable "ASSETS_PREFIX" is not set');
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
...stats,
|
|
130
|
+
publicPath: process.env.ASSETS_PREFIX,
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
const statsLegacy = webpackStats('stats.json');
|
|
134
|
+
webpackStats('stats.modern.json') || statsLegacy;
|
|
135
|
+
if (!statsLegacy) {
|
|
136
|
+
throw new Error(`Cannot find stats.json.
|
|
137
|
+
It should be placed in one of the next places:
|
|
138
|
+
${SEARCH_PATHS.join('\n\t')}
|
|
139
|
+
In case it happens on deployment:
|
|
140
|
+
- In case you are using two independent jobs for building app
|
|
141
|
+
- Either do not split build command by two independent jobs and use one common job with "tramvai build" command without --buildType
|
|
142
|
+
- Or copy stats.json (and stats.modern.json if present) file from client build output to server output by yourself in your CI
|
|
143
|
+
- Otherwise report issue to tramvai team
|
|
144
|
+
In case it happens locally:
|
|
145
|
+
- prefer to use command "tramvai start-prod" to test prod-build locally
|
|
146
|
+
- copy stats.json next to built server.js file
|
|
147
|
+
`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const formatAttributes = (htmlAttrs, target) => {
|
|
152
|
+
if (!htmlAttrs) {
|
|
153
|
+
return '';
|
|
154
|
+
}
|
|
155
|
+
const targetAttrs = htmlAttrs.filter((item) => item.target === target);
|
|
156
|
+
const collectedAttrs = targetAttrs.reduce((acc, item) => ({ ...acc, ...item.attrs }), {});
|
|
157
|
+
const attrsString = Object.keys(collectedAttrs).reduce((acc, name) => {
|
|
158
|
+
if (collectedAttrs[name] === true) {
|
|
159
|
+
return `${acc} ${name}`;
|
|
160
|
+
}
|
|
161
|
+
return `${acc} ${name}="${collectedAttrs[name]}"`;
|
|
162
|
+
}, '');
|
|
163
|
+
return attrsString.trim();
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/* eslint-disable sort-class-members/sort-class-members */
|
|
167
|
+
const mapResourcesToSlots = (resources) => resources.reduce((acc, resource) => {
|
|
168
|
+
const { slot } = resource;
|
|
169
|
+
acc[slot] = Array.isArray(acc[slot]) ? [...acc[slot], resource] : [resource];
|
|
170
|
+
return acc;
|
|
171
|
+
}, {});
|
|
172
|
+
/* eslint-enable sort-class-members/sort-class-members */
|
|
173
|
+
|
|
174
|
+
const { REACT_RENDER, HEAD_CORE_SCRIPTS, HEAD_DYNAMIC_SCRIPTS, HEAD_META, HEAD_POLYFILLS, HEAD_CORE_STYLES, HEAD_PERFORMANCE, HEAD_ANALYTICS, BODY_START, BODY_END, HEAD_ICONS, BODY_TAIL_ANALYTICS, BODY_TAIL, } = tokensRender.ResourceSlot;
|
|
175
|
+
const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
|
|
176
|
+
return [
|
|
177
|
+
htmlpagebuilder.staticRender('<!DOCTYPE html>'),
|
|
178
|
+
htmlpagebuilder.staticRender(`<html ${formatAttributes(htmlAttrs, 'html')}>`),
|
|
179
|
+
htmlpagebuilder.staticRender('<head>'),
|
|
180
|
+
htmlpagebuilder.staticRender('<meta charset="UTF-8">'),
|
|
181
|
+
htmlpagebuilder.dynamicRender(HEAD_META),
|
|
182
|
+
htmlpagebuilder.dynamicRender(HEAD_PERFORMANCE),
|
|
183
|
+
htmlpagebuilder.dynamicRender(HEAD_CORE_STYLES),
|
|
184
|
+
htmlpagebuilder.dynamicRender(HEAD_POLYFILLS),
|
|
185
|
+
htmlpagebuilder.dynamicRender(HEAD_DYNAMIC_SCRIPTS),
|
|
186
|
+
htmlpagebuilder.dynamicRender(HEAD_CORE_SCRIPTS),
|
|
187
|
+
htmlpagebuilder.dynamicRender(HEAD_ANALYTICS),
|
|
188
|
+
htmlpagebuilder.dynamicRender(HEAD_ICONS),
|
|
189
|
+
htmlpagebuilder.staticRender('</head>'),
|
|
190
|
+
htmlpagebuilder.staticRender(`<body ${formatAttributes(htmlAttrs, 'body')}>`),
|
|
191
|
+
htmlpagebuilder.dynamicRender(BODY_START),
|
|
192
|
+
// react app
|
|
193
|
+
htmlpagebuilder.dynamicRender(REACT_RENDER),
|
|
194
|
+
htmlpagebuilder.dynamicRender(BODY_END),
|
|
195
|
+
htmlpagebuilder.dynamicRender(BODY_TAIL_ANALYTICS),
|
|
196
|
+
htmlpagebuilder.dynamicRender(BODY_TAIL),
|
|
197
|
+
htmlpagebuilder.staticRender('</body>'),
|
|
198
|
+
htmlpagebuilder.staticRender('</html>'),
|
|
199
|
+
];
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const testPageResources = (options) => {
|
|
203
|
+
var _a;
|
|
204
|
+
const { modules, providers = [] } = options;
|
|
205
|
+
const { di, runLine } = testHelpers.getDiWrapper({
|
|
206
|
+
di: options.di,
|
|
207
|
+
modules,
|
|
208
|
+
providers: [
|
|
209
|
+
{
|
|
210
|
+
provide: 'htmlPageSchema',
|
|
211
|
+
useFactory: htmlPageSchemaFactory,
|
|
212
|
+
deps: {
|
|
213
|
+
htmlAttrs: tokensRender.HTML_ATTRS,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
provide: tokensRender.HTML_ATTRS,
|
|
218
|
+
useValue: {
|
|
219
|
+
target: 'html',
|
|
220
|
+
attrs: {
|
|
221
|
+
class: 'no-js',
|
|
222
|
+
lang: 'ru',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
multi: true,
|
|
226
|
+
},
|
|
227
|
+
...providers,
|
|
228
|
+
core.provide({
|
|
229
|
+
provide: tokensRender.RESOURCES_REGISTRY,
|
|
230
|
+
useClass: ResourcesRegistry,
|
|
231
|
+
deps: {
|
|
232
|
+
resourceInliner: RESOURCE_INLINER,
|
|
233
|
+
},
|
|
234
|
+
}),
|
|
235
|
+
core.provide({
|
|
236
|
+
provide: RESOURCE_INLINER,
|
|
237
|
+
useValue: {
|
|
238
|
+
shouldInline() {
|
|
239
|
+
return false;
|
|
240
|
+
},
|
|
241
|
+
shouldAddResource() {
|
|
242
|
+
return true;
|
|
243
|
+
},
|
|
244
|
+
inlineResource() {
|
|
245
|
+
return [];
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
}),
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
const renderSlots = flatten__default["default"]((_a = di.get({ token: tokensRender.RENDER_SLOTS, optional: true })) !== null && _a !== void 0 ? _a : []);
|
|
252
|
+
const resourcesRegistry = di.get(tokensRender.RESOURCES_REGISTRY);
|
|
253
|
+
const render = () => {
|
|
254
|
+
const rawHtml = htmlpagebuilder.buildPage({
|
|
255
|
+
slotHandlers: mapResourcesToSlots([...renderSlots, ...resourcesRegistry.getPageResources()]),
|
|
256
|
+
description: di.get('htmlPageSchema'),
|
|
257
|
+
});
|
|
258
|
+
return testHelpers.parseHtml(rawHtml, {});
|
|
259
|
+
};
|
|
260
|
+
return {
|
|
261
|
+
render,
|
|
262
|
+
di,
|
|
263
|
+
runLine,
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
exports.testPageResources = testPageResources;
|