@tramvai/module-render 2.70.0 → 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.
- package/lib/browser.js +9 -233
- package/lib/client/index.browser.js +48 -0
- package/lib/client/renderer.browser.js +50 -0
- package/lib/react/index.browser.js +11 -0
- package/lib/react/index.es.js +11 -0
- package/lib/react/index.js +15 -0
- package/lib/react/pageErrorBoundary.browser.js +23 -0
- package/lib/react/pageErrorBoundary.es.js +23 -0
- package/lib/react/pageErrorBoundary.js +27 -0
- package/lib/react/root.browser.js +58 -0
- package/lib/react/root.es.js +58 -0
- package/lib/react/root.js +62 -0
- package/lib/resourcesInliner/externalFilesHelper.es.js +17 -0
- package/lib/resourcesInliner/externalFilesHelper.js +26 -0
- package/lib/resourcesInliner/fileProcessor.es.js +31 -0
- package/lib/resourcesInliner/fileProcessor.js +40 -0
- package/lib/resourcesInliner/resourcesInliner.es.js +204 -0
- package/lib/resourcesInliner/resourcesInliner.js +213 -0
- package/lib/resourcesInliner/tokens.es.js +15 -0
- package/lib/resourcesInliner/tokens.js +20 -0
- package/lib/resourcesRegistry/index.es.js +28 -0
- package/lib/resourcesRegistry/index.js +36 -0
- package/lib/server/PageBuilder.es.js +93 -0
- package/lib/server/PageBuilder.js +102 -0
- package/lib/server/ReactRenderServer.es.js +90 -0
- package/lib/server/ReactRenderServer.js +98 -0
- package/lib/server/blocks/bundleResource/bundleResource.es.js +62 -0
- package/lib/server/blocks/bundleResource/bundleResource.js +71 -0
- package/lib/server/blocks/polyfill.es.js +35 -0
- package/lib/server/blocks/polyfill.js +39 -0
- package/lib/{server_inline.inline.es.js → server/blocks/preload/onload.inline.es.js} +1 -1
- package/lib/{server_inline.inline.js → server/blocks/preload/onload.inline.js} +2 -0
- package/lib/server/blocks/preload/preloadBlock.es.js +21 -0
- package/lib/server/blocks/preload/preloadBlock.js +30 -0
- package/lib/server/blocks/utils/fetchWebpackStats.es.js +88 -0
- package/lib/server/blocks/utils/fetchWebpackStats.js +115 -0
- package/lib/server/blocks/utils/flushFiles.es.js +33 -0
- package/lib/server/blocks/utils/flushFiles.js +44 -0
- package/lib/server/blocks/utils/requireFunc.es.js +5 -0
- package/lib/server/blocks/utils/requireFunc.js +9 -0
- package/lib/server/constants/performance.es.js +3 -0
- package/lib/server/constants/performance.js +7 -0
- package/lib/server/htmlPageSchema.es.js +33 -0
- package/lib/server/htmlPageSchema.js +37 -0
- package/lib/server/utils.es.js +16 -0
- package/lib/server/utils.js +20 -0
- package/lib/server.es.js +18 -859
- package/lib/server.js +33 -909
- package/lib/shared/LayoutModule.browser.js +40 -0
- package/lib/shared/LayoutModule.es.js +40 -0
- package/lib/shared/LayoutModule.js +42 -0
- package/lib/shared/pageErrorStore.browser.js +19 -0
- package/lib/shared/pageErrorStore.es.js +19 -0
- package/lib/shared/pageErrorStore.js +26 -0
- package/lib/shared/providers.browser.js +18 -0
- package/lib/shared/providers.es.js +18 -0
- package/lib/shared/providers.js +22 -0
- package/package.json +23 -24
package/lib/browser.js
CHANGED
|
@@ -1,238 +1,14 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
2
|
import { Module, provide, commandLineListTokens, DI_TOKEN } from '@tramvai/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { STORE_TOKEN, LOGGER_TOKEN, CONTEXT_TOKEN } from '@tramvai/tokens-common';
|
|
4
|
+
import { RESOURCES_REGISTRY, CUSTOM_RENDER, EXTEND_RENDER, RENDERER_CALLBACK, USE_REACT_STRICT_MODE, RENDER_MODE } from '@tramvai/tokens-render';
|
|
5
5
|
export * from '@tramvai/tokens-render';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import { useUrl, usePageService } from '@tramvai/module-router';
|
|
13
|
-
import debounce from '@tinkoff/utils/function/debounce';
|
|
14
|
-
import { useIsomorphicLayoutEffect } from '@tinkoff/react-hooks';
|
|
15
|
-
import { composeLayoutOptions, createLayout } from '@tinkoff/layout-factory';
|
|
16
|
-
|
|
17
|
-
function serializeError(error) {
|
|
18
|
-
return {
|
|
19
|
-
...error,
|
|
20
|
-
message: error.message,
|
|
21
|
-
stack: error.stack,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function deserializeError(serializedError) {
|
|
25
|
-
const error = new Error(serializedError.message);
|
|
26
|
-
Object.assign(error, serializedError);
|
|
27
|
-
return error;
|
|
28
|
-
}
|
|
29
|
-
const setPageErrorEvent = createEvent('setPageError');
|
|
30
|
-
const initialState = null;
|
|
31
|
-
const PageErrorStore = createReducer('pageError', initialState).on(setPageErrorEvent, (state, error) => error && serializeError(error));
|
|
32
|
-
|
|
33
|
-
const PageErrorBoundary = (props) => {
|
|
34
|
-
const { children } = props;
|
|
35
|
-
const pageService = useDi(PAGE_SERVICE_TOKEN);
|
|
36
|
-
const url = useUrl();
|
|
37
|
-
const serializedError = useStore(PageErrorStore);
|
|
38
|
-
const error = useMemo(() => {
|
|
39
|
-
return serializedError && deserializeError(serializedError);
|
|
40
|
-
}, [serializedError]);
|
|
41
|
-
const errorHandlers = useDi({ token: ERROR_BOUNDARY_TOKEN, optional: true });
|
|
42
|
-
const fallbackFromDi = useDi({ token: ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
43
|
-
const fallback = pageService.resolveComponentFromConfig('errorBoundary');
|
|
44
|
-
return (jsx(UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi, children: children }));
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Result component structure:
|
|
49
|
-
*
|
|
50
|
-
* <Root>
|
|
51
|
-
* <RootComponent>
|
|
52
|
-
* <LayoutComponent>
|
|
53
|
-
* <NestedLayoutComponent>
|
|
54
|
-
* <ErrorBoundaryComponent>
|
|
55
|
-
* <PageComponent />
|
|
56
|
-
* </ErrorBoundaryComponent>
|
|
57
|
-
* </NestedLayoutComponent>
|
|
58
|
-
* </LayoutComponent>
|
|
59
|
-
* </RootComponent>
|
|
60
|
-
* </Root>
|
|
61
|
-
*
|
|
62
|
-
* All components separated for a few reasons:
|
|
63
|
-
* - Page subtree can be rendered independently when Layout and Nested Layout the same
|
|
64
|
-
* - Nested Layout can be rerendered only on its changes
|
|
65
|
-
* - Layout can be rendered only on its changes
|
|
66
|
-
*/
|
|
67
|
-
const LayoutRenderComponent = ({ children }) => {
|
|
68
|
-
const pageService = usePageService();
|
|
69
|
-
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
70
|
-
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
71
|
-
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
72
|
-
const layout = useMemo(() => (jsx(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent, children: children })), [LayoutComponent, HeaderComponent, FooterComponent, children]);
|
|
73
|
-
return layout;
|
|
74
|
-
};
|
|
75
|
-
const NestedLayoutRenderComponent = ({ children }) => {
|
|
76
|
-
const pageService = usePageService();
|
|
77
|
-
const NestedLayoutComponent = pageService.resolveComponentFromConfig('nestedLayout');
|
|
78
|
-
const nestedLayout = useMemo(() => jsx(NestedLayoutComponent, { children: children }), [NestedLayoutComponent, children]);
|
|
79
|
-
return nestedLayout;
|
|
80
|
-
};
|
|
81
|
-
const PageRenderComponent = () => {
|
|
82
|
-
const pageService = usePageService();
|
|
83
|
-
const { pageComponent } = pageService.getConfig();
|
|
84
|
-
let PageComponent = pageService.getComponent(pageComponent);
|
|
85
|
-
if (!PageComponent) {
|
|
86
|
-
PageComponent = () => {
|
|
87
|
-
throw new Error(`Page component '${pageComponent}' not found`);
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const page = useMemo(() => (jsx(PageErrorBoundary, { children: jsx(PageComponent, {}) })), [PageComponent]);
|
|
91
|
-
return page;
|
|
92
|
-
};
|
|
93
|
-
const Root = () => {
|
|
94
|
-
const pageRenderComponent = useMemo(() => jsx(PageRenderComponent, {}), []);
|
|
95
|
-
const nestedLayoutRenderComponent = useMemo(() => jsx(NestedLayoutRenderComponent, { children: pageRenderComponent }), [pageRenderComponent]);
|
|
96
|
-
return jsx(LayoutRenderComponent, { children: nestedLayoutRenderComponent });
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
function renderReact({ di }, context) {
|
|
100
|
-
const serverState = typeof window !== 'undefined' ? context.getState() : undefined;
|
|
101
|
-
return (jsx(Provider, { context: context, serverState: serverState, children: jsx(DIContext.Provider, { value: di, children: jsx(Root, {}) }) }));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let hydrateRoot;
|
|
105
|
-
let startTransition;
|
|
106
|
-
try {
|
|
107
|
-
// eslint-disable-next-line import/no-unresolved, import/extensions
|
|
108
|
-
hydrateRoot = require('react-dom/client').hydrateRoot;
|
|
109
|
-
startTransition = require('react').startTransition;
|
|
110
|
-
}
|
|
111
|
-
catch { }
|
|
112
|
-
const ExecuteRenderCallback = ({ children, callback, }) => {
|
|
113
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
114
|
-
useIsomorphicLayoutEffect(callback, []);
|
|
115
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
116
|
-
return children;
|
|
117
|
-
};
|
|
118
|
-
const renderer = ({ element, container, callback, log }) => {
|
|
119
|
-
if (process.env.__TRAMVAI_CONCURRENT_FEATURES && typeof hydrateRoot === 'function') {
|
|
120
|
-
const wrappedElement = createElement(ExecuteRenderCallback, { callback }, element);
|
|
121
|
-
let allErrors = new Map();
|
|
122
|
-
const logHydrateRecoverableError = debounce(50, () => {
|
|
123
|
-
if (allErrors.size === 0) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const [{ error, errorInfo }, ...otherErrors] = Array.from(allErrors.values());
|
|
127
|
-
allErrors = new Map();
|
|
128
|
-
log.error({
|
|
129
|
-
event: 'hydrate:recover-after-error',
|
|
130
|
-
error,
|
|
131
|
-
errorInfo,
|
|
132
|
-
otherErrors,
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
return startTransition(() => {
|
|
136
|
-
hydrateRoot(container, wrappedElement, {
|
|
137
|
-
onRecoverableError: (error, errorInfo) => {
|
|
138
|
-
// deduplicate by unique important string values
|
|
139
|
-
allErrors.set((error === null || error === void 0 ? void 0 : error.message) + (errorInfo === null || errorInfo === void 0 ? void 0 : errorInfo.componentStack), { error, errorInfo });
|
|
140
|
-
logHydrateRecoverableError();
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
const { hydrate } = require('react-dom');
|
|
146
|
-
return hydrate(element, container, callback);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
function rendering({ logger, consumerContext, customRender, extendRender, di, useStrictMode, rendererCallback, }) {
|
|
150
|
-
const log = logger('module-render');
|
|
151
|
-
return new Promise((resolve, reject) => {
|
|
152
|
-
let renderResult = renderReact({ di }, consumerContext);
|
|
153
|
-
if (extendRender) {
|
|
154
|
-
each((render) => {
|
|
155
|
-
renderResult = render(renderResult);
|
|
156
|
-
}, extendRender);
|
|
157
|
-
}
|
|
158
|
-
if (customRender) {
|
|
159
|
-
return customRender(renderResult);
|
|
160
|
-
}
|
|
161
|
-
if (useStrictMode) {
|
|
162
|
-
renderResult = createElement(StrictMode, null, renderResult);
|
|
163
|
-
}
|
|
164
|
-
const container = document.querySelector('.application');
|
|
165
|
-
const executeRendererCallbacks = (renderErr) => rendererCallback === null || rendererCallback === void 0 ? void 0 : rendererCallback.forEach((cb) => {
|
|
166
|
-
try {
|
|
167
|
-
cb(renderErr);
|
|
168
|
-
}
|
|
169
|
-
catch (cbError) {
|
|
170
|
-
// eslint-disable-next-line no-console
|
|
171
|
-
console.error(cbError);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
const callback = () => {
|
|
175
|
-
log.debug('App rendering');
|
|
176
|
-
document.querySelector('html').classList.remove('no-js');
|
|
177
|
-
executeRendererCallbacks();
|
|
178
|
-
resolve();
|
|
179
|
-
};
|
|
180
|
-
const params = { element: renderResult, container, callback, log };
|
|
181
|
-
try {
|
|
182
|
-
renderer(params);
|
|
183
|
-
}
|
|
184
|
-
catch (e) {
|
|
185
|
-
executeRendererCallbacks(e);
|
|
186
|
-
reject(e);
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const RenderChildrenComponent = ({ children }) => children;
|
|
192
|
-
let LayoutModule = class LayoutModule {
|
|
193
|
-
};
|
|
194
|
-
LayoutModule = __decorate([
|
|
195
|
-
Module({
|
|
196
|
-
providers: [
|
|
197
|
-
{
|
|
198
|
-
provide: DEFAULT_LAYOUT_COMPONENT,
|
|
199
|
-
useFactory: ({ layoutOptions }) => {
|
|
200
|
-
const options = composeLayoutOptions(layoutOptions);
|
|
201
|
-
return createLayout(options);
|
|
202
|
-
},
|
|
203
|
-
deps: {
|
|
204
|
-
layoutOptions: { token: LAYOUT_OPTIONS, optional: true },
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
provide: 'componentDefaultList',
|
|
209
|
-
multi: true,
|
|
210
|
-
useFactory: (components) => ({
|
|
211
|
-
...components,
|
|
212
|
-
nestedLayoutDefault: RenderChildrenComponent,
|
|
213
|
-
}),
|
|
214
|
-
deps: {
|
|
215
|
-
layoutDefault: DEFAULT_LAYOUT_COMPONENT,
|
|
216
|
-
footerDefault: { token: DEFAULT_FOOTER_COMPONENT, optional: true },
|
|
217
|
-
headerDefault: { token: DEFAULT_HEADER_COMPONENT, optional: true },
|
|
218
|
-
errorBoundaryDefault: { token: DEFAULT_ERROR_BOUNDARY_COMPONENT, optional: true },
|
|
219
|
-
},
|
|
220
|
-
},
|
|
221
|
-
],
|
|
222
|
-
})
|
|
223
|
-
], LayoutModule);
|
|
224
|
-
|
|
225
|
-
const providers = [
|
|
226
|
-
provide({
|
|
227
|
-
provide: COMBINE_REDUCERS,
|
|
228
|
-
multi: true,
|
|
229
|
-
useValue: PageErrorStore,
|
|
230
|
-
}),
|
|
231
|
-
provide({
|
|
232
|
-
provide: TRAMVAI_RENDER_MODE,
|
|
233
|
-
useValue: 'ssr',
|
|
234
|
-
}),
|
|
235
|
-
];
|
|
6
|
+
import { ROUTER_TOKEN } from '@tramvai/tokens-router';
|
|
7
|
+
import { rendering } from './client/index.browser.js';
|
|
8
|
+
import { LayoutModule } from './shared/LayoutModule.browser.js';
|
|
9
|
+
import { providers } from './shared/providers.browser.js';
|
|
10
|
+
import { PageErrorStore, setPageErrorEvent } from './shared/pageErrorStore.browser.js';
|
|
11
|
+
export { PageErrorStore, deserializeError, serializeError, setPageErrorEvent } from './shared/pageErrorStore.browser.js';
|
|
236
12
|
|
|
237
13
|
var RenderModule_1;
|
|
238
14
|
const DEFAULT_POLYFILL_CONDITION = '';
|
|
@@ -339,4 +115,4 @@ RenderModule = RenderModule_1 = __decorate([
|
|
|
339
115
|
})
|
|
340
116
|
], RenderModule);
|
|
341
117
|
|
|
342
|
-
export { DEFAULT_POLYFILL_CONDITION,
|
|
118
|
+
export { DEFAULT_POLYFILL_CONDITION, RenderModule };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import each from '@tinkoff/utils/array/each';
|
|
2
|
+
import { createElement, StrictMode } from 'react';
|
|
3
|
+
import { renderReact } from '../react/index.browser.js';
|
|
4
|
+
import { renderer } from './renderer.browser.js';
|
|
5
|
+
|
|
6
|
+
function rendering({ logger, consumerContext, customRender, extendRender, di, useStrictMode, rendererCallback, }) {
|
|
7
|
+
const log = logger('module-render');
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
let renderResult = renderReact({ di }, consumerContext);
|
|
10
|
+
if (extendRender) {
|
|
11
|
+
each((render) => {
|
|
12
|
+
renderResult = render(renderResult);
|
|
13
|
+
}, extendRender);
|
|
14
|
+
}
|
|
15
|
+
if (customRender) {
|
|
16
|
+
return customRender(renderResult);
|
|
17
|
+
}
|
|
18
|
+
if (useStrictMode) {
|
|
19
|
+
renderResult = createElement(StrictMode, null, renderResult);
|
|
20
|
+
}
|
|
21
|
+
const container = document.querySelector('.application');
|
|
22
|
+
const executeRendererCallbacks = (renderErr) => rendererCallback === null || rendererCallback === void 0 ? void 0 : rendererCallback.forEach((cb) => {
|
|
23
|
+
try {
|
|
24
|
+
cb(renderErr);
|
|
25
|
+
}
|
|
26
|
+
catch (cbError) {
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
28
|
+
console.error(cbError);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const callback = () => {
|
|
32
|
+
log.debug('App rendering');
|
|
33
|
+
document.querySelector('html').classList.remove('no-js');
|
|
34
|
+
executeRendererCallbacks();
|
|
35
|
+
resolve();
|
|
36
|
+
};
|
|
37
|
+
const params = { element: renderResult, container, callback, log };
|
|
38
|
+
try {
|
|
39
|
+
renderer(params);
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
executeRendererCallbacks(e);
|
|
43
|
+
reject(e);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { rendering };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import debounce from '@tinkoff/utils/function/debounce';
|
|
2
|
+
import { createElement } from 'react';
|
|
3
|
+
import { useIsomorphicLayoutEffect } from '@tinkoff/react-hooks';
|
|
4
|
+
|
|
5
|
+
let hydrateRoot;
|
|
6
|
+
let startTransition;
|
|
7
|
+
try {
|
|
8
|
+
// eslint-disable-next-line import/no-unresolved, import/extensions
|
|
9
|
+
hydrateRoot = require('react-dom/client').hydrateRoot;
|
|
10
|
+
startTransition = require('react').startTransition;
|
|
11
|
+
}
|
|
12
|
+
catch { }
|
|
13
|
+
const ExecuteRenderCallback = ({ children, callback, }) => {
|
|
14
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15
|
+
useIsomorphicLayoutEffect(callback, []);
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
+
return children;
|
|
18
|
+
};
|
|
19
|
+
const renderer = ({ element, container, callback, log }) => {
|
|
20
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES && typeof hydrateRoot === 'function') {
|
|
21
|
+
const wrappedElement = createElement(ExecuteRenderCallback, { callback }, element);
|
|
22
|
+
let allErrors = new Map();
|
|
23
|
+
const logHydrateRecoverableError = debounce(50, () => {
|
|
24
|
+
if (allErrors.size === 0) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const [{ error, errorInfo }, ...otherErrors] = Array.from(allErrors.values());
|
|
28
|
+
allErrors = new Map();
|
|
29
|
+
log.error({
|
|
30
|
+
event: 'hydrate:recover-after-error',
|
|
31
|
+
error,
|
|
32
|
+
errorInfo,
|
|
33
|
+
otherErrors,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
return startTransition(() => {
|
|
37
|
+
hydrateRoot(container, wrappedElement, {
|
|
38
|
+
onRecoverableError: (error, errorInfo) => {
|
|
39
|
+
// deduplicate by unique important string values
|
|
40
|
+
allErrors.set((error === null || error === void 0 ? void 0 : error.message) + (errorInfo === null || errorInfo === void 0 ? void 0 : errorInfo.componentStack), { error, errorInfo });
|
|
41
|
+
logHydrateRecoverableError();
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const { hydrate } = require('react-dom');
|
|
47
|
+
return hydrate(element, container, callback);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export { renderer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Provider } from '@tramvai/state';
|
|
3
|
+
import { DIContext } from '@tramvai/react';
|
|
4
|
+
import { Root } from './root.browser.js';
|
|
5
|
+
|
|
6
|
+
function renderReact({ di }, context) {
|
|
7
|
+
const serverState = typeof window !== 'undefined' ? context.getState() : undefined;
|
|
8
|
+
return (jsx(Provider, { context: context, serverState: serverState, children: jsx(DIContext.Provider, { value: di, children: jsx(Root, {}) }) }));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { renderReact };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Provider } from '@tramvai/state';
|
|
3
|
+
import { DIContext } from '@tramvai/react';
|
|
4
|
+
import { Root } from './root.es.js';
|
|
5
|
+
|
|
6
|
+
function renderReact({ di }, context) {
|
|
7
|
+
const serverState = typeof window !== 'undefined' ? context.getState() : undefined;
|
|
8
|
+
return (jsx(Provider, { context: context, serverState: serverState, children: jsx(DIContext.Provider, { value: di, children: jsx(Root, {}) }) }));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { renderReact };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var state = require('@tramvai/state');
|
|
7
|
+
var react = require('@tramvai/react');
|
|
8
|
+
var root = require('./root.js');
|
|
9
|
+
|
|
10
|
+
function renderReact({ di }, context) {
|
|
11
|
+
const serverState = typeof window !== 'undefined' ? context.getState() : undefined;
|
|
12
|
+
return (jsxRuntime.jsx(state.Provider, { context: context, serverState: serverState, children: jsxRuntime.jsx(react.DIContext.Provider, { value: di, children: jsxRuntime.jsx(root.Root, {}) }) }));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
exports.renderReact = renderReact;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useDi, ERROR_BOUNDARY_TOKEN, ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, UniversalErrorBoundary } from '@tramvai/react';
|
|
4
|
+
import { useUrl } from '@tramvai/module-router';
|
|
5
|
+
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
6
|
+
import { useStore } from '@tramvai/state';
|
|
7
|
+
import { PageErrorStore, deserializeError } from '../shared/pageErrorStore.browser.js';
|
|
8
|
+
|
|
9
|
+
const PageErrorBoundary = (props) => {
|
|
10
|
+
const { children } = props;
|
|
11
|
+
const pageService = useDi(PAGE_SERVICE_TOKEN);
|
|
12
|
+
const url = useUrl();
|
|
13
|
+
const serializedError = useStore(PageErrorStore);
|
|
14
|
+
const error = useMemo(() => {
|
|
15
|
+
return serializedError && deserializeError(serializedError);
|
|
16
|
+
}, [serializedError]);
|
|
17
|
+
const errorHandlers = useDi({ token: ERROR_BOUNDARY_TOKEN, optional: true });
|
|
18
|
+
const fallbackFromDi = useDi({ token: ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
19
|
+
const fallback = pageService.resolveComponentFromConfig('errorBoundary');
|
|
20
|
+
return (jsx(UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi, children: children }));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { PageErrorBoundary };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { useDi, ERROR_BOUNDARY_TOKEN, ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, UniversalErrorBoundary } from '@tramvai/react';
|
|
4
|
+
import { useUrl } from '@tramvai/module-router';
|
|
5
|
+
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
6
|
+
import { useStore } from '@tramvai/state';
|
|
7
|
+
import { PageErrorStore, deserializeError } from '../shared/pageErrorStore.es.js';
|
|
8
|
+
|
|
9
|
+
const PageErrorBoundary = (props) => {
|
|
10
|
+
const { children } = props;
|
|
11
|
+
const pageService = useDi(PAGE_SERVICE_TOKEN);
|
|
12
|
+
const url = useUrl();
|
|
13
|
+
const serializedError = useStore(PageErrorStore);
|
|
14
|
+
const error = useMemo(() => {
|
|
15
|
+
return serializedError && deserializeError(serializedError);
|
|
16
|
+
}, [serializedError]);
|
|
17
|
+
const errorHandlers = useDi({ token: ERROR_BOUNDARY_TOKEN, optional: true });
|
|
18
|
+
const fallbackFromDi = useDi({ token: ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
19
|
+
const fallback = pageService.resolveComponentFromConfig('errorBoundary');
|
|
20
|
+
return (jsx(UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi, children: children }));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { PageErrorBoundary };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var react$1 = require('react');
|
|
7
|
+
var react = require('@tramvai/react');
|
|
8
|
+
var moduleRouter = require('@tramvai/module-router');
|
|
9
|
+
var tokensRouter = require('@tramvai/tokens-router');
|
|
10
|
+
var state = require('@tramvai/state');
|
|
11
|
+
var pageErrorStore = require('../shared/pageErrorStore.js');
|
|
12
|
+
|
|
13
|
+
const PageErrorBoundary = (props) => {
|
|
14
|
+
const { children } = props;
|
|
15
|
+
const pageService = react.useDi(tokensRouter.PAGE_SERVICE_TOKEN);
|
|
16
|
+
const url = moduleRouter.useUrl();
|
|
17
|
+
const serializedError = state.useStore(pageErrorStore.PageErrorStore);
|
|
18
|
+
const error = react$1.useMemo(() => {
|
|
19
|
+
return serializedError && pageErrorStore.deserializeError(serializedError);
|
|
20
|
+
}, [serializedError]);
|
|
21
|
+
const errorHandlers = react.useDi({ token: react.ERROR_BOUNDARY_TOKEN, optional: true });
|
|
22
|
+
const fallbackFromDi = react.useDi({ token: react.ERROR_BOUNDARY_FALLBACK_COMPONENT_TOKEN, optional: true });
|
|
23
|
+
const fallback = pageService.resolveComponentFromConfig('errorBoundary');
|
|
24
|
+
return (jsxRuntime.jsx(react.UniversalErrorBoundary, { url: url, error: error, errorHandlers: errorHandlers, fallback: fallback, fallbackFromDi: fallbackFromDi, children: children }));
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
exports.PageErrorBoundary = PageErrorBoundary;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { usePageService } from '@tramvai/module-router';
|
|
4
|
+
import { PageErrorBoundary } from './pageErrorBoundary.browser.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Result component structure:
|
|
8
|
+
*
|
|
9
|
+
* <Root>
|
|
10
|
+
* <RootComponent>
|
|
11
|
+
* <LayoutComponent>
|
|
12
|
+
* <NestedLayoutComponent>
|
|
13
|
+
* <ErrorBoundaryComponent>
|
|
14
|
+
* <PageComponent />
|
|
15
|
+
* </ErrorBoundaryComponent>
|
|
16
|
+
* </NestedLayoutComponent>
|
|
17
|
+
* </LayoutComponent>
|
|
18
|
+
* </RootComponent>
|
|
19
|
+
* </Root>
|
|
20
|
+
*
|
|
21
|
+
* All components separated for a few reasons:
|
|
22
|
+
* - Page subtree can be rendered independently when Layout and Nested Layout the same
|
|
23
|
+
* - Nested Layout can be rerendered only on its changes
|
|
24
|
+
* - Layout can be rendered only on its changes
|
|
25
|
+
*/
|
|
26
|
+
const LayoutRenderComponent = ({ children }) => {
|
|
27
|
+
const pageService = usePageService();
|
|
28
|
+
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
29
|
+
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
30
|
+
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
31
|
+
const layout = useMemo(() => (jsx(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent, children: children })), [LayoutComponent, HeaderComponent, FooterComponent, children]);
|
|
32
|
+
return layout;
|
|
33
|
+
};
|
|
34
|
+
const NestedLayoutRenderComponent = ({ children }) => {
|
|
35
|
+
const pageService = usePageService();
|
|
36
|
+
const NestedLayoutComponent = pageService.resolveComponentFromConfig('nestedLayout');
|
|
37
|
+
const nestedLayout = useMemo(() => jsx(NestedLayoutComponent, { children: children }), [NestedLayoutComponent, children]);
|
|
38
|
+
return nestedLayout;
|
|
39
|
+
};
|
|
40
|
+
const PageRenderComponent = () => {
|
|
41
|
+
const pageService = usePageService();
|
|
42
|
+
const { pageComponent } = pageService.getConfig();
|
|
43
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
44
|
+
if (!PageComponent) {
|
|
45
|
+
PageComponent = () => {
|
|
46
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const page = useMemo(() => (jsx(PageErrorBoundary, { children: jsx(PageComponent, {}) })), [PageComponent]);
|
|
50
|
+
return page;
|
|
51
|
+
};
|
|
52
|
+
const Root = () => {
|
|
53
|
+
const pageRenderComponent = useMemo(() => jsx(PageRenderComponent, {}), []);
|
|
54
|
+
const nestedLayoutRenderComponent = useMemo(() => jsx(NestedLayoutRenderComponent, { children: pageRenderComponent }), [pageRenderComponent]);
|
|
55
|
+
return jsx(LayoutRenderComponent, { children: nestedLayoutRenderComponent });
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { Root };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { usePageService } from '@tramvai/module-router';
|
|
4
|
+
import { PageErrorBoundary } from './pageErrorBoundary.es.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Result component structure:
|
|
8
|
+
*
|
|
9
|
+
* <Root>
|
|
10
|
+
* <RootComponent>
|
|
11
|
+
* <LayoutComponent>
|
|
12
|
+
* <NestedLayoutComponent>
|
|
13
|
+
* <ErrorBoundaryComponent>
|
|
14
|
+
* <PageComponent />
|
|
15
|
+
* </ErrorBoundaryComponent>
|
|
16
|
+
* </NestedLayoutComponent>
|
|
17
|
+
* </LayoutComponent>
|
|
18
|
+
* </RootComponent>
|
|
19
|
+
* </Root>
|
|
20
|
+
*
|
|
21
|
+
* All components separated for a few reasons:
|
|
22
|
+
* - Page subtree can be rendered independently when Layout and Nested Layout the same
|
|
23
|
+
* - Nested Layout can be rerendered only on its changes
|
|
24
|
+
* - Layout can be rendered only on its changes
|
|
25
|
+
*/
|
|
26
|
+
const LayoutRenderComponent = ({ children }) => {
|
|
27
|
+
const pageService = usePageService();
|
|
28
|
+
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
29
|
+
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
30
|
+
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
31
|
+
const layout = useMemo(() => (jsx(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent, children: children })), [LayoutComponent, HeaderComponent, FooterComponent, children]);
|
|
32
|
+
return layout;
|
|
33
|
+
};
|
|
34
|
+
const NestedLayoutRenderComponent = ({ children }) => {
|
|
35
|
+
const pageService = usePageService();
|
|
36
|
+
const NestedLayoutComponent = pageService.resolveComponentFromConfig('nestedLayout');
|
|
37
|
+
const nestedLayout = useMemo(() => jsx(NestedLayoutComponent, { children: children }), [NestedLayoutComponent, children]);
|
|
38
|
+
return nestedLayout;
|
|
39
|
+
};
|
|
40
|
+
const PageRenderComponent = () => {
|
|
41
|
+
const pageService = usePageService();
|
|
42
|
+
const { pageComponent } = pageService.getConfig();
|
|
43
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
44
|
+
if (!PageComponent) {
|
|
45
|
+
PageComponent = () => {
|
|
46
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const page = useMemo(() => (jsx(PageErrorBoundary, { children: jsx(PageComponent, {}) })), [PageComponent]);
|
|
50
|
+
return page;
|
|
51
|
+
};
|
|
52
|
+
const Root = () => {
|
|
53
|
+
const pageRenderComponent = useMemo(() => jsx(PageRenderComponent, {}), []);
|
|
54
|
+
const nestedLayoutRenderComponent = useMemo(() => jsx(NestedLayoutRenderComponent, { children: pageRenderComponent }), [pageRenderComponent]);
|
|
55
|
+
return jsx(LayoutRenderComponent, { children: nestedLayoutRenderComponent });
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export { Root };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var react = require('react');
|
|
7
|
+
var moduleRouter = require('@tramvai/module-router');
|
|
8
|
+
var pageErrorBoundary = require('./pageErrorBoundary.js');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Result component structure:
|
|
12
|
+
*
|
|
13
|
+
* <Root>
|
|
14
|
+
* <RootComponent>
|
|
15
|
+
* <LayoutComponent>
|
|
16
|
+
* <NestedLayoutComponent>
|
|
17
|
+
* <ErrorBoundaryComponent>
|
|
18
|
+
* <PageComponent />
|
|
19
|
+
* </ErrorBoundaryComponent>
|
|
20
|
+
* </NestedLayoutComponent>
|
|
21
|
+
* </LayoutComponent>
|
|
22
|
+
* </RootComponent>
|
|
23
|
+
* </Root>
|
|
24
|
+
*
|
|
25
|
+
* All components separated for a few reasons:
|
|
26
|
+
* - Page subtree can be rendered independently when Layout and Nested Layout the same
|
|
27
|
+
* - Nested Layout can be rerendered only on its changes
|
|
28
|
+
* - Layout can be rendered only on its changes
|
|
29
|
+
*/
|
|
30
|
+
const LayoutRenderComponent = ({ children }) => {
|
|
31
|
+
const pageService = moduleRouter.usePageService();
|
|
32
|
+
const LayoutComponent = pageService.resolveComponentFromConfig('layout');
|
|
33
|
+
const HeaderComponent = pageService.resolveComponentFromConfig('header');
|
|
34
|
+
const FooterComponent = pageService.resolveComponentFromConfig('footer');
|
|
35
|
+
const layout = react.useMemo(() => (jsxRuntime.jsx(LayoutComponent, { Header: HeaderComponent, Footer: FooterComponent, children: children })), [LayoutComponent, HeaderComponent, FooterComponent, children]);
|
|
36
|
+
return layout;
|
|
37
|
+
};
|
|
38
|
+
const NestedLayoutRenderComponent = ({ children }) => {
|
|
39
|
+
const pageService = moduleRouter.usePageService();
|
|
40
|
+
const NestedLayoutComponent = pageService.resolveComponentFromConfig('nestedLayout');
|
|
41
|
+
const nestedLayout = react.useMemo(() => jsxRuntime.jsx(NestedLayoutComponent, { children: children }), [NestedLayoutComponent, children]);
|
|
42
|
+
return nestedLayout;
|
|
43
|
+
};
|
|
44
|
+
const PageRenderComponent = () => {
|
|
45
|
+
const pageService = moduleRouter.usePageService();
|
|
46
|
+
const { pageComponent } = pageService.getConfig();
|
|
47
|
+
let PageComponent = pageService.getComponent(pageComponent);
|
|
48
|
+
if (!PageComponent) {
|
|
49
|
+
PageComponent = () => {
|
|
50
|
+
throw new Error(`Page component '${pageComponent}' not found`);
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const page = react.useMemo(() => (jsxRuntime.jsx(pageErrorBoundary.PageErrorBoundary, { children: jsxRuntime.jsx(PageComponent, {}) })), [PageComponent]);
|
|
54
|
+
return page;
|
|
55
|
+
};
|
|
56
|
+
const Root = () => {
|
|
57
|
+
const pageRenderComponent = react.useMemo(() => jsxRuntime.jsx(PageRenderComponent, {}), []);
|
|
58
|
+
const nestedLayoutRenderComponent = react.useMemo(() => jsxRuntime.jsx(NestedLayoutRenderComponent, { children: pageRenderComponent }), [pageRenderComponent]);
|
|
59
|
+
return jsxRuntime.jsx(LayoutRenderComponent, { children: nestedLayoutRenderComponent });
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
exports.Root = Root;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
|
|
3
|
+
const thirtySeconds = 1000 * 30;
|
|
4
|
+
const getFileContentLength = async (url) => {
|
|
5
|
+
const info = await fetch(url, { method: 'HEAD', timeout: thirtySeconds });
|
|
6
|
+
return info.headers.get('content-length');
|
|
7
|
+
};
|
|
8
|
+
const getFile = async (url) => {
|
|
9
|
+
const fileResponse = await fetch(url, { timeout: thirtySeconds });
|
|
10
|
+
if (fileResponse.ok) {
|
|
11
|
+
const file = await fileResponse.text();
|
|
12
|
+
return file;
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export { getFile, getFileContentLength };
|