@tramvai/module-render 2.70.1 → 2.72.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.
Files changed (58) hide show
  1. package/lib/browser.js +9 -233
  2. package/lib/client/index.browser.js +48 -0
  3. package/lib/client/renderer.browser.js +50 -0
  4. package/lib/react/index.browser.js +11 -0
  5. package/lib/react/index.es.js +11 -0
  6. package/lib/react/index.js +15 -0
  7. package/lib/react/pageErrorBoundary.browser.js +23 -0
  8. package/lib/react/pageErrorBoundary.es.js +23 -0
  9. package/lib/react/pageErrorBoundary.js +27 -0
  10. package/lib/react/root.browser.js +58 -0
  11. package/lib/react/root.es.js +58 -0
  12. package/lib/react/root.js +62 -0
  13. package/lib/resourcesInliner/externalFilesHelper.es.js +17 -0
  14. package/lib/resourcesInliner/externalFilesHelper.js +26 -0
  15. package/lib/resourcesInliner/fileProcessor.es.js +31 -0
  16. package/lib/resourcesInliner/fileProcessor.js +40 -0
  17. package/lib/resourcesInliner/resourcesInliner.es.js +204 -0
  18. package/lib/resourcesInliner/resourcesInliner.js +213 -0
  19. package/lib/resourcesInliner/tokens.es.js +15 -0
  20. package/lib/resourcesInliner/tokens.js +20 -0
  21. package/lib/resourcesRegistry/index.es.js +28 -0
  22. package/lib/resourcesRegistry/index.js +36 -0
  23. package/lib/server/PageBuilder.es.js +93 -0
  24. package/lib/server/PageBuilder.js +102 -0
  25. package/lib/server/ReactRenderServer.es.js +90 -0
  26. package/lib/server/ReactRenderServer.js +98 -0
  27. package/lib/server/blocks/bundleResource/bundleResource.es.js +62 -0
  28. package/lib/server/blocks/bundleResource/bundleResource.js +71 -0
  29. package/lib/server/blocks/polyfill.es.js +35 -0
  30. package/lib/server/blocks/polyfill.js +39 -0
  31. package/lib/{server_inline.inline.es.js → server/blocks/preload/onload.inline.es.js} +1 -1
  32. package/lib/{server_inline.inline.js → server/blocks/preload/onload.inline.js} +2 -0
  33. package/lib/server/blocks/preload/preloadBlock.es.js +21 -0
  34. package/lib/server/blocks/preload/preloadBlock.js +30 -0
  35. package/lib/server/blocks/utils/fetchWebpackStats.es.js +88 -0
  36. package/lib/server/blocks/utils/fetchWebpackStats.js +115 -0
  37. package/lib/server/blocks/utils/flushFiles.es.js +33 -0
  38. package/lib/server/blocks/utils/flushFiles.js +44 -0
  39. package/lib/server/blocks/utils/requireFunc.es.js +5 -0
  40. package/lib/server/blocks/utils/requireFunc.js +9 -0
  41. package/lib/server/constants/performance.es.js +3 -0
  42. package/lib/server/constants/performance.js +7 -0
  43. package/lib/server/htmlPageSchema.es.js +33 -0
  44. package/lib/server/htmlPageSchema.js +37 -0
  45. package/lib/server/utils.es.js +16 -0
  46. package/lib/server/utils.js +20 -0
  47. package/lib/server.es.js +18 -859
  48. package/lib/server.js +33 -909
  49. package/lib/shared/LayoutModule.browser.js +40 -0
  50. package/lib/shared/LayoutModule.es.js +40 -0
  51. package/lib/shared/LayoutModule.js +42 -0
  52. package/lib/shared/pageErrorStore.browser.js +19 -0
  53. package/lib/shared/pageErrorStore.es.js +19 -0
  54. package/lib/shared/pageErrorStore.js +26 -0
  55. package/lib/shared/providers.browser.js +18 -0
  56. package/lib/shared/providers.es.js +18 -0
  57. package/lib/shared/providers.js +22 -0
  58. package/package.json +23 -24
package/lib/server.js CHANGED
@@ -3,8 +3,8 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
- var react$1 = require('react');
7
- var server$1 = require('react-dom/server');
6
+ var react = require('react');
7
+ var server = require('react-dom/server');
8
8
  var core = require('@tramvai/core');
9
9
  var tokensCommon = require('@tramvai/tokens-common');
10
10
  var tokensRouter = require('@tramvai/tokens-router');
@@ -12,894 +12,18 @@ var moduleClientHints = require('@tramvai/module-client-hints');
12
12
  var tokensRender = require('@tramvai/tokens-render');
13
13
  var dippy = require('@tinkoff/dippy');
14
14
  var tokensServerPrivate = require('@tramvai/tokens-server-private');
15
- var react = require('@tramvai/react');
15
+ var react$1 = require('@tramvai/react');
16
16
  var url = require('@tinkoff/url');
17
17
  var userAgent = require('@tinkoff/user-agent');
