@tramvai/module-render 1.55.2 → 1.56.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/browser.d.ts +1 -0
- package/lib/browser.js +81 -26
- package/lib/react/root.d.ts +0 -2
- package/lib/server.d.ts +1 -0
- package/lib/server.es.js +137 -43
- package/lib/server.js +137 -41
- package/lib/shared/pageErrorStore.d.ts +14 -0
- package/lib/shared/providers.d.ts +1 -0
- package/package.json +19 -14
package/lib/browser.d.ts
CHANGED
package/lib/browser.js
CHANGED
|
@@ -1,41 +1,70 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
|
-
import { Module, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
|
|
3
|
-
import { LOGGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/module-common';
|
|
2
|
+
import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
|
|
3
|
+
import { STORE_TOKEN, LOGGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/module-common';
|
|
4
4
|
import { DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, RESOURCES_REGISTRY, CUSTOM_RENDER, EXTEND_RENDER, RENDERER_CALLBACK, RENDER_MODE } from '@tramvai/tokens-render';
|
|
5
5
|
export * from '@tramvai/tokens-render';
|
|
6
|
-
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
6
|
+
import { ROUTER_TOKEN, PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
7
7
|
import each from '@tinkoff/utils/array/each';
|
|
8
|
-
import React, { PureComponent, createElement, StrictMode, useEffect } from 'react';
|
|
9
|
-
import { Provider } from '@tramvai/state';
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import strictEqual from '@tinkoff/utils/is/strictEqual';
|
|
13
|
-
import { useRoute } from '@tramvai/module-router';
|
|
8
|
+
import React, { PureComponent, useMemo, createElement, StrictMode, useEffect } from 'react';
|
|
9
|
+
import { createEvent, createReducer, useStore, Provider } from '@tramvai/state';
|
|
10
|
+
import { useDi, ERROR_BOUNDARY_TOKEN, ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, UniversalErrorBoundary, DIContext } from '@tramvai/react';
|
|
11
|
+
import { useRoute, useUrl } from '@tramvai/module-router';
|
|
14
12
|
import ReactDOM, { hydrate } from 'react-dom';
|
|
15
13
|
import { composeLayoutOptions, createLayout } from '@tinkoff/layout-factory';
|
|
14
|
+
import { COMBINE_REDUCERS } from '@tramvai/tokens-common';
|
|
16
15
|
|
|
16
|
+
function serializeError(error) {
|
|
17
|
+
return {
|
|
18
|
+
...error,
|
|
19
|
+
message: error.message,
|
|
20
|
+
stack: error.stack,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function deserializeError(serializedError) {
|
|
24
|
+
const error = new Error(serializedError.message);
|
|
25
|
+
Object.assign(error, serializedError);
|
|
26
|
+
return error;
|
|
27
|
+
}
|
|
28
|
+
const setPageErrorEvent = createEvent('setPageError');
|
|
29
|
+
const initialState = null;
|
|
30
|
+
const PageErrorStore = createReducer('pageError', initialState).on(setPageErrorEvent, (state, error) => error && serializeError(error));
|
|
31
|
+
|
|
32
|
+
const PageErrorBoundary = (props) => {
|
|
33
|
+
const { children, fallback } = props;
|
|
34
|
+
const url = useUrl();
|
|
35
|
+
const serializedError = useStore(PageErrorStore);
|
|
36
|
+
const error = useMemo(() => {
|
|
37
|
+
return serializedError && deserializeError(serializedError);
|
|
38
|
+
}, [serializedError]);
|
|
39
|
+
const errorHandlers = useDi({ token: ERROR_BOUNDARY_TOKEN, optional: true });
|
|
40
|
+
const fallbackFromDi = useDi({ token: ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
41
|
+
return (React.createElement(UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi }, children));
|
|
42
|
+
};
|
|
17
43
|
class RootComponent extends PureComponent {
|
|
18
44
|
render() {
|
|
19
|
-
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent } = this.props;
|
|
45
|
+
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent, ErrorBoundaryComponent, } = this.props;
|
|
20
46
|
return (React.createElement(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent },
|
|
21
|
-
React.createElement(
|
|
47
|
+
React.createElement(PageErrorBoundary, { fallback: ErrorBoundaryComponent },
|
|
48
|
+
React.createElement(PageComponent, null))));
|
|
22
49
|
}
|
|
23
50
|
}
|
|
24
|
-
const
|
|
25
|
-
const pageWrapper = memoOne(withError(), strictEqual);
|
|
26
|
-
const Root = withError()(({ pageService }) => {
|
|
51
|
+
const Root = ({ pageService }) => {
|
|
27
52
|
const { config } = useRoute();
|
|
28
53
|
const { pageComponent } = config;
|
|
29
|
-
|
|
54
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
30
55
|
if (!PageComponent) {
|
|
31
|
-
|
|
56
|
+
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
57
|
+
PageComponent = () => {
|
|
58
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
59
|
+
};
|
|
32
60
|
}
|
|
33
|
-
//
|
|
61
|
+
// Get components for current page, otherwise use a defaults
|
|
34
62
|
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
35
63
|
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
36
64
|
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
37
|
-
|
|
38
|
-
});
|
|
65
|
+
const ErrorBoundaryComponent = pageService.resolveComponentFromConfig('errorBoundary');
|
|
66
|
+
return (React.createElement(RootComponent, { HeaderComponent: HeaderComponent, FooterComponent: FooterComponent, LayoutComponent: LayoutComponent, PageComponent: PageComponent, ErrorBoundaryComponent: ErrorBoundaryComponent }));
|
|
67
|
+
};
|
|
39
68
|
|
|
40
69
|
function renderReact({ pageService, di }, context) {
|
|
41
70
|
return (React.createElement(Provider, { context: context },
|
|
@@ -144,6 +173,14 @@ LayoutModule = __decorate([
|
|
|
144
173
|
})
|
|
145
174
|
], LayoutModule);
|
|
146
175
|
|
|
176
|
+
const providers = [
|
|
177
|
+
provide({
|
|
178
|
+
provide: COMBINE_REDUCERS,
|
|
179
|
+
multi: true,
|
|
180
|
+
useValue: PageErrorStore,
|
|
181
|
+
}),
|
|
182
|
+
];
|
|
183
|
+
|
|
147
184
|
var RenderModule_1;
|
|
148
185
|
const DEFAULT_POLYFILL_CONDITION = '';
|
|
149
186
|
const throwErrorInDev = (logger) => {
|
|
@@ -170,7 +207,25 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
170
207
|
Module({
|
|
171
208
|
imports: [LayoutModule],
|
|
172
209
|
providers: [
|
|
173
|
-
|
|
210
|
+
...providers,
|
|
211
|
+
provide({
|
|
212
|
+
provide: commandLineListTokens.customerStart,
|
|
213
|
+
multi: true,
|
|
214
|
+
useFactory: ({ router, store }) => {
|
|
215
|
+
return function clearPageError() {
|
|
216
|
+
router.registerHook('beforeResolve', async () => {
|
|
217
|
+
if (store.getState(PageErrorStore)) {
|
|
218
|
+
store.dispatch(setPageErrorEvent(null));
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
deps: {
|
|
224
|
+
router: ROUTER_TOKEN,
|
|
225
|
+
store: STORE_TOKEN,
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
provide({
|
|
174
229
|
provide: RESOURCES_REGISTRY,
|
|
175
230
|
useFactory: ({ logger }) => ({
|
|
176
231
|
getPageResources: () => {
|
|
@@ -182,8 +237,8 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
182
237
|
deps: {
|
|
183
238
|
logger: LOGGER_TOKEN,
|
|
184
239
|
},
|
|
185
|
-
},
|
|
186
|
-
{
|
|
240
|
+
}),
|
|
241
|
+
provide({
|
|
187
242
|
provide: commandLineListTokens.generatePage,
|
|
188
243
|
useFactory: (deps) => {
|
|
189
244
|
return function renderClientCommand() {
|
|
@@ -202,13 +257,13 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
202
257
|
mode: RENDER_MODE,
|
|
203
258
|
},
|
|
204
259
|
multi: true,
|
|
205
|
-
},
|
|
206
|
-
{
|
|
260
|
+
}),
|
|
261
|
+
provide({
|
|
207
262
|
provide: RENDER_MODE,
|
|
208
263
|
useValue: 'legacy',
|
|
209
|
-
},
|
|
264
|
+
}),
|
|
210
265
|
],
|
|
211
266
|
})
|
|
212
267
|
], RenderModule);
|
|
213
268
|
|
|
214
|
-
export { DEFAULT_POLYFILL_CONDITION, RenderModule };
|
|
269
|
+
export { DEFAULT_POLYFILL_CONDITION, PageErrorStore, RenderModule, deserializeError, serializeError, setPageErrorEvent };
|
package/lib/react/root.d.ts
CHANGED
package/lib/server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RenderModuleConfig } from './shared/types';
|
|
2
|
+
export * from './shared/pageErrorStore';
|
|
2
3
|
export * from '@tramvai/tokens-render';
|
|
3
4
|
export declare const DEFAULT_POLYFILL_CONDITION = "!window.Promise.prototype.finally || !window.URL || !window.URLSearchParams || !window.AbortController || !window.IntersectionObserver || !Object.fromEntries";
|
|
4
5
|
export declare class RenderModule {
|
package/lib/server.es.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import React, { PureComponent, useMemo, createElement } from 'react';
|
|
3
|
+
import { renderToString } from 'react-dom/server';
|
|
4
|
+
import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
|
|
5
|
+
import { CREATE_CACHE_TOKEN, LOGGER_TOKEN, REQUEST_MANAGER_TOKEN, RESPONSE_MANAGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/module-common';
|
|
4
6
|
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
5
7
|
import { ClientHintsModule, USER_AGENT_TOKEN } from '@tramvai/module-client-hints';
|
|
6
8
|
import { ResourceType, ResourceSlot, DEFAULT_LAYOUT_COMPONENT, LAYOUT_OPTIONS, DEFAULT_FOOTER_COMPONENT, DEFAULT_HEADER_COMPONENT, RESOURCES_REGISTRY, RESOURCE_INLINE_OPTIONS, RENDER_SLOTS, POLYFILL_CONDITION, HTML_ATTRS, CUSTOM_RENDER, EXTEND_RENDER } from '@tramvai/tokens-render';
|
|
7
9
|
export * from '@tramvai/tokens-render';
|
|
8
10
|
import { createToken, Scope } from '@tinkoff/dippy';
|
|
11
|
+
import { WEB_APP_AFTER_INIT_TOKEN } from '@tramvai/tokens-server';
|
|
12
|
+
import { useDi, ERROR_BOUNDARY_TOKEN, ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, UniversalErrorBoundary, DIContext, ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN } from '@tramvai/react';
|
|
13
|
+
import { resolve, isAbsoluteUrl as isAbsoluteUrl$1, parse } from '@tinkoff/url';
|
|
9
14
|
import isUndefined from '@tinkoff/utils/is/undefined';
|
|
10
15
|
import isEmpty from '@tinkoff/utils/is/empty';
|
|
11
|
-
import { resolve, isAbsoluteUrl as isAbsoluteUrl$1 } from '@tinkoff/url';
|
|
12
16
|
import fetch from 'node-fetch';
|
|
13
17
|
import startsWith from '@tinkoff/utils/string/startsWith';
|
|
14
18
|
import toArray from '@tinkoff/utils/array/toArray';
|
|
@@ -25,14 +29,10 @@ import * as path from 'path';
|
|
|
25
29
|
import each from '@tinkoff/utils/array/each';
|
|
26
30
|
import path$1 from '@tinkoff/utils/object/path';
|
|
27
31
|
import { o as onload } from './server_inline.inline.es.js';
|
|
28
|
-
import {
|
|
29
|
-
import
|
|
30
|
-
import { Provider } from '@tramvai/state';
|
|
31
|
-
import { withError, DIContext } from '@tramvai/react';
|
|
32
|
-
import memoOne from '@tinkoff/utils/function/memoize/one';
|
|
33
|
-
import strictEqual from '@tinkoff/utils/is/strictEqual';
|
|
34
|
-
import { useRoute } from '@tramvai/module-router';
|
|
32
|
+
import { createEvent, createReducer, useStore, Provider } from '@tramvai/state';
|
|
33
|
+
import { useRoute, useUrl } from '@tramvai/module-router';
|
|
35
34
|
import { composeLayoutOptions, createLayout } from '@tinkoff/layout-factory';
|
|
35
|
+
import { COMBINE_REDUCERS } from '@tramvai/tokens-common';
|
|
36
36
|
|
|
37
37
|
const thirtySeconds = 1000 * 30;
|
|
38
38
|
const getFileContentLength = async (url) => {
|
|
@@ -601,28 +601,58 @@ const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
|
|
|
601
601
|
];
|
|
602
602
|
};
|
|
603
603
|
|
|
604
|
+
function serializeError(error) {
|
|
605
|
+
return {
|
|
606
|
+
...error,
|
|
607
|
+
message: error.message,
|
|
608
|
+
stack: error.stack,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
function deserializeError(serializedError) {
|
|
612
|
+
const error = new Error(serializedError.message);
|
|
613
|
+
Object.assign(error, serializedError);
|
|
614
|
+
return error;
|
|
615
|
+
}
|
|
616
|
+
const setPageErrorEvent = createEvent('setPageError');
|
|
617
|
+
const initialState = null;
|
|
618
|
+
const PageErrorStore = createReducer('pageError', initialState).on(setPageErrorEvent, (state, error) => error && serializeError(error));
|
|
619
|
+
|
|
620
|
+
const PageErrorBoundary = (props) => {
|
|
621
|
+
const { children, fallback } = props;
|
|
622
|
+
const url = useUrl();
|
|
623
|
+
const serializedError = useStore(PageErrorStore);
|
|
624
|
+
const error = useMemo(() => {
|
|
625
|
+
return serializedError && deserializeError(serializedError);
|
|
626
|
+
}, [serializedError]);
|
|
627
|
+
const errorHandlers = useDi({ token: ERROR_BOUNDARY_TOKEN, optional: true });
|
|
628
|
+
const fallbackFromDi = useDi({ token: ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
629
|
+
return (React.createElement(UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi }, children));
|
|
630
|
+
};
|
|
604
631
|
class RootComponent extends PureComponent {
|
|
605
632
|
render() {
|
|
606
|
-
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent } = this.props;
|
|
633
|
+
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent, ErrorBoundaryComponent, } = this.props;
|
|
607
634
|
return (React.createElement(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent },
|
|
608
|
-
React.createElement(
|
|
635
|
+
React.createElement(PageErrorBoundary, { fallback: ErrorBoundaryComponent },
|
|
636
|
+
React.createElement(PageComponent, null))));
|
|
609
637
|
}
|
|
610
638
|
}
|
|
611
|
-
const
|
|
612
|
-
const pageWrapper = memoOne(withError(), strictEqual);
|
|
613
|
-
const Root = withError()(({ pageService }) => {
|
|
639
|
+
const Root = ({ pageService }) => {
|
|
614
640
|
const { config } = useRoute();
|
|
615
641
|
const { pageComponent } = config;
|
|
616
|
-
|
|
642
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
617
643
|
if (!PageComponent) {
|
|
618
|
-
|
|
644
|
+
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
645
|
+
PageComponent = () => {
|
|
646
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
647
|
+
};
|
|
619
648
|
}
|
|
620
|
-
//
|
|
649
|
+
// Get components for current page, otherwise use a defaults
|
|
621
650
|
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
622
651
|
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
623
652
|
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
624
|
-
|
|
625
|
-
});
|
|
653
|
+
const ErrorBoundaryComponent = pageService.resolveComponentFromConfig('errorBoundary');
|
|
654
|
+
return (React.createElement(RootComponent, { HeaderComponent: HeaderComponent, FooterComponent: FooterComponent, LayoutComponent: LayoutComponent, PageComponent: PageComponent, ErrorBoundaryComponent: ErrorBoundaryComponent }));
|
|
655
|
+
};
|
|
626
656
|
|
|
627
657
|
function renderReact({ pageService, di }, context) {
|
|
628
658
|
return (React.createElement(Provider, { context: context },
|
|
@@ -681,6 +711,14 @@ LayoutModule = __decorate([
|
|
|
681
711
|
})
|
|
682
712
|
], LayoutModule);
|
|
683
713
|
|
|
714
|
+
const providers = [
|
|
715
|
+
provide({
|
|
716
|
+
provide: COMBINE_REDUCERS,
|
|
717
|
+
multi: true,
|
|
718
|
+
useValue: PageErrorStore,
|
|
719
|
+
}),
|
|
720
|
+
];
|
|
721
|
+
|
|
684
722
|
var RenderModule_1;
|
|
685
723
|
const DEFAULT_POLYFILL_CONDITION = '!window.Promise.prototype.finally || !window.URL || !window.URLSearchParams || !window.AbortController || !window.IntersectionObserver || !Object.fromEntries';
|
|
686
724
|
let RenderModule = RenderModule_1 = class RenderModule {
|
|
@@ -702,14 +740,15 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
702
740
|
Module({
|
|
703
741
|
imports: [ClientHintsModule, LayoutModule],
|
|
704
742
|
providers: [
|
|
705
|
-
|
|
743
|
+
...providers,
|
|
744
|
+
provide({
|
|
706
745
|
provide: RESOURCES_REGISTRY,
|
|
707
746
|
useClass: ResourcesRegistry,
|
|
708
747
|
deps: {
|
|
709
748
|
resourceInliner: RESOURCE_INLINER,
|
|
710
749
|
},
|
|
711
|
-
},
|
|
712
|
-
{
|
|
750
|
+
}),
|
|
751
|
+
provide({
|
|
713
752
|
provide: RESOURCES_REGISTRY_CACHE,
|
|
714
753
|
scope: Scope.SINGLETON,
|
|
715
754
|
useFactory: ({ createCache }) => {
|
|
@@ -724,20 +763,40 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
724
763
|
deps: {
|
|
725
764
|
createCache: CREATE_CACHE_TOKEN,
|
|
726
765
|
},
|
|
727
|
-
},
|
|
728
|
-
{
|
|
766
|
+
}),
|
|
767
|
+
provide({
|
|
729
768
|
provide: RESOURCE_INLINER,
|
|
730
769
|
useClass: ResourcesInliner,
|
|
731
770
|
deps: {
|
|
732
771
|
resourcesRegistryCache: RESOURCES_REGISTRY_CACHE,
|
|
733
772
|
resourceInlineThreshold: { token: RESOURCE_INLINE_OPTIONS, optional: true },
|
|
734
773
|
},
|
|
735
|
-
},
|
|
736
|
-
{
|
|
774
|
+
}),
|
|
775
|
+
provide({
|
|
737
776
|
provide: commandLineListTokens.generatePage,
|
|
738
|
-
useFactory: ({ htmlBuilder, responseManager, }) => {
|
|
777
|
+
useFactory: ({ htmlBuilder, logger, requestManager, responseManager, context }) => {
|
|
778
|
+
const log = logger('module-render');
|
|
739
779
|
return async function render() {
|
|
740
|
-
|
|
780
|
+
let html;
|
|
781
|
+
try {
|
|
782
|
+
html = await htmlBuilder.flow();
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
const requestInfo = {
|
|
786
|
+
ip: requestManager.getClientIp(),
|
|
787
|
+
requestId: requestManager.getHeader('x-request-id'),
|
|
788
|
+
url: requestManager.getUrl(),
|
|
789
|
+
};
|
|
790
|
+
log.error({ event: 'page-render-error', error, requestInfo });
|
|
791
|
+
// Assuming that there was an error when rendering the page, try to render again with ErrorBoundary
|
|
792
|
+
context.dispatch(setPageErrorEvent(error));
|
|
793
|
+
html = await htmlBuilder.flow();
|
|
794
|
+
}
|
|
795
|
+
const pageRenderError = context.getState(PageErrorStore);
|
|
796
|
+
if (pageRenderError) {
|
|
797
|
+
const status = pageRenderError.status || pageRenderError.httpStatus || 500;
|
|
798
|
+
responseManager.setStatus(status);
|
|
799
|
+
}
|
|
741
800
|
// Проставляем не кэширующие заголовки
|
|
742
801
|
// TODO Заменить после выкатки на прод и прохода всех тестов на cache-control = no-cache,no-store,max-age=0,must-revalidate
|
|
743
802
|
responseManager.setHeader('expires', '0');
|
|
@@ -747,12 +806,15 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
747
806
|
};
|
|
748
807
|
},
|
|
749
808
|
deps: {
|
|
809
|
+
logger: LOGGER_TOKEN,
|
|
810
|
+
requestManager: REQUEST_MANAGER_TOKEN,
|
|
750
811
|
responseManager: RESPONSE_MANAGER_TOKEN,
|
|
751
812
|
htmlBuilder: 'htmlBuilder',
|
|
813
|
+
context: CONTEXT_TOKEN,
|
|
752
814
|
},
|
|
753
815
|
multi: true,
|
|
754
|
-
},
|
|
755
|
-
{
|
|
816
|
+
}),
|
|
817
|
+
provide({
|
|
756
818
|
provide: 'htmlBuilder',
|
|
757
819
|
useClass: PageBuilder,
|
|
758
820
|
deps: {
|
|
@@ -766,8 +828,8 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
766
828
|
userAgent: USER_AGENT_TOKEN,
|
|
767
829
|
htmlAttrs: HTML_ATTRS,
|
|
768
830
|
},
|
|
769
|
-
},
|
|
770
|
-
{
|
|
831
|
+
}),
|
|
832
|
+
provide({
|
|
771
833
|
provide: 'reactRender',
|
|
772
834
|
useClass: ReactRenderServer,
|
|
773
835
|
deps: {
|
|
@@ -777,15 +839,15 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
777
839
|
extendRender: { token: EXTEND_RENDER, optional: true },
|
|
778
840
|
di: DI_TOKEN,
|
|
779
841
|
},
|
|
780
|
-
},
|
|
781
|
-
{
|
|
842
|
+
}),
|
|
843
|
+
provide({
|
|
782
844
|
provide: 'htmlPageSchema',
|
|
783
845
|
useFactory: htmlPageSchemaFactory,
|
|
784
846
|
deps: {
|
|
785
847
|
htmlAttrs: HTML_ATTRS,
|
|
786
848
|
},
|
|
787
|
-
},
|
|
788
|
-
{
|
|
849
|
+
}),
|
|
850
|
+
provide({
|
|
789
851
|
provide: HTML_ATTRS,
|
|
790
852
|
useValue: {
|
|
791
853
|
target: 'html',
|
|
@@ -795,8 +857,8 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
795
857
|
},
|
|
796
858
|
},
|
|
797
859
|
multi: true,
|
|
798
|
-
},
|
|
799
|
-
{
|
|
860
|
+
}),
|
|
861
|
+
provide({
|
|
800
862
|
provide: HTML_ATTRS,
|
|
801
863
|
useValue: {
|
|
802
864
|
target: 'app',
|
|
@@ -805,11 +867,11 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
805
867
|
},
|
|
806
868
|
},
|
|
807
869
|
multi: true,
|
|
808
|
-
},
|
|
809
|
-
{
|
|
870
|
+
}),
|
|
871
|
+
provide({
|
|
810
872
|
provide: POLYFILL_CONDITION,
|
|
811
873
|
useValue: DEFAULT_POLYFILL_CONDITION,
|
|
812
|
-
},
|
|
874
|
+
}),
|
|
813
875
|
provide({
|
|
814
876
|
// Включаем инлайнинг CSS-файлов размером до 40кб (до gzip) по умолчанию.
|
|
815
877
|
provide: RESOURCE_INLINE_OPTIONS,
|
|
@@ -818,8 +880,40 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
818
880
|
types: [ResourceType.style],
|
|
819
881
|
},
|
|
820
882
|
}),
|
|
883
|
+
provide({
|
|
884
|
+
provide: WEB_APP_AFTER_INIT_TOKEN,
|
|
885
|
+
multi: true,
|
|
886
|
+
useFactory: ({ RootErrorBoundary, logger }) => {
|
|
887
|
+
const log = logger('module-render:error-handler');
|
|
888
|
+
return (app) => {
|
|
889
|
+
app.use((err, req, res, next) => {
|
|
890
|
+
if (!RootErrorBoundary) {
|
|
891
|
+
return next(err);
|
|
892
|
+
}
|
|
893
|
+
let body;
|
|
894
|
+
try {
|
|
895
|
+
log.info({ event: 'render-root-boundary' });
|
|
896
|
+
body = renderToString(createElement(RootErrorBoundary, { error: err, url: parse(req.url) }));
|
|
897
|
+
res.status(err.httpStatus || err.status || 500);
|
|
898
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
899
|
+
res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'));
|
|
900
|
+
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
901
|
+
return res.send(body);
|
|
902
|
+
}
|
|
903
|
+
catch (e) {
|
|
904
|
+
log.warn({ event: 'render-root-boundary-error', error: e });
|
|
905
|
+
return next(err);
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
};
|
|
909
|
+
},
|
|
910
|
+
deps: {
|
|
911
|
+
RootErrorBoundary: { token: ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN, optional: true },
|
|
912
|
+
logger: LOGGER_TOKEN,
|
|
913
|
+
},
|
|
914
|
+
}),
|
|
821
915
|
],
|
|
822
916
|
})
|
|
823
917
|
], RenderModule);
|
|
824
918
|
|
|
825
|
-
export { DEFAULT_POLYFILL_CONDITION, RenderModule };
|
|
919
|
+
export { DEFAULT_POLYFILL_CONDITION, PageErrorStore, RenderModule, deserializeError, serializeError, setPageErrorEvent };
|
package/lib/server.js
CHANGED
|
@@ -3,15 +3,19 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var tslib = require('tslib');
|
|
6
|
+
var React = require('react');
|
|
7
|
+
var server$1 = require('react-dom/server');
|
|
6
8
|
var core = require('@tramvai/core');
|
|
7
9
|
var moduleCommon = require('@tramvai/module-common');
|
|
8
10
|
var tokensRouter = require('@tramvai/tokens-router');
|
|
9
11
|
var moduleClientHints = require('@tramvai/module-client-hints');
|
|
10
12
|
var tokensRender = require('@tramvai/tokens-render');
|
|
11
13
|
var dippy = require('@tinkoff/dippy');
|
|
14
|
+
var tokensServer = require('@tramvai/tokens-server');
|
|
15
|
+
var react = require('@tramvai/react');
|
|
16
|
+
var url = require('@tinkoff/url');
|
|
12
17
|
var isUndefined = require('@tinkoff/utils/is/undefined');
|
|
13
18
|
var isEmpty = require('@tinkoff/utils/is/empty');
|
|
14
|
-
var url = require('@tinkoff/url');
|
|
15
19
|
var fetch = require('node-fetch');
|
|
16
20
|
var startsWith = require('@tinkoff/utils/string/startsWith');
|
|
17
21
|
var toArray = require('@tinkoff/utils/array/toArray');
|
|
@@ -28,14 +32,10 @@ var path = require('path');
|
|
|
28
32
|
var each = require('@tinkoff/utils/array/each');
|
|
29
33
|
var path$1 = require('@tinkoff/utils/object/path');
|
|
30
34
|
var inline_inline = require('./server_inline.inline.js');
|
|
31
|
-
var server$1 = require('react-dom/server');
|
|
32
|
-
var React = require('react');
|
|
33
35
|
var state = require('@tramvai/state');
|
|
34
|
-
var react = require('@tramvai/react');
|
|
35
|
-
var memoOne = require('@tinkoff/utils/function/memoize/one');
|
|
36
|
-
var strictEqual = require('@tinkoff/utils/is/strictEqual');
|
|
37
36
|
var moduleRouter = require('@tramvai/module-router');
|
|
38
37
|
var layoutFactory = require('@tinkoff/layout-factory');
|
|
38
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
39
39
|
|
|
40
40
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
41
41
|
|
|
@@ -57,6 +57,7 @@ function _interopNamespace(e) {
|
|
|
57
57
|
return n;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
60
61
|
var isUndefined__default = /*#__PURE__*/_interopDefaultLegacy(isUndefined);
|
|
61
62
|
var isEmpty__default = /*#__PURE__*/_interopDefaultLegacy(isEmpty);
|
|
62
63
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
@@ -69,9 +70,6 @@ var uniq__default = /*#__PURE__*/_interopDefaultLegacy(uniq);
|
|
|
69
70
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
70
71
|
var each__default = /*#__PURE__*/_interopDefaultLegacy(each);
|
|
71
72
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path$1);
|
|
72
|
-
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
73
|
-
var memoOne__default = /*#__PURE__*/_interopDefaultLegacy(memoOne);
|
|
74
|
-
var strictEqual__default = /*#__PURE__*/_interopDefaultLegacy(strictEqual);
|
|
75
73
|
|
|
76
74
|
const thirtySeconds = 1000 * 30;
|
|
77
75
|
const getFileContentLength = async (url) => {
|
|
@@ -640,28 +638,58 @@ const htmlPageSchemaFactory = ({ htmlAttrs, }) => {
|
|
|
640
638
|
];
|
|
641
639
|
};
|
|
642
640
|
|
|
641
|
+
function serializeError(error) {
|
|
642
|
+
return {
|
|
643
|
+
...error,
|
|
644
|
+
message: error.message,
|
|
645
|
+
stack: error.stack,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
function deserializeError(serializedError) {
|
|
649
|
+
const error = new Error(serializedError.message);
|
|
650
|
+
Object.assign(error, serializedError);
|
|
651
|
+
return error;
|
|
652
|
+
}
|
|
653
|
+
const setPageErrorEvent = state.createEvent('setPageError');
|
|
654
|
+
const initialState = null;
|
|
655
|
+
const PageErrorStore = state.createReducer('pageError', initialState).on(setPageErrorEvent, (state, error) => error && serializeError(error));
|
|
656
|
+
|
|
657
|
+
const PageErrorBoundary = (props) => {
|
|
658
|
+
const { children, fallback } = props;
|
|
659
|
+
const url = moduleRouter.useUrl();
|
|
660
|
+
const serializedError = state.useStore(PageErrorStore);
|
|
661
|
+
const error = React.useMemo(() => {
|
|
662
|
+
return serializedError && deserializeError(serializedError);
|
|
663
|
+
}, [serializedError]);
|
|
664
|
+
const errorHandlers = react.useDi({ token: react.ERROR_BOUNDARY_TOKEN, optional: true });
|
|
665
|
+
const fallbackFromDi = react.useDi({ token: react.ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
666
|
+
return (React__default["default"].createElement(react.UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi }, children));
|
|
667
|
+
};
|
|
643
668
|
class RootComponent extends React.PureComponent {
|
|
644
669
|
render() {
|
|
645
|
-
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent } = this.props;
|
|
670
|
+
const { LayoutComponent, PageComponent, HeaderComponent, FooterComponent, ErrorBoundaryComponent, } = this.props;
|
|
646
671
|
return (React__default["default"].createElement(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent },
|
|
647
|
-
React__default["default"].createElement(
|
|
672
|
+
React__default["default"].createElement(PageErrorBoundary, { fallback: ErrorBoundaryComponent },
|
|
673
|
+
React__default["default"].createElement(PageComponent, null))));
|
|
648
674
|
}
|
|
649
675
|
}
|
|
650
|
-
const
|
|
651
|
-
const pageWrapper = memoOne__default["default"](react.withError(), strictEqual__default["default"]);
|
|
652
|
-
const Root = react.withError()(({ pageService }) => {
|
|
676
|
+
const Root = ({ pageService }) => {
|
|
653
677
|
const { config } = moduleRouter.useRoute();
|
|
654
678
|
const { pageComponent } = config;
|
|
655
|
-
|
|
679
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
656
680
|
if (!PageComponent) {
|
|
657
|
-
|
|
681
|
+
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
682
|
+
PageComponent = () => {
|
|
683
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
684
|
+
};
|
|
658
685
|
}
|
|
659
|
-
//
|
|
686
|
+
// Get components for current page, otherwise use a defaults
|
|
660
687
|
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
661
688
|
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
662
689
|
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
663
|
-
|
|
664
|
-
});
|
|
690
|
+
const ErrorBoundaryComponent = pageService.resolveComponentFromConfig('errorBoundary');
|
|
691
|
+
return (React__default["default"].createElement(RootComponent, { HeaderComponent: HeaderComponent, FooterComponent: FooterComponent, LayoutComponent: LayoutComponent, PageComponent: PageComponent, ErrorBoundaryComponent: ErrorBoundaryComponent }));
|
|
692
|
+
};
|
|
665
693
|
|
|
666
694
|
function renderReact({ pageService, di }, context) {
|
|
667
695
|
return (React__default["default"].createElement(state.Provider, { context: context },
|
|
@@ -720,6 +748,14 @@ LayoutModule = tslib.__decorate([
|
|
|
720
748
|
})
|
|
721
749
|
], LayoutModule);
|
|
722
750
|
|
|
751
|
+
const providers = [
|
|
752
|
+
core.provide({
|
|
753
|
+
provide: tokensCommon.COMBINE_REDUCERS,
|
|
754
|
+
multi: true,
|
|
755
|
+
useValue: PageErrorStore,
|
|
756
|
+
}),
|
|
757
|
+
];
|
|
758
|
+
|
|
723
759
|
var RenderModule_1;
|
|
724
760
|
const DEFAULT_POLYFILL_CONDITION = '!window.Promise.prototype.finally || !window.URL || !window.URLSearchParams || !window.AbortController || !window.IntersectionObserver || !Object.fromEntries';
|
|
725
761
|
exports.RenderModule = RenderModule_1 = class RenderModule {
|
|
@@ -741,14 +777,15 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
741
777
|
core.Module({
|
|
742
778
|
imports: [moduleClientHints.ClientHintsModule, LayoutModule],
|
|
743
779
|
providers: [
|
|
744
|
-
|
|
780
|
+
...providers,
|
|
781
|
+
core.provide({
|
|
745
782
|
provide: tokensRender.RESOURCES_REGISTRY,
|
|
746
783
|
useClass: ResourcesRegistry,
|
|
747
784
|
deps: {
|
|
748
785
|
resourceInliner: RESOURCE_INLINER,
|
|
749
786
|
},
|
|
750
|
-
},
|
|
751
|
-
{
|
|
787
|
+
}),
|
|
788
|
+
core.provide({
|
|
752
789
|
provide: RESOURCES_REGISTRY_CACHE,
|
|
753
790
|
scope: dippy.Scope.SINGLETON,
|
|
754
791
|
useFactory: ({ createCache }) => {
|
|
@@ -763,20 +800,40 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
763
800
|
deps: {
|
|
764
801
|
createCache: moduleCommon.CREATE_CACHE_TOKEN,
|
|
765
802
|
},
|
|
766
|
-
},
|
|
767
|
-
{
|
|
803
|
+
}),
|
|
804
|
+
core.provide({
|
|
768
805
|
provide: RESOURCE_INLINER,
|
|
769
806
|
useClass: ResourcesInliner,
|
|
770
807
|
deps: {
|
|
771
808
|
resourcesRegistryCache: RESOURCES_REGISTRY_CACHE,
|
|
772
809
|
resourceInlineThreshold: { token: tokensRender.RESOURCE_INLINE_OPTIONS, optional: true },
|
|
773
810
|
},
|
|
774
|
-
},
|
|
775
|
-
{
|
|
811
|
+
}),
|
|
812
|
+
core.provide({
|
|
776
813
|
provide: core.commandLineListTokens.generatePage,
|
|
777
|
-
useFactory: ({ htmlBuilder, responseManager, }) => {
|
|
814
|
+
useFactory: ({ htmlBuilder, logger, requestManager, responseManager, context }) => {
|
|
815
|
+
const log = logger('module-render');
|
|
778
816
|
return async function render() {
|
|
779
|
-
|
|
817
|
+
let html;
|
|
818
|
+
try {
|
|
819
|
+
html = await htmlBuilder.flow();
|
|
820
|
+
}
|
|
821
|
+
catch (error) {
|
|
822
|
+
const requestInfo = {
|
|
823
|
+
ip: requestManager.getClientIp(),
|
|
824
|
+
requestId: requestManager.getHeader('x-request-id'),
|
|
825
|
+
url: requestManager.getUrl(),
|
|
826
|
+
};
|
|
827
|
+
log.error({ event: 'page-render-error', error, requestInfo });
|
|
828
|
+
// Assuming that there was an error when rendering the page, try to render again with ErrorBoundary
|
|
829
|
+
context.dispatch(setPageErrorEvent(error));
|
|
830
|
+
html = await htmlBuilder.flow();
|
|
831
|
+
}
|
|
832
|
+
const pageRenderError = context.getState(PageErrorStore);
|
|
833
|
+
if (pageRenderError) {
|
|
834
|
+
const status = pageRenderError.status || pageRenderError.httpStatus || 500;
|
|
835
|
+
responseManager.setStatus(status);
|
|
836
|
+
}
|
|
780
837
|
// Проставляем не кэширующие заголовки
|
|
781
838
|
// TODO Заменить после выкатки на прод и прохода всех тестов на cache-control = no-cache,no-store,max-age=0,must-revalidate
|
|
782
839
|
responseManager.setHeader('expires', '0');
|
|
@@ -786,12 +843,15 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
786
843
|
};
|
|
787
844
|
},
|
|
788
845
|
deps: {
|
|
846
|
+
logger: moduleCommon.LOGGER_TOKEN,
|
|
847
|
+
requestManager: moduleCommon.REQUEST_MANAGER_TOKEN,
|
|
789
848
|
responseManager: moduleCommon.RESPONSE_MANAGER_TOKEN,
|
|
790
849
|
htmlBuilder: 'htmlBuilder',
|
|
850
|
+
context: moduleCommon.CONTEXT_TOKEN,
|
|
791
851
|
},
|
|
792
852
|
multi: true,
|
|
793
|
-
},
|
|
794
|
-
{
|
|
853
|
+
}),
|
|
854
|
+
core.provide({
|
|
795
855
|
provide: 'htmlBuilder',
|
|
796
856
|
useClass: PageBuilder,
|
|
797
857
|
deps: {
|
|
@@ -805,8 +865,8 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
805
865
|
userAgent: moduleClientHints.USER_AGENT_TOKEN,
|
|
806
866
|
htmlAttrs: tokensRender.HTML_ATTRS,
|
|
807
867
|
},
|
|
808
|
-
},
|
|
809
|
-
{
|
|
868
|
+
}),
|
|
869
|
+
core.provide({
|
|
810
870
|
provide: 'reactRender',
|
|
811
871
|
useClass: ReactRenderServer,
|
|
812
872
|
deps: {
|
|
@@ -816,15 +876,15 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
816
876
|
extendRender: { token: tokensRender.EXTEND_RENDER, optional: true },
|
|
817
877
|
di: core.DI_TOKEN,
|
|
818
878
|
},
|
|
819
|
-
},
|
|
820
|
-
{
|
|
879
|
+
}),
|
|
880
|
+
core.provide({
|
|
821
881
|
provide: 'htmlPageSchema',
|
|
822
882
|
useFactory: htmlPageSchemaFactory,
|
|
823
883
|
deps: {
|
|
824
884
|
htmlAttrs: tokensRender.HTML_ATTRS,
|
|
825
885
|
},
|
|
826
|
-
},
|
|
827
|
-
{
|
|
886
|
+
}),
|
|
887
|
+
core.provide({
|
|
828
888
|
provide: tokensRender.HTML_ATTRS,
|
|
829
889
|
useValue: {
|
|
830
890
|
target: 'html',
|
|
@@ -834,8 +894,8 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
834
894
|
},
|
|
835
895
|
},
|
|
836
896
|
multi: true,
|
|
837
|
-
},
|
|
838
|
-
{
|
|
897
|
+
}),
|
|
898
|
+
core.provide({
|
|
839
899
|
provide: tokensRender.HTML_ATTRS,
|
|
840
900
|
useValue: {
|
|
841
901
|
target: 'app',
|
|
@@ -844,11 +904,11 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
844
904
|
},
|
|
845
905
|
},
|
|
846
906
|
multi: true,
|
|
847
|
-
},
|
|
848
|
-
{
|
|
907
|
+
}),
|
|
908
|
+
core.provide({
|
|
849
909
|
provide: tokensRender.POLYFILL_CONDITION,
|
|
850
910
|
useValue: DEFAULT_POLYFILL_CONDITION,
|
|
851
|
-
},
|
|
911
|
+
}),
|
|
852
912
|
core.provide({
|
|
853
913
|
// Включаем инлайнинг CSS-файлов размером до 40кб (до gzip) по умолчанию.
|
|
854
914
|
provide: tokensRender.RESOURCE_INLINE_OPTIONS,
|
|
@@ -857,11 +917,47 @@ exports.RenderModule = RenderModule_1 = tslib.__decorate([
|
|
|
857
917
|
types: [tokensRender.ResourceType.style],
|
|
858
918
|
},
|
|
859
919
|
}),
|
|
920
|
+
core.provide({
|
|
921
|
+
provide: tokensServer.WEB_APP_AFTER_INIT_TOKEN,
|
|
922
|
+
multi: true,
|
|
923
|
+
useFactory: ({ RootErrorBoundary, logger }) => {
|
|
924
|
+
const log = logger('module-render:error-handler');
|
|
925
|
+
return (app) => {
|
|
926
|
+
app.use((err, req, res, next) => {
|
|
927
|
+
if (!RootErrorBoundary) {
|
|
928
|
+
return next(err);
|
|
929
|
+
}
|
|
930
|
+
let body;
|
|
931
|
+
try {
|
|
932
|
+
log.info({ event: 'render-root-boundary' });
|
|
933
|
+
body = server$1.renderToString(React.createElement(RootErrorBoundary, { error: err, url: url.parse(req.url) }));
|
|
934
|
+
res.status(err.httpStatus || err.status || 500);
|
|
935
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
936
|
+
res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'));
|
|
937
|
+
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
938
|
+
return res.send(body);
|
|
939
|
+
}
|
|
940
|
+
catch (e) {
|
|
941
|
+
log.warn({ event: 'render-root-boundary-error', error: e });
|
|
942
|
+
return next(err);
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
};
|
|
946
|
+
},
|
|
947
|
+
deps: {
|
|
948
|
+
RootErrorBoundary: { token: react.ROOT_ERROR_BOUNDARY_COMPONENT_TOKEN, optional: true },
|
|
949
|
+
logger: moduleCommon.LOGGER_TOKEN,
|
|
950
|
+
},
|
|
951
|
+
}),
|
|
860
952
|
],
|
|
861
953
|
})
|
|
862
954
|
], exports.RenderModule);
|
|
863
955
|
|
|
864
956
|
exports.DEFAULT_POLYFILL_CONDITION = DEFAULT_POLYFILL_CONDITION;
|
|
957
|
+
exports.PageErrorStore = PageErrorStore;
|
|
958
|
+
exports.deserializeError = deserializeError;
|
|
959
|
+
exports.serializeError = serializeError;
|
|
960
|
+
exports.setPageErrorEvent = setPageErrorEvent;
|
|
865
961
|
Object.keys(tokensRender).forEach(function (k) {
|
|
866
962
|
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
|
|
867
963
|
enumerable: true,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare type AnyError = Error & {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
};
|
|
4
|
+
export interface SerializedError {
|
|
5
|
+
message: string;
|
|
6
|
+
stack?: string;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}
|
|
9
|
+
export declare function serializeError(error: AnyError): SerializedError;
|
|
10
|
+
export declare function deserializeError(serializedError: SerializedError): AnyError;
|
|
11
|
+
export declare type IPageErrorStore = SerializedError | null;
|
|
12
|
+
export declare const setPageErrorEvent: import("@tramvai/types-actions-state-context").EventCreator1<AnyError, AnyError>;
|
|
13
|
+
export declare const PageErrorStore: import("@tramvai/state").Reducer<SerializedError, "pageError">;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const providers: import("@tramvai/core").Provider<unknown, any>[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-render",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.56.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"browser": "lib/browser.js",
|
|
6
6
|
"main": "lib/server.js",
|
|
@@ -24,31 +24,36 @@
|
|
|
24
24
|
"@tinkoff/htmlpagebuilder": "0.4.22",
|
|
25
25
|
"@tinkoff/layout-factory": "0.2.28",
|
|
26
26
|
"@tinkoff/url": "0.7.37",
|
|
27
|
-
"@tinkoff/user-agent": "0.3.
|
|
28
|
-
"@tramvai/module-client-hints": "1.
|
|
29
|
-
"@tramvai/module-router": "1.
|
|
30
|
-
"@tramvai/react": "1.
|
|
27
|
+
"@tinkoff/user-agent": "0.3.235",
|
|
28
|
+
"@tramvai/module-client-hints": "1.56.0",
|
|
29
|
+
"@tramvai/module-router": "1.56.0",
|
|
30
|
+
"@tramvai/react": "1.56.0",
|
|
31
31
|
"@tramvai/safe-strings": "0.4.3",
|
|
32
|
-
"@tramvai/tokens-render": "1.
|
|
33
|
-
"@tramvai/experiments": "1.
|
|
32
|
+
"@tramvai/tokens-render": "1.56.0",
|
|
33
|
+
"@tramvai/experiments": "1.56.0",
|
|
34
34
|
"@types/loadable__server": "^5.12.6",
|
|
35
35
|
"node-fetch": "^2.6.1"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@tinkoff/dippy": "0.7.38",
|
|
39
39
|
"@tinkoff/utils": "^2.1.2",
|
|
40
|
-
"@tramvai/cli": "1.
|
|
41
|
-
"@tramvai/core": "1.
|
|
42
|
-
"@tramvai/module-common": "1.
|
|
43
|
-
"@tramvai/state": "1.
|
|
44
|
-
"@tramvai/test-helpers": "1.
|
|
45
|
-
"@tramvai/tokens-common": "1.
|
|
46
|
-
"@tramvai/tokens-router": "1.
|
|
40
|
+
"@tramvai/cli": "1.56.0",
|
|
41
|
+
"@tramvai/core": "1.56.0",
|
|
42
|
+
"@tramvai/module-common": "1.56.0",
|
|
43
|
+
"@tramvai/state": "1.56.0",
|
|
44
|
+
"@tramvai/test-helpers": "1.56.0",
|
|
45
|
+
"@tramvai/tokens-common": "1.56.0",
|
|
46
|
+
"@tramvai/tokens-router": "1.56.0",
|
|
47
|
+
"@tramvai/tokens-server": "1.56.0",
|
|
48
|
+
"express": "^4.17.1",
|
|
47
49
|
"prop-types": "^15.6.2",
|
|
48
50
|
"react": ">=16.8.0",
|
|
49
51
|
"react-dom": ">=16.8.0",
|
|
50
52
|
"tslib": "^2.0.3"
|
|
51
53
|
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/express": "^4.17.9"
|
|
56
|
+
},
|
|
52
57
|
"gitHead": "8e826a214c87b188fc4d254cdd8f2a2b2c55f3a8",
|
|
53
58
|
"module": "lib/server.es.js",
|
|
54
59
|
"license": "Apache-2.0"
|