18
- var isUndefined = require('@tinkoff/utils/is/undefined');
19
- var isEmpty = require('@tinkoff/utils/is/empty');
20
- var fetch = require('node-fetch');
21
- var startsWith = require('@tinkoff/utils/string/startsWith');
22
- var toArray = require('@tinkoff/utils/array/toArray');
23
- var flatten = require('@tinkoff/utils/array/flatten');
24
- var htmlpagebuilder = require('@tinkoff/htmlpagebuilder');
25
- var safeStrings = require('@tramvai/safe-strings');
26
- var server = require('@loadable/server');
27
- var has = require('@tinkoff/utils/object/has');
28
- var last = require('@tinkoff/utils/array/last');
29
- var experiments = require('@tramvai/experiments');
30
- var uniq = require('@tinkoff/utils/array/uniq');
31
- var path = require('path');
32
- var each = require('@tinkoff/utils/array/each');
33
- var path$1 = require('@tinkoff/utils/object/path');
34
- var inline_inline = require('./server_inline.inline.js');
35
- var stream = require('stream');
36
- var jsxRuntime = require('react/jsx-runtime');
37
- var state = require('@tramvai/state');
38
- var moduleRouter = require('@tramvai/module-router');
39
- var layoutFactory = require('@tinkoff/layout-factory');
40
-
41
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
42
-
43
- function _interopNamespace(e) {
44
- if (e && e.__esModule) return e;
45
- var n = Object.create(null);
46
- if (e) {
47
- Object.keys(e).forEach(function (k) {
48
- if (k !== 'default') {
49
- var d = Object.getOwnPropertyDescriptor(e, k);
50
- Object.defineProperty(n, k, d.get ? d : {
51
- enumerable: true,
52
- get: function () { return e[k]; }
53
- });
54
- }
55
- });
56
- }
57
- n["default"] = e;
58
- return n;
59
- }
60
-
61
- var isUndefined__default = /*#__PURE__*/_interopDefaultLegacy(isUndefined);
62
- var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
63
- var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
64
- var startsWith__default = /*#__PURE__*/_interopDefaultLegacy(startsWith);
65
- var toArray__default = /*#__PURE__*/_interopDefaultLegacy(toArray);
66
- var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
67
- var has__default = /*#__PURE__*/_interopDefaultLegacy(has);
68
- var last__default = /*#__PURE__*/_interopDefaultLegacy(last);
69
- var uniq__default = /*#__PURE__*/_interopDefaultLegacy(uniq);
70
- var path__namespace = /*#__PURE__*/_interopNamespace(path);
71
- var each__default = /*#__PURE__*/_interopDefaultLegacy(each);
72
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path$1);
73
-
74
- const thirtySeconds = 1000 * 30;
75
- const getFileContentLength = async (url) => {
76
- const info = await fetch__default["default"](url, { method: 'HEAD', timeout: thirtySeconds });
77
- return info.headers.get('content-length');
78
- };
79
- const getFile = async (url) => {
80
- const fileResponse = await fetch__default["default"](url, { timeout: thirtySeconds });
81
- if (fileResponse.ok) {
82
- const file = await fileResponse.text();
83
- return file;
84
- }
85
- return undefined;
86
- };
87
-
88
- const URL_OCCURRENCES_RE = /(url\((['"]?))(.*?)(\2\))/gi;
89
- const isAbsoluteUrl = (resourceUrl) => ['http://', 'https://', '//'].some((prefix) => startsWith__default["default"](prefix, resourceUrl));
90
- const toHttpsUrl = (resourceUrl) => {
91
- if (resourceUrl.indexOf('//localhost') !== -1) {
92
- return resourceUrl;
93
- }
94
- if (startsWith__default["default"]('http://', resourceUrl)) {
95
- return resourceUrl.replace('http://', 'https://');
96
- }
97
- if (startsWith__default["default"]('//', resourceUrl)) {
98
- return resourceUrl.replace('//', 'https://');
99
- }
100
- return resourceUrl;
101
- };
102
- const urlReplacerCreator = (resourceUrl) => (str, leftGroup, _, extractedUrl, rightGroup) => {
103
- return isAbsoluteUrl(extractedUrl)
104
- ? str
105
- : `${leftGroup}${url.resolve(toHttpsUrl(resourceUrl), extractedUrl)}${rightGroup}`;
106
- };
107
- const processFile = (resource, file) => {
108
- if (resource.type === tokensRender.ResourceType.style) {
109
- return file.replace(URL_OCCURRENCES_RE, urlReplacerCreator(resource.payload));
110
- }
111
- return file;
112
- };
113
-
114
- const INTERNAL_CACHE_SIZE = 50;
115
- const ASSETS_PREFIX = process.env.NODE_ENV === 'development' &&
116
- (process.env.ASSETS_PREFIX === 'static' || !process.env.ASSETS_PREFIX)
117
- ? `http://localhost:${process.env.PORT_STATIC}/dist/`
118
- : process.env.ASSETS_PREFIX;
119
- const getInlineType = (type) => {
120
- switch (type) {
121
- case tokensRender.ResourceType.style:
122
- return tokensRender.ResourceType.inlineStyle;
123
- case tokensRender.ResourceType.script:
124
- return tokensRender.ResourceType.inlineScript;
125
- default:
126
- return type;
127
- }
128
- };
129
- const getResourceUrl = (resource) => {
130
- if (isEmpty__default["default"](resource.payload) || !url.isAbsoluteUrl(resource.payload)) {
131
- return undefined;
132
- }
133
- return resource.payload.startsWith('//')
134
- ? `https://${resource.payload.substr(2)}`
135
- : resource.payload;
136
- };
137
- class ResourcesInliner {
138
- constructor({ resourcesRegistryCache, resourceInlineThreshold, logger }) {
139
- this.internalFilesCache = new Map();
140
- this.runningRequests = new Set();
141
- this.scheduleFileLoad = async (resource, resourceInlineThreshold) => {
142
- const url = getResourceUrl(resource);
143
- const requestKey = `file${url}`;
144
- const filesCache = this.getFilesCache(url);
145
- const result = filesCache.get(url);
146
- if (result) {
147
- return result;
148
- }
149
- if (!this.runningRequests.has(requestKey)) {
150
- this.runningRequests.add(url);
151
- try {
152
- const file = await getFile(url);
153
- if (file === undefined) {
154
- this.resourcesRegistryCache.disabledUrlsCache.set(url, true);
155
- return;
156
- }
157
- const size = file.length;
158
- if (size < resourceInlineThreshold) {
159
- filesCache.set(url, processFile(resource, file));
160
- }
161
- this.resourcesRegistryCache.sizeCache.set(url, size);
162
- }
163
- catch (error) {
164
- this.log.warn({
165
- event: 'file-load-failed',
166
- url,
167
- error,
168
- });
169
- }
170
- finally {
171
- this.runningRequests.delete(requestKey);
172
- }
173
- }
174
- };
175
- this.scheduleFileSizeLoad = async (resource, resourceInlineThreshold) => {
176
- const url = getResourceUrl(resource);
177
- const requestKey = `size${url}`;
178
- const result = this.resourcesRegistryCache.sizeCache.get(url);
179
- if (result) {
180
- return result;
181
- }
182
- if (!this.runningRequests.has(requestKey)) {
183
- this.runningRequests.add(requestKey);
184
- try {
185
- const contentLength = await getFileContentLength(url);
186
- const size = isUndefined__default["default"](contentLength) ? 0 : +contentLength;
187
- if (size) {
188
- this.resourcesRegistryCache.sizeCache.set(url, size);
189
- }
190
- if (size < resourceInlineThreshold) {
191
- this.scheduleFileLoad(resource, resourceInlineThreshold);
192
- }
193
- }
194
- catch (error) {
195
- this.log.warn({
196
- event: 'file-content-length-load-failed',
197
- url,
198
- error,
199
- });
200
- }
201
- finally {
202
- this.runningRequests.delete(requestKey);
203
- }
204
- }
205
- };
206
- this.resourcesRegistryCache = resourcesRegistryCache;
207
- this.resourceInlineThreshold = resourceInlineThreshold;
208
- this.log = logger('resources-inliner');
209
- }
210
- getFilesCache(url) {
211
- if (url.startsWith(ASSETS_PREFIX)) {
212
- // internal resources are resources generated by the current app itself
213
- // these kind of resources are pretty static and won't be changed while app is running
214
- // so we can cache it with bare Map and do not care about how to cleanup cache from outdated entries
215
- return this.internalFilesCache;
216
- }
217
- return this.resourcesRegistryCache.filesCache;
218
- }
219
- // check that resource's preload-link should be added to render
220
- shouldAddResource(resource) {
221
- if (resource.type !== tokensRender.ResourceType.preloadLink) {
222
- // only checking preload-links
223
- return true;
224
- }
225
- const url = getResourceUrl(resource);
226
- if (isUndefined__default["default"](url)) {
227
- // if url is undefined that file is not in cache
228
- return true;
229
- }
230
- // if file is residing in cache that means it will be inlined in page render
231
- // therefore no need to have preload-link for the inlined resource
232
- return !this.getFilesCache(url).has(url);
233
- }
234
- // method for check is passed resource should be inlined in HTML-page
235
- shouldInline(resource) {
236
- var _a;
237
- if (!(((_a = this.resourceInlineThreshold) === null || _a === void 0 ? void 0 : _a.types) || []).includes(resource.type)) {
238
- return false;
239
- }
240
- const resourceInlineThreshold = this.resourceInlineThreshold.threshold;
241
- if (isUndefined__default["default"](resourceInlineThreshold)) {
242
- return false;
243
- }
244
- const url = getResourceUrl(resource);
245
- if (isUndefined__default["default"](url) || this.resourcesRegistryCache.disabledUrlsCache.has(url)) {
246
- return false;
247
- }
248
- const filesCache = this.getFilesCache(url);
249
- if (filesCache.has(url)) {
250
- return true;
251
- }
252
- if (filesCache === this.internalFilesCache &&
253
- this.internalFilesCache.size >= INTERNAL_CACHE_SIZE) {
254
- // if we've exceeded limits for the internal resources cache ignore any new entries
255
- return false;
256
- }
257
- if (!this.resourcesRegistryCache.sizeCache.has(url)) {
258
- this.scheduleFileSizeLoad(resource, resourceInlineThreshold);
259
- return false;
260
- }
261
- const size = this.resourcesRegistryCache.sizeCache.get(url);
262
- if (size > resourceInlineThreshold) {
263
- return false;
264
- }
265
- this.scheduleFileLoad(resource, resourceInlineThreshold);
266
- return false;
267
- }
268
- inlineResource(resource) {
269
- const url = getResourceUrl(resource);
270
- if (isUndefined__default["default"](url)) {
271
- // usually, it should not happen but anyway check it for safety
272
- return [resource];
273
- }
274
- const text = this.getFilesCache(url).get(url);
275
- if (isEmpty__default["default"](text)) {
276
- return [resource];
277
- }
278
- const result = [];
279
- if (process.env.NODE_ENV === 'development') {
280
- // html comment for debugging inlining in dev mode
281
- result.push({
282
- slot: resource.slot,
283
- type: tokensRender.ResourceType.asIs,
284
- payload: `<!-- Inlined file ${url} -->`,
285
- });
286
- }
287
- result.push({
288
- ...resource,
289
- type: getInlineType(resource.type),
290
- payload: text,
291
- });
292
- if (resource.type === tokensRender.ResourceType.style) {
293
- // If we don't add data-href then extract-css-chunks-webpack-plugin
294
- // will add link to resources to the html head (https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/blob/master/src/index.js#L346)
295
- // wherein link in case of css files plugin will look for a link tag, but we add a style tag
296
- // so we can't use tag from above and have to generate new one
297
- result.push({
298
- slot: resource.slot,
299
- type: tokensRender.ResourceType.style,
300
- payload: null,
301
- attrs: {
302
- 'data-href': resource.payload,
303
- },
304
- });
305
- }
306
- return result;
307
- }
308
- }
309
-
310
- /**
311
- * @description
312
- * Инлайнер ресурсов - используется на сервере для регистрации файлов, которые должны быть вставлены
313
- * в итоговую html-страницу в виде ссылки на файл или заинлайнеными полностью
314
- */
315
- const RESOURCE_INLINER = dippy.createToken('resourceInliner');
316
- /**
317
- * @description
318
- * Кэш загруженных ресурсов.
319
- */
320
- const RESOURCES_REGISTRY_CACHE = dippy.createToken('resourcesRegistryCache');
321
-
322
- class ResourcesRegistry {
323
- constructor({ resourceInliner }) {
324
- this.resources = new Set();
325
- this.resourceInliner = resourceInliner;
326
- }
327
- register(resourceOrResources) {
328
- toArray__default["default"](resourceOrResources).forEach((resource) => {
329
- this.resources.add(resource);
330
- });
331
- }
332
- getPageResources() {
333
- return Array.from(this.resources.values())
334
- .reduce((acc, resource) => {
335
- if (this.resourceInliner.shouldInline(resource)) {
336
- Array.prototype.push.apply(acc, this.resourceInliner.inlineResource(resource));
337
- }
338
- else {
339
- acc.push(resource);
340
- }
341
- return acc;
342
- }, [])
343
- .filter((resource) => this.resourceInliner.shouldAddResource(resource));
344
- }
345
- }
346
-
347
- const PRELOAD_JS = '__preloadJS';
348
-
349
- const isJs = (file) => /\.js$/.test(file) && !/\.hot-update\.js$/.test(file);
350
- const isCss = (file) => /\.css$/.test(file);
351
- const getFilesByType = (files) => {
352
- const scripts = files.filter(isJs);
353
- const styles = files.filter(isCss);
354
- return {
355
- scripts,
356
- styles,
357
- };
358
- };
359
- const flushFiles = (chunks, webpackStats, { ignoreDependencies = false, } = {}) => {
360
- // при использовании namedChunkGroups во все entry-файлы как зависимость попадает runtimeChunk
361
- // что при повторных вызовах flushChunks вызовет дублирование подключения manifest.js
362
- // из-за чего приложение может запускаться несколько раз
363
- // без поля namedChunkGroups flushChunks вернет только сами ассеты для чанков, без зависимостей
364
- const { assetsByChunkName, namedChunkGroups } = webpackStats;
365
- const resolvedChunks = [];
366
- for (const chunk of chunks) {
367
- if (!ignoreDependencies && (namedChunkGroups === null || namedChunkGroups === void 0 ? void 0 : namedChunkGroups[chunk])) {
368
- resolvedChunks.push(...namedChunkGroups[chunk].chunks);
369
- }
370
- else {
371
- resolvedChunks.push(chunk);
372
- }
373
- }
374
- const files = flatten__default["default"](uniq__default["default"](resolvedChunks).map((chunk) => assetsByChunkName[chunk]));
375
- return getFilesByType(files);
376
- };
377
-
378
- const requireFunc =
379
- // @ts-ignore
380
- typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
381
-
382
- let appConfig;
383
- try {
384
- appConfig = require('@tramvai/cli/lib/external/config').appConfig;
385
- }
386
- catch (e) { }
387
- let fetchStats = async () => {
388
- throw new Error(`Unknown environment`);
389
- };
390
- if (process.env.NODE_ENV === 'development') {
391
- fetchStats = async () => {
392
- const { modern: configModern, staticHost, staticPort, output } = appConfig;
393
- const getUrl = (filename) => `http://${staticHost}:${staticPort}/${output.client}/${filename}`;
394
- const request = await fetch__default["default"](getUrl(configModern ? 'stats.modern.json' : 'stats.json'));
395
- const stats = await request.json();
396
- // static - популярная заглушка в env.development.js файлах, надо игнорировать, как было раньше
397
- const hasAssetsPrefix = process.env.ASSETS_PREFIX && process.env.ASSETS_PREFIX !== 'static';
398
- const publicPath = hasAssetsPrefix ? process.env.ASSETS_PREFIX : stats.publicPath;
399
- return {
400
- ...stats,
401
- publicPath,
402
- };
403
- };
404
- }
405
- if (process.env.NODE_ENV === 'test') {
406
- fetchStats = () => {
407
- // mock for unit-testing as there is no real static return something just to make server render work
408
- return Promise.resolve({ publicPath: 'http://localhost:4000/', assetsByChunkName: {} });
409
- };
410
- }
411
- if (process.env.NODE_ENV === 'production') {
412
- const SEARCH_PATHS = [process.cwd(), __dirname];
413
- const webpackStats = (fileName) => {
414
- let stats;
415
- for (const dir of SEARCH_PATHS) {
416
- try {
417
- const statsPath = path__namespace.resolve(dir, fileName);
418
- stats = requireFunc(statsPath);
419
- break;
420
- }
421
- catch (e) {
422
- // ignore errors as this function is used to load stats for several optional destinations
423
- // and these destinations may not have stats file
424
- }
425
- }
426
- if (!stats) {
427
- return;
428
- }
429
- if (!process.env.ASSETS_PREFIX) {
430
- if (process.env.STATIC_PREFIX) {
431
- throw new Error('Required env variable "ASSETS_PREFIX" is not set. Instead of using "STATIC_PREFIX" env please define "ASSETS_PREFIX: STATIC_PREFIX + /compiled"');
432
- }
433
- throw new Error('Required env variable "ASSETS_PREFIX" is not set');
434
- }
435
- return {
436
- ...stats,
437
- publicPath: process.env.ASSETS_PREFIX,
438
- };
439
- };
440
- const statsLegacy = webpackStats('stats.json');
441
- const statsModern = webpackStats('stats.modern.json') || statsLegacy;
442
- if (!statsLegacy) {
443
- throw new Error(`Cannot find stats.json.
444
- It should be placed in one of the next places:
445
- ${SEARCH_PATHS.join('\n\t')}
446
- In case it happens on deployment:
447
- - In case you are using two independent jobs for building app
448
- - Either do not split build command by two independent jobs and use one common job with "tramvai build" command without --buildType
449
- - Or copy stats.json (and stats.modern.json if present) file from client build output to server output by yourself in your CI
450
- - Otherwise report issue to tramvai team
451
- In case it happens locally:
452
- - prefer to use command "tramvai start-prod" to test prod-build locally
453
- - copy stats.json next to built server.js file
454
- `);
455
- }
456
- fetchStats = (modern) => {
457
- const stats = modern ? statsModern : statsLegacy;
458
- return Promise.resolve(stats);
459
- };
460
- }
461
- const fetchWebpackStats = async ({ modern, } = {}) => {
462
- return fetchStats(modern);
463
- };
464
-
465
- const bundleResource = async ({ bundle, modern, extractor, pageComponent, }) => {
466
- // for file-system pages preload page chunk against bundle chunk
467
- const chunkNameFromBundle = experiments.isFileSystemPageComponent(pageComponent)
468
- ? experiments.fileSystemPageToWebpackChunkName(pageComponent)
469
- : last__default["default"](bundle.split('/'));
470
- const webpackStats = await fetchWebpackStats({ modern });
471
- const { publicPath, assetsByChunkName } = webpackStats;
472
- const bundles = has__default["default"]('common-chunk', assetsByChunkName)
473
- ? ['common-chunk', chunkNameFromBundle]
474
- : [chunkNameFromBundle];
475
- const lazyChunks = extractor.getMainAssets().map((entry) => entry.chunk);
476
- const { scripts: baseScripts } = flushFiles(['vendor'], webpackStats, {
477
- ignoreDependencies: true,
478
- });
479
- const { scripts, styles } = flushFiles([...bundles, ...lazyChunks, 'platform'], webpackStats);
480
- const genHref = (href) => `${publicPath}${href}`;
481
- const result = [];
482
- if (process.env.NODE_ENV === 'production' ||
483
- (process.env.ASSETS_PREFIX && process.env.ASSETS_PREFIX !== 'static')) {
484
- result.push({
485
- type: tokensRender.ResourceType.inlineScript,
486
- slot: tokensRender.ResourceSlot.HEAD_CORE_SCRIPTS,
487
- payload: `window.ap = ${`"${process.env.ASSETS_PREFIX}"`};`,
488
- });
489
- }
490
- styles.map((style) => result.push({
491
- type: tokensRender.ResourceType.style,
492
- slot: tokensRender.ResourceSlot.HEAD_CORE_STYLES,
493
- payload: genHref(style),
494
- attrs: {
495
- 'data-critical': 'true',
496
- onload: `${PRELOAD_JS}()`,
497
- },
498
- }));
499
- baseScripts.map((script) => result.push({
500
- type: tokensRender.ResourceType.script,
501
- slot: tokensRender.ResourceSlot.HEAD_CORE_SCRIPTS,
502
- payload: genHref(script),
503
- attrs: {
504
- 'data-critical': 'true',
505
- },
506
- }));
507
- scripts.map((script) => result.push({
508
- type: tokensRender.ResourceType.script,
509
- slot: tokensRender.ResourceSlot.HEAD_CORE_SCRIPTS,
510
- payload: genHref(script),
511
- attrs: {
512
- 'data-critical': 'true',
513
- },
514
- }));
515
- return result;
516
- };
517
-
518
- const polyfillResources = async ({ condition, modern, }) => {
519
- const webpackStats = await fetchWebpackStats({ modern });
520
- const { publicPath } = webpackStats;
521
- // получает файл полифилла из stats.json\stats.modern.json.
522
- // В зависимости от версии браузера будет использован полифилл из legacy или modern сборки,
523
- // т.к. полифиллы для них могут отличаться на основании преобразований `@babel/preset-env`
524
- const { scripts: polyfillScripts } = flushFiles(['polyfill'], webpackStats, {
525
- ignoreDependencies: true,
526
- });
527
- const genHref = (href) => `${publicPath}${href}`;
528
- const result = [];
529
- polyfillScripts.forEach((script) => {
530
- const href = genHref(script);
531
- result.push({
532
- type: tokensRender.ResourceType.inlineScript,
533
- slot: tokensRender.ResourceSlot.HEAD_POLYFILLS,
534
- payload: `(function (){
535
- var con;
536
- try {
537
- con = ${condition};
538
- } catch (e) {
539
- con = true;
540
- }
541
- if (con) { document.write('<script defer="defer" charset="utf-8" data-critical="true" crossorigin="anonymous" src="${href}"><\\/script>')}
542
- })()`,
543
- });
544
- });
545
- return result;
546
- };
547
-
548
- const addPreloadForCriticalJS = (pageResources) => {
549
- const jsUrls = [];
550
- each__default["default"]((res) => {
551
- if (res.type === 'script' && path__default["default"](['attrs', 'data-critical'], res)) {
552
- jsUrls.push(res.payload);
553
- }
554
- }, pageResources);
555
- return {
556
- type: tokensRender.ResourceType.inlineScript,
557
- slot: tokensRender.ResourceSlot.HEAD_PERFORMANCE,
558
- payload: `window.${PRELOAD_JS}=(${inline_inline.onload})([${jsUrls.map((url) => `"${url}"`).join(',')}])`,
559
- };
560
- };
561
-
562
- const formatAttributes = (htmlAttrs, target) => {
563
- if (!htmlAttrs) {
564
- return '';
565
- }
566
- const targetAttrs = htmlAttrs.filter((item) => item.target === target);
567
- const collectedAttrs = targetAttrs.reduce((acc, item) => ({ ...acc, ...item.attrs }), {});
568
- const attrsString = Object.keys(collectedAttrs).reduce((acc, name) => {
569
- if (collectedAttrs[name] === true) {
570
- return `${acc} ${name}`;
571
- }
572
- return `${acc} ${name}="${collectedAttrs[name]}"`;
573
- }, '');
574
- return attrsString.trim();
575
- };
576
-
577
- /* eslint-disable sort-class-members/sort-class-members */
578
- const mapResourcesToSlots = (resources) => resources.reduce((acc, resource) => {
579
- const { slot } = resource;
580
- if (Array.isArray(acc[slot])) {
581
- acc[slot].push(resource);
582
- }
583
- else {
584
- acc[slot] = [resource];
585
- }
586
- return acc;
587
- }, {});
588
- class PageBuilder {
589
- constructor({ renderSlots, pageService, resourcesRegistry, context, reactRender, htmlPageSchema, polyfillCondition, htmlAttrs, modern, renderFlowAfter, logger, }) {
590
- this.htmlAttrs = htmlAttrs;
591
- this.renderSlots = flatten__default["default"](renderSlots || []);
592
- this.pageService = pageService;
593
- this.context = context;
594
- this.resourcesRegistry = resourcesRegistry;
595
- this.reactRender = reactRender;
596
- this.htmlPageSchema = htmlPageSchema;
597
- this.polyfillCondition = polyfillCondition;
598
- this.modern = modern;
599
- this.renderFlowAfter = renderFlowAfter || [];
600
- this.log = logger('page-builder');
601
- }
602
- async flow() {
603
- const stats = await fetchWebpackStats({ modern: this.modern });
604
- const extractor = new server.ChunkExtractor({ stats, entrypoints: [] });
605
- // first we render the application, because we need to extract information about the data used by the components
606
- await this.renderApp(extractor);
607
- await Promise.all(this.renderFlowAfter.map((callback) => callback().catch((error) => {
608
- this.log.warn({ event: 'render-flow-after-error', callback, error });
609
- })));
610
- this.dehydrateState();
611
- // load information and dependency for the current bundle and page
612
- await this.fetchChunksInfo(extractor);
613
- this.preloadBlock();
614
- return this.generateHtml();
615
- }
616
- dehydrateState() {
617
- this.resourcesRegistry.register({
618
- type: tokensRender.ResourceType.asIs,
619
- slot: tokensRender.ResourceSlot.BODY_END,
620
- // String much better than big object, source https://v8.dev/blog/cost-of-javascript-2019#json
621
- payload: `<script id="__TRAMVAI_STATE__" type="application/json">${safeStrings.safeStringify(this.context.dehydrate().dispatcher)}</script>`,
622
- });
623
- }
624
- async fetchChunksInfo(extractor) {
625
- const { modern } = this;
626
- const { bundle, pageComponent } = this.pageService.getConfig();
627
- this.resourcesRegistry.register(await bundleResource({ bundle, modern, extractor, pageComponent }));
628
- this.resourcesRegistry.register(await polyfillResources({
629
- condition: this.polyfillCondition,
630
- modern,
631
- }));
632
- }
633
- preloadBlock() {
634
- const preloadResources = addPreloadForCriticalJS(this.resourcesRegistry.getPageResources());
635
- this.resourcesRegistry.register(preloadResources);
636
- }
637
- generateHtml() {
638
- const resultSlotHandlers = mapResourcesToSlots([
639
- ...this.renderSlots,
640
- ...this.resourcesRegistry.getPageResources(),
641
- ]);
642
- return htmlpagebuilder.buildPage({
643
- slotHandlers: resultSlotHandlers,
644
- description: this.htmlPageSchema,
645
- });
646
- }
647
- async renderApp(extractor) {
648
- const html = await this.reactRender.render(extractor);
649
- this.renderSlots = this.renderSlots.concat({
650
- type: tokensRender.ResourceType.asIs,
651
- slot: tokensRender.ResourceSlot.REACT_RENDER,
652
- payload: `<div ${formatAttributes(this.htmlAttrs, 'app')}>${html}</div>`,
653
- });
654
- }
655
- }
656
- /* eslint-enable sort-class-members/sort-class-members */
657
-
658
- 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;
659
- const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
660
- return [
661
- htmlpagebuilder.staticRender('<!DOCTYPE html>'),
662
- htmlpagebuilder.staticRender(`<html ${formatAttributes(htmlAttrs, 'html')}>`),
663
- htmlpagebuilder.staticRender('<head>'),
664
- htmlpagebuilder.staticRender('<meta charset="UTF-8">'),
665
- htmlpagebuilder.dynamicRender(HEAD_META),
666
- htmlpagebuilder.dynamicRender(HEAD_PERFORMANCE),
667
- htmlpagebuilder.dynamicRender(HEAD_CORE_STYLES),
668
- htmlpagebuilder.dynamicRender(HEAD_POLYFILLS),
669
- htmlpagebuilder.dynamicRender(HEAD_DYNAMIC_SCRIPTS),
670
- htmlpagebuilder.dynamicRender(HEAD_CORE_SCRIPTS),
671
- htmlpagebuilder.dynamicRender(HEAD_ANALYTICS),
672
- htmlpagebuilder.dynamicRender(HEAD_ICONS),
673
- htmlpagebuilder.staticRender('</head>'),
674
- htmlpagebuilder.staticRender(`<body ${formatAttributes(htmlAttrs, 'body')}>`),
675
- htmlpagebuilder.dynamicRender(BODY_START),
676
- // react app
677
- htmlpagebuilder.dynamicRender(REACT_RENDER),
678
- htmlpagebuilder.dynamicRender(BODY_END),
679
- htmlpagebuilder.dynamicRender(BODY_TAIL_ANALYTICS),
680
- htmlpagebuilder.dynamicRender(BODY_TAIL),
681
- htmlpagebuilder.staticRender('</body>'),
682
- htmlpagebuilder.staticRender('</html>'),
683
- ];
684
- };
685
-
686
- function serializeError(error) {
687
- return {
688
- ...error,
689
- message: error.message,
690
- stack: error.stack,
691
- };
692
- }
693
- function deserializeError(serializedError) {
694
- const error = new Error(serializedError.message);
695
- Object.assign(error, serializedError);
696
- return error;
697
- }
698
- const setPageErrorEvent = state.createEvent('setPageError');
699
- const initialState = null;
700
- const PageErrorStore = state.createReducer('pageError', initialState).on(setPageErrorEvent, (state, error) => error && serializeError(error));
701
-
702
- const PageErrorBoundary = (props) => {
703
- const { children } = props;
704
- const pageService = react.useDi(tokensRouter.PAGE_SERVICE_TOKEN);
705
- const url = moduleRouter.useUrl();
706
- const serializedError = state.useStore(PageErrorStore);
707
- const error = react$1.useMemo(() => {
708
- return serializedError && deserializeError(serializedError);
709
- }, [serializedError]);
710
- const errorHandlers = react.useDi({ token: react.ERROR_BOUNDARY_TOKEN, optional: true });
711
- const fallbackFromDi = react.useDi({ token: react.ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
712
- const fallback = pageService.resolveComponentFromConfig('errorBoundary');
713
- return (jsxRuntime.jsx(react.UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi, children: children }));
714
- };
715
-
716
- /**
717
- * Result component structure:
718
- *
719
- * <Root>
720
- * <RootComponent>
721
- * <LayoutComponent>
722
- * <NestedLayoutComponent>
723
- * <ErrorBoundaryComponent>
724
- * <PageComponent />
725
- * </ErrorBoundaryComponent>
726
- * </NestedLayoutComponent>
727
- * </LayoutComponent>
728
- * </RootComponent>
729
- * </Root>
730
- *
731
- * All components separated for a few reasons:
732
- * - Page subtree can be rendered independently when Layout and Nested Layout the same
733
- * - Nested Layout can be rerendered only on its changes
734
- * - Layout can be rendered only on its changes
735
- */
736
- const LayoutRenderComponent = ({ children }) => {
737
- const pageService = moduleRouter.usePageService();
738
- const LayoutComponent = pageService.resolveComponentFromConfig('layout');
739
- const HeaderComponent = pageService.resolveComponentFromConfig('header');
740
- const FooterComponent = pageService.resolveComponentFromConfig('footer');
741
- const layout = react$1.useMemo(() => (jsxRuntime.jsx(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent, children: children })), [LayoutComponent, HeaderComponent, FooterComponent, children]);
742
- return layout;
743
- };
744
- const NestedLayoutRenderComponent = ({ children }) => {
745
- const pageService = moduleRouter.usePageService();
746
- const NestedLayoutComponent = pageService.resolveComponentFromConfig('nestedLayout');
747
- const nestedLayout = react$1.useMemo(() => jsxRuntime.jsx(NestedLayoutComponent, { children: children }), [NestedLayoutComponent, children]);
748
- return nestedLayout;
749
- };
750
- const PageRenderComponent = () => {
751
- const pageService = moduleRouter.usePageService();
752
- const { pageComponent } = pageService.getConfig();
753
- let PageComponent = pageService.getComponent(pageComponent);
754
- if (!PageComponent) {
755
- PageComponent = () => {
756
- throw new Error(`Page component '${pageComponent}' not found`);
757
- };
758
- }
759
- const page = react$1.useMemo(() => (jsxRuntime.jsx(PageErrorBoundary, { children: jsxRuntime.jsx(PageComponent, {}) })), [PageComponent]);
760
- return page;
761
- };
762
- const Root = () => {
763
- const pageRenderComponent = react$1.useMemo(() => jsxRuntime.jsx(PageRenderComponent, {}), []);
764
- const nestedLayoutRenderComponent = react$1.useMemo(() => jsxRuntime.jsx(NestedLayoutRenderComponent, { children: pageRenderComponent }), [pageRenderComponent]);
765
- return jsxRuntime.jsx(LayoutRenderComponent, { children: nestedLayoutRenderComponent });
766
- };
767
-
768
- function renderReact({ di }, context) {
769
- const serverState = typeof window !== 'undefined' ? context.getState() : undefined;
770
- return (jsxRuntime.jsx(state.Provider, { context: context, serverState: serverState, children: jsxRuntime.jsx(react.DIContext.Provider, { value: di, children: jsxRuntime.jsx(Root, {}) }) }));
771
- }
772
-
773
- const RENDER_TIMEOUT = 500;
774
- class HtmlWritable extends stream.Writable {
775
- constructor() {
776
- super(...arguments);
777
- this.chunks = [];
778
- this.html = '';
779
- }
780
- getHtml() {
781
- return this.html;
782
- }
783
- _write(chunk, encoding, callback) {
784
- this.chunks.push(chunk);
785
- callback();
786
- }
787
- _final(callback) {
788
- this.html = Buffer.concat(this.chunks).toString();
789
- callback();
790
- }
791
- }
792
- class ReactRenderServer {
793
- // eslint-disable-next-line sort-class-members/sort-class-members
794
- constructor({ context, customRender, extendRender, di, renderMode, logger }) {
795
- this.context = context;
796
- this.customRender = customRender;
797
- this.extendRender = extendRender;
798
- this.di = di;
799
- this.renderMode = renderMode;
800
- this.log = logger('module-render');
801
- }
802
- render(extractor) {
803
- var _a;
804
- let renderResult = renderReact({ di: this.di }, this.context);
805
- each__default["default"]((render) => {
806
- renderResult = render(renderResult);
807
- }, (_a = this.extendRender) !== null && _a !== void 0 ? _a : []);
808
- renderResult = extractor.collectChunks(renderResult);
809
- if (this.customRender) {
810
- return this.customRender(renderResult);
811
- }
812
- if (process.env.__TRAMVAI_CONCURRENT_FEATURES && this.renderMode === 'streaming') {
813
- return new Promise((resolve, reject) => {
814
- const { renderToPipeableStream } = require('react-dom/server');
815
- const htmlWritable = new HtmlWritable();
816
- htmlWritable.on('finish', () => {
817
- resolve(htmlWritable.getHtml());
818
- });
819
- const start = Date.now();
820
- const { log } = this;
821
- log.info({
822
- event: 'streaming-render:start',
823
- });
824
- const { pipe, abort } = renderToPipeableStream(renderResult, {
825
- onAllReady() {
826
- log.info({
827
- event: 'streaming-render:complete',
828
- duration: Date.now() - start,
829
- });
830
- // here `write` will be called only once
831
- pipe(htmlWritable);
832
- },
833
- onError(error) {
834
- // error can be inside Suspense boundaries, this is not critical, continue rendering.
835
- // for criticall errors, this callback will be called with `onShellError`,
836
- // so this is a best place to error logging
837
- log.error({
838
- event: 'streaming-render:error',
839
- error,
840
- });
841
- },
842
- onShellError(error) {
843
- // always critical error, abort rendering
844
- reject(error);
845
- },
846
- });
847
- setTimeout(() => {
848
- abort();
849
- reject(new Error('React renderToPipeableStream timeout exceeded'));
850
- }, RENDER_TIMEOUT);
851
- });
852
- }
853
- const { renderToString } = require('react-dom/server');
854
- return Promise.resolve(renderToString(renderResult));
855
- }
856
- }
857
-
858
- const RenderChildrenComponent = ({ children }) => children;
859
- let LayoutModule = class LayoutModule {
860
- };
861
- LayoutModule = tslib.__decorate([
862
- core.Module({
863
- providers: [
864
- {
865
- provide: tokensRender.DEFAULT_LAYOUT_COMPONENT,
866
- useFactory: ({ layoutOptions }) => {
867
- const options = layoutFactory.composeLayoutOptions(layoutOptions);
868
- return layoutFactory.createLayout(options);
869
- },
870
- deps: {
871
- layoutOptions: { token: tokensRender.LAYOUT_OPTIONS, optional: true },
872
- },
873
- },
874
- {
875
- provide: 'componentDefaultList',
876
- multi: true,
877
- useFactory: (components) => ({
878
- ...components,
879
- nestedLayoutDefault: RenderChildrenComponent,
880
- }),
881
- deps: {
882
- layoutDefault: tokensRender.DEFAULT_LAYOUT_COMPONENT,
883
- footerDefault: { token: tokensRender.DEFAULT_FOOTER_COMPONENT, optional: true },
884
- headerDefault: { token: tokensRender.DEFAULT_HEADER_COMPONENT, optional: true },
885
- errorBoundaryDefault: { token: tokensRender.DEFAULT_ERROR_BOUNDARY_COMPONENT, optional: true },
886
- },
887
- },
888
- ],
889
- })
890
- ], LayoutModule);
891
-
892
- const providers = [
893
- core.provide({
894
- provide: tokensCommon.COMBINE_REDUCERS,
895
- multi: true,
896
- useValue: PageErrorStore,
897
- }),
898
- core.provide({
899
- provide: tokensRender.TRAMVAI_RENDER_MODE,
900
- useValue: 'ssr',
901
- }),
902
- ];
18
+ var resourcesInliner = require('./resourcesInliner/resourcesInliner.js');
19
+ var tokens = require('./resourcesInliner/tokens.js');
20
+ var index = require('./resourcesRegistry/index.js');
21
+ var PageBuilder = require('./server/PageBuilder.js');
22
+ var htmlPageSchema = require('./server/htmlPageSchema.js');
23
+ var ReactRenderServer = require('./server/ReactRenderServer.js');
24
+ var LayoutModule = require('./shared/LayoutModule.js');
25
+ var providers = require('./shared/providers.js');
26
+ var pageErrorStore = require('./shared/pageErrorStore.js');
903
27
 
904
28
  var RenderModule_1;
905
29
  const REQUEST_TTL = 5 * 60 * 1000;
@@ -921,18 +45,18 @@ exports.RenderModule = RenderModule_1 = class RenderModule {
921
45
  };
922
46
  exports.RenderModule = RenderModule_1 = tslib.__decorate([
923
47
  core.Module({
924
- imports: [moduleClientHints.ClientHintsModule, LayoutModule],
48
+ imports: [moduleClientHints.ClientHintsModule, LayoutModule.LayoutModule],
925
49
  providers: [
926
- ...providers,
50
+ ...providers.providers,
927
51
  core.provide({
928
52
  provide: tokensRender.RESOURCES_REGISTRY,
929
- useClass: ResourcesRegistry,
53
+ useClass: index.ResourcesRegistry,
930
54
  deps: {
931
- resourceInliner: RESOURCE_INLINER,
55
+ resourceInliner: tokens.RESOURCE_INLINER,
932
56
  },
933
57
  }),
934
58
  core.provide({
935
- provide: RESOURCES_REGISTRY_CACHE,
59
+ provide: tokens.RESOURCES_REGISTRY_CACHE,
936
60
  scope: dippy.Scope.SINGLETON,
937
61
  useFactory: ({ createCache }) => {
938
62
  return {
@@ -946,11 +70,11 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
946
70
  },
947
71
  }),
948
72
  core.provide({
949
- provide: RESOURCE_INLINER,
73
+ provide: tokens.RESOURCE_INLINER,
950
74
  scope: dippy.Scope.SINGLETON,
951
- useClass: ResourcesInliner,
75
+ useClass: resourcesInliner.ResourcesInliner,
952
76
  deps: {
953
- resourcesRegistryCache: RESOURCES_REGISTRY_CACHE,
77
+ resourcesRegistryCache: tokens.RESOURCES_REGISTRY_CACHE,
954
78
  resourceInlineThreshold: { token: tokensRender.RESOURCE_INLINE_OPTIONS, optional: true },
955
79
  logger: tokensCommon.LOGGER_TOKEN,
956
80
  },
@@ -968,7 +92,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
968
92
  // assuming that there was an error when rendering the page, try to render again with ErrorBoundary
969
93
  try {
970
94
  log.info({ event: 'render-page-boundary-start' });
971
- context.dispatch(setPageErrorEvent(error));
95
+ context.dispatch(pageErrorStore.setPageErrorEvent(error));
972
96
  html = await htmlBuilder.flow();
973
97
  log.info({ event: 'render-page-boundary-success' });
974
98
  }
@@ -979,7 +103,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
979
103
  throw error;
980
104
  }
981
105
  }
982
- const pageRenderError = context.getState(PageErrorStore);
106
+ const pageRenderError = context.getState(pageErrorStore.PageErrorStore);
983
107
  // log send-server-error only after successful Page Boundary render,
984
108
  // otherwise this event will be logged in default error handler
985
109
  if (pageRenderError) {
@@ -993,7 +117,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
993
117
  log.error({
994
118
  event: 'send-server-error',
995
119
  message: 'Page render error, switch to page boundary',
996
- error: deserializeError(pageRenderError),
120
+ error: pageErrorStore.deserializeError(pageRenderError),
997
121
  requestInfo,
998
122
  });
999
123
  }
@@ -1018,7 +142,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1018
142
  }),
1019
143
  core.provide({
1020
144
  provide: 'htmlBuilder',
1021
- useClass: PageBuilder,
145
+ useClass: PageBuilder.PageBuilder,
1022
146
  deps: {
1023
147
  reactRender: 'reactRender',
1024
148
  pageService: tokensRouter.PAGE_SERVICE_TOKEN,
@@ -1035,7 +159,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1035
159
  }),
1036
160
  core.provide({
1037
161
  provide: 'reactRender',
1038
- useClass: ReactRenderServer,
162
+ useClass: ReactRenderServer.ReactRenderServer,
1039
163
  deps: {
1040
164
  context: tokensCommon.CONTEXT_TOKEN,
1041
165
  customRender: { token: tokensRender.CUSTOM_RENDER, optional: true },
@@ -1047,7 +171,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1047
171
  }),
1048
172
  core.provide({
1049
173
  provide: 'htmlPageSchema',
1050
- useFactory: htmlPageSchemaFactory,
174
+ useFactory: htmlPageSchema.htmlPageSchemaFactory,
1051
175
  deps: {
1052
176
  htmlAttrs: tokensRender.HTML_ATTRS,
1053
177
  },
@@ -1097,7 +221,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1097
221
  let body;
1098
222
  try {
1099
223
  log.info({ event: 'render-root-boundary-start' });
1100
- body = server$1.renderToString(react$1.createElement(RootErrorBoundary, { error, url: url.parse(request.url) }));
224
+ body = server.renderToString(react.createElement(RootErrorBoundary, { error, url: url.parse(request.url) }));
1101
225
  log.info({ event: 'render-root-boundary-success' });
1102
226
  const status = error.status || error.httpStatus || 500;
1103
227
  // log send-server-error only after successful Root Boundary render,
@@ -1127,7 +251,7 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1127
251
  };
1128
252
  },
1129
253
  deps: {
1130
- RootErrorBoundary: { token: react.ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN, optional: true },
254
+ RootErrorBoundary: { token: react$1.ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN, optional: true },
1131
255
  logger: tokensCommon.LOGGER_TOKEN,
1132
256
  },
1133
257
  }),
@@ -1162,12 +286,12 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
1162
286
  })
1163
287
  ], exports.RenderModule);
1164
288
 
289
+ exports.ReactRenderServer = ReactRenderServer.ReactRenderServer;
290
+ exports.PageErrorStore = pageErrorStore.PageErrorStore;
291
+ exports.deserializeError = pageErrorStore.deserializeError;
292
+ exports.serializeError = pageErrorStore.serializeError;
293
+ exports.setPageErrorEvent = pageErrorStore.setPageErrorEvent;
1165
294
  exports.DEFAULT_POLYFILL_CONDITION = DEFAULT_POLYFILL_CONDITION;
1166
- exports.PageErrorStore = PageErrorStore;
1167
- exports.ReactRenderServer = ReactRenderServer;
1168
- exports.deserializeError = deserializeError;
1169
- exports.serializeError = serializeError;
1170
- exports.setPageErrorEvent = setPageErrorEvent;
1171
295
  Object.keys(tokensRender).forEach(function (k) {
1172
296
  if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
1173
297
  enumerable: true,