@tramvai/module-child-app 2.61.2 → 2.63.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/README.md +102 -7
- package/lib/browser/preload.d.ts +1 -0
- package/lib/browser/render.d.ts +1 -2
- package/lib/server/render.d.ts +1 -3
- package/lib/server.browser.js +93 -49
- package/lib/server.es.js +72 -51
- package/lib/server.js +70 -49
- package/lib/shared/di.d.ts +1 -1
- package/lib/shared/react/component.d.ts +1 -1
- package/lib/shared/react/render-context.d.ts +1 -1
- package/lib/shared/resolutionConfigManager.d.ts +6 -3
- package/lib/shared/singletonDi.d.ts +1 -1
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -32,6 +32,34 @@ createApp({
|
|
|
32
32
|
- `RequestDI` - DI-Container which is created for every request and represents specific data for single client. RequestDI inherits providers from SingletonDI and it is independent from other RequestDIs
|
|
33
33
|
- `CommandLineRunner` - instance of [CommandModule](references/modules/common.md#commandmodule)
|
|
34
34
|
|
|
35
|
+
### Workflow
|
|
36
|
+
|
|
37
|
+
This section will explain how the child-app are loaded and executed.
|
|
38
|
+
|
|
39
|
+
#### Both SSR + Client hydration
|
|
40
|
+
|
|
41
|
+
1. Provider `CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN` will assemble all of the configs for child-apps that were provided through token `CHILD_APP_RESOLUTION_CONFIGS_TOKEN` and resolve the configs on `resolvePageDeps` command line
|
|
42
|
+
2. Provider `CHILD_APP_RESOLVE_CONFIG_TOKEN` is used to generate config that are later consumable by child-app loader
|
|
43
|
+
3. Child-apps that will be rendered on the page should be preloaded with `CHILD_APP_PRELOAD_MANAGER_TOKEN` - see [preload child-app](#preload-child-app)
|
|
44
|
+
|
|
45
|
+
#### SSR
|
|
46
|
+
|
|
47
|
+
1. For every child-app that was preloaded server loads its code and executes all of the initialization - see [loading child-app](#loading-child-app)
|
|
48
|
+
2. Any child-app that were preloaded during request are added as script tag to client code to the output html
|
|
49
|
+
3. During render for child-apps their render code is executed to provide proper HTML
|
|
50
|
+
4. State is dehydrated for child-app the same time as root-app's state
|
|
51
|
+
|
|
52
|
+
#### Client hydration
|
|
53
|
+
|
|
54
|
+
1. For every child-app that was preloaded on server tramvai executes all of the initialization - see [loading child-app](#loading-child-app). In other cases initialization happens during first usage
|
|
55
|
+
2. If child-app was preloaded on server than client code should be loaded on page loaded. Otherwise tramvai will try to load client code on preload call on client side or during attempt to render child-app
|
|
56
|
+
3. During page render react will attempt to rehydrate render for child-apps that came from server. In case of errors it will rerender it from scratch
|
|
57
|
+
|
|
58
|
+
#### SPA navigations
|
|
59
|
+
|
|
60
|
+
1. During loading for next route child-app might be preloaded - it will be initialized during loading in that case otherwise child-app will be loaded as soon as it will be used.
|
|
61
|
+
2. While loading child-app it will render null. After loading child-app's render function will be used
|
|
62
|
+
|
|
35
63
|
### DI
|
|
36
64
|
|
|
37
65
|
Every child-app has its own DI-hierarchy which is isolated from other child app and partially from root-app. The only way communicate fpr DIs it's getting providers from root-app di inside child-app.
|
|
@@ -136,8 +164,70 @@ This token is considered undesirable to use as it leads to high coupling with st
|
|
|
136
164
|
|
|
137
165
|
:::
|
|
138
166
|
|
|
167
|
+
### Error handling
|
|
168
|
+
|
|
169
|
+
#### Error while loading child-app configs
|
|
170
|
+
|
|
171
|
+
Child-app configs might be loaded with providers for multi token `CHILD_APP_RESOLUTION_CONFIGS_TOKEN` that are implemented in custom modules or in the app code.
|
|
172
|
+
|
|
173
|
+
Error that were raised in custom providers will be logged as errors under `child-app:resolution-config` key. After that there errors will be ignored and won't affect other resolutions, but the configs that could be loaded with that provider will be lost.
|
|
174
|
+
|
|
175
|
+
#### Child-app with specified name was not found
|
|
176
|
+
|
|
177
|
+
There is 2 causes that may lead to missing child-app in config:
|
|
178
|
+
|
|
179
|
+
- configs defined through `CHILD_APP_RESOLUTION_CONFIGS_TOKEN` was failed and therefore there is no info about used child-app
|
|
180
|
+
- wrong naming of child-app
|
|
181
|
+
|
|
182
|
+
In any of that causes the error about missing child-app will be logged and the render for it will just return null.
|
|
183
|
+
|
|
184
|
+
If you are facing that problem first check the logs about errors for loading child-app configs than check that naming is right and such child-app exists in your configs.
|
|
185
|
+
|
|
186
|
+
#### Failed to load child-app code
|
|
187
|
+
|
|
188
|
+
Request to child-app code can fail by various causes.
|
|
189
|
+
|
|
190
|
+
If request has failed on server side the script tag with link to child-app client code will still be added to the html in order to try to load the child-app on client side. It will render fallback if provided or null on SSR (wrapped in Suspense for react@18) in that case and will try to resolve and render the child-app on the client.
|
|
191
|
+
|
|
192
|
+
If request has failed on client side it will render [fallback](#fallback) passing error or the default errorBoundary component.
|
|
193
|
+
|
|
194
|
+
#### Error during child-app render
|
|
195
|
+
|
|
196
|
+
Errors that happens inside child-app's render function
|
|
197
|
+
|
|
198
|
+
If render has failed on server side it will render fallback if provided or null otherwise. It may then proper rehydrated on client side.
|
|
199
|
+
|
|
200
|
+
If render has failed on client side it will render fallback with error if provided or default errorBoundary component
|
|
201
|
+
|
|
202
|
+
#### Error in commandLine handler
|
|
203
|
+
|
|
204
|
+
Any errors inside child-app commandLine execution will be logged and won't affect the execution of the root-app.
|
|
205
|
+
|
|
139
206
|
## API
|
|
140
207
|
|
|
208
|
+
### ChildApp
|
|
209
|
+
|
|
210
|
+
React component to render child-app with specified config in the react tree
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import React from 'react';
|
|
214
|
+
import { ChildApp } from '@tramvai/module-child-app';
|
|
215
|
+
|
|
216
|
+
export const Page = () => {
|
|
217
|
+
return (
|
|
218
|
+
<div>
|
|
219
|
+
...
|
|
220
|
+
<ChildApp name="[name]" />
|
|
221
|
+
...
|
|
222
|
+
</div>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### fallback
|
|
228
|
+
|
|
229
|
+
React.ComponentType that will be rendered while child-app is loading (by default is null) or there was an error inside child-app (by default is a standard errorBoundary component)
|
|
230
|
+
|
|
141
231
|
### CHILD_APP_INTERNAL_ROOT_STATE_ALLOWED_STORE_TOKEN
|
|
142
232
|
|
|
143
233
|
Defines the list of allowed root-app store names that might be used inside child-app.
|
|
@@ -269,7 +359,14 @@ const PageCmp: PageComponent = () => {
|
|
|
269
359
|
PageCmp.childApps = [{ name: '[name]' }];
|
|
270
360
|
```
|
|
271
361
|
|
|
272
|
-
### Debug child-app
|
|
362
|
+
### Debug child-app problems
|
|
363
|
+
|
|
364
|
+
If your are facing any problems while developing or using child-app use next instructions first.
|
|
365
|
+
|
|
366
|
+
1. Check the logs with key `child-app` that may lead to source of problems
|
|
367
|
+
2. If there is not enough logs enable all `child-app` logs - [how to display logs](references/modules/log.md#display-logs)
|
|
368
|
+
|
|
369
|
+
### Run debug version of child-app
|
|
273
370
|
|
|
274
371
|
#### Single child-app
|
|
275
372
|
|
|
@@ -328,13 +425,11 @@ You may specify a full config to debug to a specific child-app:
|
|
|
328
425
|
|
|
329
426
|
### This Suspense boundary received an update before it finished hydrating
|
|
330
427
|
|
|
331
|
-
When `React` >= `18` version is used, child-app will be wrapped in `Suspense` boundary for [Selective Hydration](https://github.com/reactwg/react-18/discussions/130).
|
|
332
|
-
This optimization can significantly decrease Total Blocking Time metric of the page.
|
|
428
|
+
When `React` >= `18` version is used, child-app will be wrapped in `Suspense` boundary for [Selective Hydration](https://github.com/reactwg/react-18/discussions/130). This optimization can significantly decrease Total Blocking Time metric of the page.
|
|
333
429
|
|
|
334
|
-
There is one drawback of this optimization - if you will try rerender child-app during selective hydration, `React` will switch to deopt mode and made full client-rendering of the child-app component.
|
|
335
|
-
Potential ways to fix this problem [described here](https://github.com/facebook/react/issues/24476#issuecomment-1127800350).
|
|
336
|
-
`ChildApp` component already wrapped in `React.memo`.
|
|
430
|
+
There is one drawback of this optimization - if you will try rerender child-app during selective hydration, `React` will switch to deopt mode and made full client-rendering of the child-app component. Potential ways to fix this problem [described here](https://github.com/facebook/react/issues/24476#issuecomment-1127800350). `ChildApp` component already wrapped in `React.memo`.
|
|
337
431
|
|
|
338
432
|
Few advices to avoid this problem:
|
|
433
|
+
|
|
339
434
|
- Memoize object, passed to child-app `props` property
|
|
340
|
-
- Prevent pass to child-app properties, which can be changed during hydration, for example at
|
|
435
|
+
- Prevent pass to child-app properties, which can be changed during hydration, for example at client-side in page actions
|
package/lib/browser/preload.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare class PreloadManager implements ChildAppPreloadManager {
|
|
|
11
11
|
private currentlyPreloaded;
|
|
12
12
|
private hasPreloadBefore;
|
|
13
13
|
private hasInitialized;
|
|
14
|
+
private map;
|
|
14
15
|
constructor({ loader, runner, resolutionConfigManager, resolveExternalConfig, store, }: {
|
|
15
16
|
loader: ChildAppLoader;
|
|
16
17
|
runner: ChildAppCommandLineRunner;
|
package/lib/browser/render.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export declare class RenderManager implements ChildAppRenderManager {
|
|
|
12
12
|
diManager: ChildAppDiManager;
|
|
13
13
|
resolveExternalConfig: typeof CHILD_APP_RESOLVE_CONFIG_TOKEN;
|
|
14
14
|
});
|
|
15
|
-
getChildDi(request: ChildAppRequestConfig): [Container |
|
|
16
|
-
flush(): Promise<boolean>;
|
|
15
|
+
getChildDi(request: ChildAppRequestConfig): [Container | undefined, undefined | Promise<Container | undefined>];
|
|
17
16
|
clear(): void;
|
|
18
17
|
}
|
package/lib/server/render.d.ts
CHANGED
|
@@ -7,14 +7,12 @@ export declare class RenderManager implements ChildAppRenderManager {
|
|
|
7
7
|
private readonly resolveFullConfig;
|
|
8
8
|
private readonly log;
|
|
9
9
|
private readonly hasRenderedSet;
|
|
10
|
-
private readonly loadingInProgress;
|
|
11
10
|
constructor({ logger, preloadManager, diManager, resolveFullConfig, }: {
|
|
12
11
|
logger: typeof LOGGER_TOKEN;
|
|
13
12
|
preloadManager: ChildAppPreloadManager;
|
|
14
13
|
diManager: ChildAppDiManager;
|
|
15
14
|
resolveFullConfig: typeof CHILD_APP_RESOLVE_CONFIG_TOKEN;
|
|
16
15
|
});
|
|
17
|
-
getChildDi(request: ChildAppRequestConfig): [Container |
|
|
18
|
-
flush(): Promise<boolean>;
|
|
16
|
+
getChildDi(request: ChildAppRequestConfig): [Container | undefined, undefined | Promise<Container | undefined>];
|
|
19
17
|
clear(): void;
|
|
20
18
|
}
|
package/lib/server.browser.js
CHANGED
|
@@ -6,22 +6,23 @@ export * from '@tramvai/tokens-child-app';
|
|
|
6
6
|
import { CONTEXT_TOKEN, ACTION_PAGE_RUNNER_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, DISPATCHER_CONTEXT_TOKEN, STORE_MIDDLEWARE, INITIAL_APP_STATE_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN } from '@tramvai/tokens-common';
|
|
7
7
|
import { RENDER_SLOTS, EXTEND_RENDER } from '@tramvai/tokens-render';
|
|
8
8
|
import { ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN, PAGE_SERVICE_TOKEN, ROUTER_TOKEN } from '@tramvai/tokens-router';
|
|
9
|
-
import { resolveLazyComponent, useDi } from '@tramvai/react';
|
|
9
|
+
import { resolveLazyComponent, UniversalErrorBoundary, useDi } from '@tramvai/react';
|
|
10
10
|
import flatten from '@tinkoff/utils/array/flatten';
|
|
11
11
|
import noop from '@tinkoff/utils/function/noop';
|
|
12
12
|
import { Subscription, ChildDispatcherContext, createEvent, createReducer } from '@tramvai/state';
|
|
13
13
|
import { jsx } from 'react/jsx-runtime';
|
|
14
|
-
import { createContext, memo, useContext, useMemo, useState, useEffect
|
|
14
|
+
import { createContext, memo, Suspense, useContext, useMemo, useState, useEffect } from 'react';
|
|
15
15
|
import applyOrReturn from '@tinkoff/utils/function/applyOrReturn';
|
|
16
16
|
import { loadModule } from '@tinkoff/module-loader-client';
|
|
17
|
+
import { useUrl } from '@tramvai/module-router';
|
|
17
18
|
|
|
18
19
|
const getChildProviders$2 = (appDi) => {
|
|
19
20
|
const context = appDi.get(CONTEXT_TOKEN);
|
|
20
21
|
return [
|
|
21
|
-
{
|
|
22
|
+
provide({
|
|
22
23
|
provide: commandLineListTokens.customerStart,
|
|
23
24
|
multi: true,
|
|
24
|
-
useFactory: ({ subscriptions
|
|
25
|
+
useFactory: ({ subscriptions }) => {
|
|
25
26
|
return async function resolveRootStateForChild() {
|
|
26
27
|
if (!subscriptions) {
|
|
27
28
|
return;
|
|
@@ -40,7 +41,7 @@ const getChildProviders$2 = (appDi) => {
|
|
|
40
41
|
deps: {
|
|
41
42
|
subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
|
|
42
43
|
},
|
|
43
|
-
},
|
|
44
|
+
}),
|
|
44
45
|
provide({
|
|
45
46
|
provide: commandLineListTokens.clear,
|
|
46
47
|
multi: true,
|
|
@@ -154,7 +155,6 @@ class SingletonDiManager {
|
|
|
154
155
|
error,
|
|
155
156
|
config,
|
|
156
157
|
});
|
|
157
|
-
return null;
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
forEachChildDi(cb) {
|
|
@@ -223,7 +223,7 @@ const getChildProviders = (appDi) => {
|
|
|
223
223
|
dispatcher,
|
|
224
224
|
// context will be set later by the CONTEXT_TOKEN
|
|
225
225
|
context: {},
|
|
226
|
-
initialState,
|
|
226
|
+
initialState: initialState !== null && initialState !== void 0 ? initialState : { stores: [] },
|
|
227
227
|
middlewares: flatten(middlewares || []),
|
|
228
228
|
parentDispatcherContext,
|
|
229
229
|
parentAllowedStores: flatten(parentAllowedStores || []),
|
|
@@ -284,7 +284,7 @@ class DiManager {
|
|
|
284
284
|
|
|
285
285
|
class CommandLineRunner {
|
|
286
286
|
constructor({ logger, rootCommandLineRunner, diManager, }) {
|
|
287
|
-
this.log = logger('child-app:
|
|
287
|
+
this.log = logger('child-app:command-line-runner');
|
|
288
288
|
this.rootCommandLineRunner = rootCommandLineRunner;
|
|
289
289
|
this.diManager = diManager;
|
|
290
290
|
}
|
|
@@ -384,10 +384,11 @@ const getModuleFederation = async (container, name = 'entry') => {
|
|
|
384
384
|
};
|
|
385
385
|
|
|
386
386
|
class ChildAppResolutionConfigManager {
|
|
387
|
-
constructor({ configs, }) {
|
|
387
|
+
constructor({ configs, logger, }) {
|
|
388
388
|
this.hasInitialized = false;
|
|
389
389
|
this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
|
|
390
390
|
this.mapping = new Map();
|
|
391
|
+
this.log = logger('child-app:resolution-config');
|
|
391
392
|
}
|
|
392
393
|
async init() {
|
|
393
394
|
if (this.hasInitialized) {
|
|
@@ -398,10 +399,18 @@ class ChildAppResolutionConfigManager {
|
|
|
398
399
|
}
|
|
399
400
|
this.initPromise = (async () => {
|
|
400
401
|
const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
|
|
401
|
-
return
|
|
402
|
+
return Promise.resolve()
|
|
403
|
+
.then(() => {
|
|
404
|
+
return applyOrReturn([], rawConfig);
|
|
405
|
+
})
|
|
406
|
+
.catch((error) => {
|
|
407
|
+
this.log.error(error, 'Failed while resolving resolution config');
|
|
408
|
+
});
|
|
402
409
|
}));
|
|
403
410
|
flatten(configs).forEach((config) => {
|
|
404
|
-
|
|
411
|
+
if (config) {
|
|
412
|
+
this.mapping.set(config.name, config);
|
|
413
|
+
}
|
|
405
414
|
});
|
|
406
415
|
this.hasInitialized = true;
|
|
407
416
|
})();
|
|
@@ -411,7 +420,7 @@ class ChildAppResolutionConfigManager {
|
|
|
411
420
|
var _a;
|
|
412
421
|
const fromMapping = this.mapping.get(name);
|
|
413
422
|
if (!fromMapping) {
|
|
414
|
-
return
|
|
423
|
+
return;
|
|
415
424
|
}
|
|
416
425
|
const cfg = fromMapping.byTag[tag];
|
|
417
426
|
if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
|
|
@@ -444,6 +453,7 @@ const sharedProviders = [
|
|
|
444
453
|
useClass: ChildAppResolutionConfigManager,
|
|
445
454
|
deps: {
|
|
446
455
|
configs: { token: CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
|
|
456
|
+
logger: LOGGER_TOKEN,
|
|
447
457
|
},
|
|
448
458
|
}),
|
|
449
459
|
provide({
|
|
@@ -460,8 +470,9 @@ const sharedProviders = [
|
|
|
460
470
|
}),
|
|
461
471
|
provide({
|
|
462
472
|
provide: CHILD_APP_RESOLVE_CONFIG_TOKEN,
|
|
463
|
-
useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
|
|
473
|
+
useFactory: ({ envManager, logger, rootBaseUrl, resolutionConfigManager }) => {
|
|
464
474
|
const rawEnv = envManager.get('CHILD_APP_DEBUG');
|
|
475
|
+
const log = logger('child-app:resolve-config');
|
|
465
476
|
const debug = new Map();
|
|
466
477
|
rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
|
|
467
478
|
const [name, url] = entry.split('=');
|
|
@@ -473,7 +484,8 @@ const sharedProviders = [
|
|
|
473
484
|
const req = { name, tag, version: request.version };
|
|
474
485
|
const config = resolutionConfigManager.resolve(req);
|
|
475
486
|
if (!config) {
|
|
476
|
-
|
|
487
|
+
log.error(`Child-app "${name}" with tag "${tag}" has not found`);
|
|
488
|
+
return;
|
|
477
489
|
}
|
|
478
490
|
const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
|
|
479
491
|
const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
|
|
@@ -505,6 +517,7 @@ const sharedProviders = [
|
|
|
505
517
|
},
|
|
506
518
|
deps: {
|
|
507
519
|
envManager: ENV_MANAGER_TOKEN,
|
|
520
|
+
logger: LOGGER_TOKEN,
|
|
508
521
|
rootBaseUrl: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
|
|
509
522
|
resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
|
|
510
523
|
},
|
|
@@ -711,6 +724,7 @@ class PreloadManager {
|
|
|
711
724
|
this.currentlyPreloaded = new Map();
|
|
712
725
|
this.hasPreloadBefore = new Set();
|
|
713
726
|
this.hasInitialized = false;
|
|
727
|
+
this.map = new Map();
|
|
714
728
|
this.loader = loader;
|
|
715
729
|
this.runner = runner;
|
|
716
730
|
this.store = store;
|
|
@@ -720,29 +734,39 @@ class PreloadManager {
|
|
|
720
734
|
async preload(request) {
|
|
721
735
|
await this.init();
|
|
722
736
|
const config = this.resolveExternalConfig(request);
|
|
737
|
+
if (!config) {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
723
740
|
const { key } = config;
|
|
741
|
+
if (this.pageHasRendered) {
|
|
742
|
+
this.currentlyPreloaded.set(key, config);
|
|
743
|
+
}
|
|
724
744
|
if (!this.isPreloaded(config)) {
|
|
745
|
+
if (this.map.has(key)) {
|
|
746
|
+
return this.map.get(key);
|
|
747
|
+
}
|
|
748
|
+
// TODO: remove after dropping support for react@<18 as it can handle hydration errors with Suspense
|
|
725
749
|
// in case React render yet has not been executed do not load any external child-app app as
|
|
726
750
|
// as it will lead to markup mismatch on markup hydration
|
|
727
751
|
if (this.pageHasRendered) {
|
|
728
752
|
// but in case render has happened load child-app as soon as possible
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
753
|
+
const promise = (async () => {
|
|
754
|
+
try {
|
|
755
|
+
await this.loader.load(config);
|
|
756
|
+
await this.run('customer', config);
|
|
757
|
+
await this.run('clear', config);
|
|
758
|
+
}
|
|
759
|
+
catch (error) { }
|
|
733
760
|
this.hasPreloadBefore.add(key);
|
|
734
|
-
}
|
|
735
|
-
|
|
761
|
+
})();
|
|
762
|
+
this.map.set(key, promise);
|
|
763
|
+
return promise;
|
|
736
764
|
}
|
|
737
765
|
}
|
|
738
|
-
if (this.pageHasRendered) {
|
|
739
|
-
this.currentlyPreloaded.set(key, config);
|
|
740
|
-
}
|
|
741
766
|
}
|
|
742
767
|
isPreloaded(request) {
|
|
743
768
|
const config = this.resolveExternalConfig(request);
|
|
744
|
-
|
|
745
|
-
return this.hasPreloadBefore.has(key);
|
|
769
|
+
return !!config && this.hasPreloadBefore.has(config.key);
|
|
746
770
|
}
|
|
747
771
|
async runPreloaded() {
|
|
748
772
|
await this.init();
|
|
@@ -764,6 +788,7 @@ class PreloadManager {
|
|
|
764
788
|
async clearPreloaded() {
|
|
765
789
|
if (this.pageHasLoaded) {
|
|
766
790
|
this.currentlyPreloaded.clear();
|
|
791
|
+
this.map.clear();
|
|
767
792
|
return;
|
|
768
793
|
}
|
|
769
794
|
this.pageHasLoaded = true;
|
|
@@ -772,6 +797,7 @@ class PreloadManager {
|
|
|
772
797
|
promises.push(this.run('clear', config));
|
|
773
798
|
});
|
|
774
799
|
this.currentlyPreloaded.clear();
|
|
800
|
+
this.map.clear();
|
|
775
801
|
await Promise.all(promises);
|
|
776
802
|
}
|
|
777
803
|
getPreloadedList() {
|
|
@@ -782,8 +808,10 @@ class PreloadManager {
|
|
|
782
808
|
const { preloaded } = this.store.getState(ChildAppStore);
|
|
783
809
|
preloaded.forEach((request) => {
|
|
784
810
|
const config = this.resolveExternalConfig(request);
|
|
785
|
-
|
|
786
|
-
|
|
811
|
+
if (config) {
|
|
812
|
+
this.currentlyPreloaded.set(config.key, config);
|
|
813
|
+
this.hasPreloadBefore.add(config.key);
|
|
814
|
+
}
|
|
787
815
|
});
|
|
788
816
|
this.hasInitialized = true;
|
|
789
817
|
}
|
|
@@ -810,8 +838,11 @@ class RenderManager {
|
|
|
810
838
|
}
|
|
811
839
|
getChildDi(request) {
|
|
812
840
|
const config = this.resolveExternalConfig(request);
|
|
841
|
+
if (!config) {
|
|
842
|
+
throw new Error(`Child app "${request.name}" not found`);
|
|
843
|
+
}
|
|
813
844
|
if (this.preloadManager.isPreloaded(request)) {
|
|
814
|
-
return [this.diManager.getChildDi(config),
|
|
845
|
+
return [this.diManager.getChildDi(config), undefined];
|
|
815
846
|
}
|
|
816
847
|
this.log.warn({
|
|
817
848
|
message: 'Child-app has been used but not preloaded before React render',
|
|
@@ -820,10 +851,7 @@ class RenderManager {
|
|
|
820
851
|
const promiseDi = this.preloadManager.preload(request).then(() => {
|
|
821
852
|
return this.diManager.getChildDi(config);
|
|
822
853
|
});
|
|
823
|
-
return [
|
|
824
|
-
}
|
|
825
|
-
async flush() {
|
|
826
|
-
return false;
|
|
854
|
+
return [undefined, promiseDi];
|
|
827
855
|
}
|
|
828
856
|
clear() { }
|
|
829
857
|
}
|
|
@@ -938,7 +966,9 @@ const browserProviders = [
|
|
|
938
966
|
}),
|
|
939
967
|
];
|
|
940
968
|
|
|
941
|
-
const FailedChildAppFallback = ({ name, version, tag,
|
|
969
|
+
const FailedChildAppFallback = ({ name, version, tag, fallback: Fallback, }) => {
|
|
970
|
+
const logger = useDi(LOGGER_TOKEN);
|
|
971
|
+
const log = logger('child-app:render');
|
|
942
972
|
// On client-side hydration errors will be handled in `hydrateRoot` `onRecoverableError` property,
|
|
943
973
|
// and update errors will be handled in Error Boundaries.
|
|
944
974
|
//
|
|
@@ -948,7 +978,7 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
948
978
|
// On server-side, we still use `renderToString`,
|
|
949
979
|
// and need to manually log render errors for components, wrapped in Suspense Boundaries.
|
|
950
980
|
if (typeof window === 'undefined') {
|
|
951
|
-
|
|
981
|
+
log.error({
|
|
952
982
|
event: 'failed-render',
|
|
953
983
|
message: 'child-app failed to render, will try to recover during hydration',
|
|
954
984
|
name,
|
|
@@ -958,21 +988,29 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
958
988
|
}
|
|
959
989
|
return Fallback ? jsx(Fallback, {}) : null;
|
|
960
990
|
};
|
|
961
|
-
const
|
|
991
|
+
const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
|
|
962
992
|
const renderManager = useContext(RenderContext);
|
|
963
|
-
const resolveExternalConfig = useDi(CHILD_APP_RESOLVE_CONFIG_TOKEN);
|
|
964
993
|
const logger = useDi(LOGGER_TOKEN);
|
|
965
994
|
const log = logger('child-app:render');
|
|
966
|
-
const [maybeDi,
|
|
967
|
-
return renderManager.getChildDi(
|
|
968
|
-
}, [name, version, tag, renderManager
|
|
995
|
+
const [maybeDi, maybePromiseDi] = useMemo(() => {
|
|
996
|
+
return renderManager.getChildDi({ name, version, tag });
|
|
997
|
+
}, [name, version, tag, renderManager]);
|
|
969
998
|
const [di, setDi] = useState(maybeDi);
|
|
999
|
+
const [promiseDi, setPromiseDi] = useState(maybePromiseDi);
|
|
970
1000
|
useEffect(() => {
|
|
971
1001
|
if (!di && promiseDi) {
|
|
972
1002
|
// any errors with loading child-app should be handled in some other place
|
|
973
|
-
promiseDi
|
|
1003
|
+
promiseDi
|
|
1004
|
+
.then(setDi)
|
|
1005
|
+
.finally(() => setPromiseDi(undefined))
|
|
1006
|
+
.catch(noop);
|
|
974
1007
|
}
|
|
975
1008
|
}, [di, promiseDi]);
|
|
1009
|
+
if (!di && promiseDi) {
|
|
1010
|
+
// in case child-app was not rendered on ssr
|
|
1011
|
+
// and we have to wait before it's loading
|
|
1012
|
+
return Fallback ? jsx(Fallback, {}) : null;
|
|
1013
|
+
}
|
|
976
1014
|
if (!di) {
|
|
977
1015
|
log.error({
|
|
978
1016
|
event: 'not-found',
|
|
@@ -981,7 +1019,10 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
981
1019
|
tag,
|
|
982
1020
|
message: 'child-app was not initialized',
|
|
983
1021
|
});
|
|
984
|
-
|
|
1022
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES || typeof window !== 'undefined') {
|
|
1023
|
+
throw new Error(`Child-app was not initialized, check the loading error for child-app "${name}"`);
|
|
1024
|
+
}
|
|
1025
|
+
return Fallback ? jsx(Fallback, {}) : null;
|
|
985
1026
|
}
|
|
986
1027
|
try {
|
|
987
1028
|
const Cmp = di.get({ token: CHILD_APP_INTERNAL_RENDER_TOKEN, optional: true });
|
|
@@ -995,14 +1036,7 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
995
1036
|
});
|
|
996
1037
|
return null;
|
|
997
1038
|
}
|
|
998
|
-
|
|
999
|
-
di,
|
|
1000
|
-
props,
|
|
1001
|
-
});
|
|
1002
|
-
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1003
|
-
return (jsx(Suspense, { fallback: jsx(FailedChildAppFallback, { name: name, version: version, tag: tag, logger: log, fallback: fallback }), children: result }));
|
|
1004
|
-
}
|
|
1005
|
-
return result;
|
|
1039
|
+
return jsx(Cmp, { di: di, props: props });
|
|
1006
1040
|
}
|
|
1007
1041
|
catch (error) {
|
|
1008
1042
|
log.error({
|
|
@@ -1015,6 +1049,16 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
1015
1049
|
});
|
|
1016
1050
|
return null;
|
|
1017
1051
|
}
|
|
1052
|
+
};
|
|
1053
|
+
const ChildApp = memo((config) => {
|
|
1054
|
+
const { fallback } = config;
|
|
1055
|
+
const url = useUrl();
|
|
1056
|
+
const result = (jsx(UniversalErrorBoundary, { url: url, fallback: fallback, children: jsx(ChildAppWrapper, { ...config }) }));
|
|
1057
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1058
|
+
const fallbackRender = FailedChildAppFallback(config);
|
|
1059
|
+
return jsx(Suspense, { fallback: fallbackRender, children: result });
|
|
1060
|
+
}
|
|
1061
|
+
return result;
|
|
1018
1062
|
});
|
|
1019
1063
|
|
|
1020
1064
|
let ChildAppModule = class ChildAppModule {
|
package/lib/server.es.js
CHANGED
|
@@ -6,16 +6,17 @@ export * from '@tramvai/tokens-child-app';
|
|
|
6
6
|
import { ACTION_PAGE_RUNNER_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, CONTEXT_TOKEN, DISPATCHER_CONTEXT_TOKEN, STORE_MIDDLEWARE, INITIAL_APP_STATE_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
|
|
7
7
|
import { RENDER_SLOTS, EXTEND_RENDER, ResourceType, ResourceSlot, RESOURCES_REGISTRY } from '@tramvai/tokens-render';
|
|
8
8
|
import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
|
|
9
|
-
import { resolveLazyComponent, useDi } from '@tramvai/react';
|
|
9
|
+
import { resolveLazyComponent, UniversalErrorBoundary, useDi } from '@tramvai/react';
|
|
10
10
|
import flatten from '@tinkoff/utils/array/flatten';
|
|
11
11
|
import { ChildDispatcherContext, createEvent, createReducer } from '@tramvai/state';
|
|
12
12
|
import { jsx } from 'react/jsx-runtime';
|
|
13
|
-
import { createContext, memo, useContext, useMemo, useState, useEffect
|
|
13
|
+
import { createContext, memo, Suspense, useContext, useMemo, useState, useEffect } from 'react';
|
|
14
14
|
import applyOrReturn from '@tinkoff/utils/function/applyOrReturn';
|
|
15
15
|
import { combineValidators, isUrl, endsWith } from '@tinkoff/env-validators';
|
|
16
16
|
import { safeStringify } from '@tramvai/safe-strings';
|
|
17
17
|
import { ServerLoader as ServerLoader$1 } from '@tinkoff/module-loader-server';
|
|
18
18
|
import noop from '@tinkoff/utils/function/noop';
|
|
19
|
+
import { useUrl } from '@tramvai/module-router';
|
|
19
20
|
|
|
20
21
|
const getChildProviders$2 = (appDi) => {
|
|
21
22
|
return [
|
|
@@ -92,7 +93,6 @@ class SingletonDiManager {
|
|
|
92
93
|
error,
|
|
93
94
|
config,
|
|
94
95
|
});
|
|
95
|
-
return null;
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
forEachChildDi(cb) {
|
|
@@ -161,7 +161,7 @@ const getChildProviders = (appDi) => {
|
|
|
161
161
|
dispatcher,
|
|
162
162
|
// context will be set later by the CONTEXT_TOKEN
|
|
163
163
|
context: {},
|
|
164
|
-
initialState,
|
|
164
|
+
initialState: initialState !== null && initialState !== void 0 ? initialState : { stores: [] },
|
|
165
165
|
middlewares: flatten(middlewares || []),
|
|
166
166
|
parentDispatcherContext,
|
|
167
167
|
parentAllowedStores: flatten(parentAllowedStores || []),
|
|
@@ -222,7 +222,7 @@ class DiManager {
|
|
|
222
222
|
|
|
223
223
|
class CommandLineRunner {
|
|
224
224
|
constructor({ logger, rootCommandLineRunner, diManager, }) {
|
|
225
|
-
this.log = logger('child-app:
|
|
225
|
+
this.log = logger('child-app:command-line-runner');
|
|
226
226
|
this.rootCommandLineRunner = rootCommandLineRunner;
|
|
227
227
|
this.diManager = diManager;
|
|
228
228
|
}
|
|
@@ -322,10 +322,11 @@ const getModuleFederation = async (container, name = 'entry') => {
|
|
|
322
322
|
};
|
|
323
323
|
|
|
324
324
|
class ChildAppResolutionConfigManager {
|
|
325
|
-
constructor({ configs, }) {
|
|
325
|
+
constructor({ configs, logger, }) {
|
|
326
326
|
this.hasInitialized = false;
|
|
327
327
|
this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
|
|
328
328
|
this.mapping = new Map();
|
|
329
|
+
this.log = logger('child-app:resolution-config');
|
|
329
330
|
}
|
|
330
331
|
async init() {
|
|
331
332
|
if (this.hasInitialized) {
|
|
@@ -336,10 +337,18 @@ class ChildAppResolutionConfigManager {
|
|
|
336
337
|
}
|
|
337
338
|
this.initPromise = (async () => {
|
|
338
339
|
const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
|
|
339
|
-
return
|
|
340
|
+
return Promise.resolve()
|
|
341
|
+
.then(() => {
|
|
342
|
+
return applyOrReturn([], rawConfig);
|
|
343
|
+
})
|
|
344
|
+
.catch((error) => {
|
|
345
|
+
this.log.error(error, 'Failed while resolving resolution config');
|
|
346
|
+
});
|
|
340
347
|
}));
|
|
341
348
|
flatten(configs).forEach((config) => {
|
|
342
|
-
|
|
349
|
+
if (config) {
|
|
350
|
+
this.mapping.set(config.name, config);
|
|
351
|
+
}
|
|
343
352
|
});
|
|
344
353
|
this.hasInitialized = true;
|
|
345
354
|
})();
|
|
@@ -349,7 +358,7 @@ class ChildAppResolutionConfigManager {
|
|
|
349
358
|
var _a;
|
|
350
359
|
const fromMapping = this.mapping.get(name);
|
|
351
360
|
if (!fromMapping) {
|
|
352
|
-
return
|
|
361
|
+
return;
|
|
353
362
|
}
|
|
354
363
|
const cfg = fromMapping.byTag[tag];
|
|
355
364
|
if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
|
|
@@ -382,6 +391,7 @@ const sharedProviders = [
|
|
|
382
391
|
useClass: ChildAppResolutionConfigManager,
|
|
383
392
|
deps: {
|
|
384
393
|
configs: { token: CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
|
|
394
|
+
logger: LOGGER_TOKEN,
|
|
385
395
|
},
|
|
386
396
|
}),
|
|
387
397
|
provide({
|
|
@@ -398,8 +408,9 @@ const sharedProviders = [
|
|
|
398
408
|
}),
|
|
399
409
|
provide({
|
|
400
410
|
provide: CHILD_APP_RESOLVE_CONFIG_TOKEN,
|
|
401
|
-
useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
|
|
411
|
+
useFactory: ({ envManager, logger, rootBaseUrl, resolutionConfigManager }) => {
|
|
402
412
|
const rawEnv = envManager.get('CHILD_APP_DEBUG');
|
|
413
|
+
const log = logger('child-app:resolve-config');
|
|
403
414
|
const debug = new Map();
|
|
404
415
|
rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
|
|
405
416
|
const [name, url] = entry.split('=');
|
|
@@ -411,7 +422,8 @@ const sharedProviders = [
|
|
|
411
422
|
const req = { name, tag, version: request.version };
|
|
412
423
|
const config = resolutionConfigManager.resolve(req);
|
|
413
424
|
if (!config) {
|
|
414
|
-
|
|
425
|
+
log.error(`Child-app "${name}" with tag "${tag}" has not found`);
|
|
426
|
+
return;
|
|
415
427
|
}
|
|
416
428
|
const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
|
|
417
429
|
const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
|
|
@@ -443,6 +455,7 @@ const sharedProviders = [
|
|
|
443
455
|
},
|
|
444
456
|
deps: {
|
|
445
457
|
envManager: ENV_MANAGER_TOKEN,
|
|
458
|
+
logger: LOGGER_TOKEN,
|
|
446
459
|
rootBaseUrl: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
|
|
447
460
|
resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
|
|
448
461
|
},
|
|
@@ -640,6 +653,9 @@ class PreloadManager {
|
|
|
640
653
|
async preload(request) {
|
|
641
654
|
await this.resolutionConfigManager.init();
|
|
642
655
|
const config = this.resolveFullConfig(request);
|
|
656
|
+
if (!config) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
643
659
|
const { key } = config;
|
|
644
660
|
if (this.map.has(key)) {
|
|
645
661
|
await this.map.get(key);
|
|
@@ -664,8 +680,7 @@ class PreloadManager {
|
|
|
664
680
|
}
|
|
665
681
|
isPreloaded(request) {
|
|
666
682
|
const config = this.resolveFullConfig(request);
|
|
667
|
-
|
|
668
|
-
return this.map.has(key);
|
|
683
|
+
return !!config && this.map.has(config.key);
|
|
669
684
|
}
|
|
670
685
|
async runPreloaded() {
|
|
671
686
|
this.shouldRunImmediately = true;
|
|
@@ -748,7 +763,6 @@ class StateManager {
|
|
|
748
763
|
class RenderManager {
|
|
749
764
|
constructor({ logger, preloadManager, diManager, resolveFullConfig, }) {
|
|
750
765
|
this.hasRenderedSet = new Set();
|
|
751
|
-
this.loadingInProgress = new Map();
|
|
752
766
|
this.log = logger('child-app:render');
|
|
753
767
|
this.preloadManager = preloadManager;
|
|
754
768
|
this.diManager = diManager;
|
|
@@ -756,37 +770,24 @@ class RenderManager {
|
|
|
756
770
|
}
|
|
757
771
|
getChildDi(request) {
|
|
758
772
|
const config = this.resolveFullConfig(request);
|
|
773
|
+
if (!config) {
|
|
774
|
+
throw new Error(`Child app "${request.name}" not found`);
|
|
775
|
+
}
|
|
759
776
|
this.hasRenderedSet.add(config.key);
|
|
760
777
|
if (this.preloadManager.isPreloaded(request)) {
|
|
761
|
-
return [this.diManager.getChildDi(config),
|
|
778
|
+
return [this.diManager.getChildDi(config), undefined];
|
|
762
779
|
}
|
|
763
780
|
this.log.warn({
|
|
764
781
|
message: 'Child-app has been used but not preloaded before React render',
|
|
765
782
|
request,
|
|
766
783
|
});
|
|
767
|
-
|
|
768
|
-
const promiseDi = this.preloadManager.preload(request).then(() => {
|
|
769
|
-
return this.diManager.getChildDi(config);
|
|
770
|
-
});
|
|
771
|
-
return [null, promiseDi];
|
|
772
|
-
}
|
|
773
|
-
async flush() {
|
|
774
|
-
const promises = [];
|
|
775
|
-
for (const [_, request] of this.loadingInProgress.entries()) {
|
|
776
|
-
promises.push(this.preloadManager.preload(request));
|
|
777
|
-
}
|
|
778
|
-
this.loadingInProgress.clear();
|
|
779
|
-
if (promises.length) {
|
|
780
|
-
await Promise.all(promises);
|
|
781
|
-
return true;
|
|
782
|
-
}
|
|
783
|
-
return false;
|
|
784
|
+
return [undefined, undefined];
|
|
784
785
|
}
|
|
785
786
|
clear() {
|
|
786
787
|
const preloadedList = this.preloadManager.getPreloadedList();
|
|
787
788
|
for (const request of preloadedList) {
|
|
788
789
|
const config = this.resolveFullConfig(request);
|
|
789
|
-
if (!this.hasRenderedSet.has(config.key)) {
|
|
790
|
+
if (!config || !this.hasRenderedSet.has(config.key)) {
|
|
790
791
|
this.log.warn({
|
|
791
792
|
message: 'Child-app has been preloaded but not used in React render',
|
|
792
793
|
request,
|
|
@@ -801,7 +802,11 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
|
|
|
801
802
|
const log = logger('child-app:render:slots');
|
|
802
803
|
const result = [];
|
|
803
804
|
preloadManager.getPreloadedList().forEach((requestConfig) => {
|
|
805
|
+
var _a;
|
|
804
806
|
const config = resolveFullConfig(requestConfig);
|
|
807
|
+
if (!config) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
805
810
|
const di = diManager.getChildDi(config);
|
|
806
811
|
result.push({
|
|
807
812
|
type: ResourceType.script,
|
|
@@ -815,7 +820,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
|
|
|
815
820
|
result.push({
|
|
816
821
|
type: ResourceType.style,
|
|
817
822
|
slot: ResourceSlot.HEAD_CORE_STYLES,
|
|
818
|
-
payload: config.css.entry,
|
|
823
|
+
payload: (_a = config.css.entry) !== null && _a !== void 0 ? _a : null,
|
|
819
824
|
attrs: {
|
|
820
825
|
'data-critical': 'true',
|
|
821
826
|
},
|
|
@@ -957,7 +962,9 @@ const serverProviders = [
|
|
|
957
962
|
}),
|
|
958
963
|
];
|
|
959
964
|
|
|
960
|
-
const FailedChildAppFallback = ({ name, version, tag,
|
|
965
|
+
const FailedChildAppFallback = ({ name, version, tag, fallback: Fallback, }) => {
|
|
966
|
+
const logger = useDi(LOGGER_TOKEN);
|
|
967
|
+
const log = logger('child-app:render');
|
|
961
968
|
// On client-side hydration errors will be handled in `hydrateRoot` `onRecoverableError` property,
|
|
962
969
|
// and update errors will be handled in Error Boundaries.
|
|
963
970
|
//
|
|
@@ -967,7 +974,7 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
967
974
|
// On server-side, we still use `renderToString`,
|
|
968
975
|
// and need to manually log render errors for components, wrapped in Suspense Boundaries.
|
|
969
976
|
if (typeof window === 'undefined') {
|
|
970
|
-
|
|
977
|
+
log.error({
|
|
971
978
|
event: 'failed-render',
|
|
972
979
|
message: 'child-app failed to render, will try to recover during hydration',
|
|
973
980
|
name,
|
|
@@ -977,21 +984,29 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
977
984
|
}
|
|
978
985
|
return Fallback ? jsx(Fallback, {}) : null;
|
|
979
986
|
};
|
|
980
|
-
const
|
|
987
|
+
const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
|
|
981
988
|
const renderManager = useContext(RenderContext);
|
|
982
|
-
const resolveExternalConfig = useDi(CHILD_APP_RESOLVE_CONFIG_TOKEN);
|
|
983
989
|
const logger = useDi(LOGGER_TOKEN);
|
|
984
990
|
const log = logger('child-app:render');
|
|
985
|
-
const [maybeDi,
|
|
986
|
-
return renderManager.getChildDi(
|
|
987
|
-
}, [name, version, tag, renderManager
|
|
991
|
+
const [maybeDi, maybePromiseDi] = useMemo(() => {
|
|
992
|
+
return renderManager.getChildDi({ name, version, tag });
|
|
993
|
+
}, [name, version, tag, renderManager]);
|
|
988
994
|
const [di, setDi] = useState(maybeDi);
|
|
995
|
+
const [promiseDi, setPromiseDi] = useState(maybePromiseDi);
|
|
989
996
|
useEffect(() => {
|
|
990
997
|
if (!di && promiseDi) {
|
|
991
998
|
// any errors with loading child-app should be handled in some other place
|
|
992
|
-
promiseDi
|
|
999
|
+
promiseDi
|
|
1000
|
+
.then(setDi)
|
|
1001
|
+
.finally(() => setPromiseDi(undefined))
|
|
1002
|
+
.catch(noop);
|
|
993
1003
|
}
|
|
994
1004
|
}, [di, promiseDi]);
|
|
1005
|
+
if (!di && promiseDi) {
|
|
1006
|
+
// in case child-app was not rendered on ssr
|
|
1007
|
+
// and we have to wait before it's loading
|
|
1008
|
+
return Fallback ? jsx(Fallback, {}) : null;
|
|
1009
|
+
}
|
|
995
1010
|
if (!di) {
|
|
996
1011
|
log.error({
|
|
997
1012
|
event: 'not-found',
|
|
@@ -1000,7 +1015,10 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
1000
1015
|
tag,
|
|
1001
1016
|
message: 'child-app was not initialized',
|
|
1002
1017
|
});
|
|
1003
|
-
|
|
1018
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES || typeof window !== 'undefined') {
|
|
1019
|
+
throw new Error(`Child-app was not initialized, check the loading error for child-app "${name}"`);
|
|
1020
|
+
}
|
|
1021
|
+
return Fallback ? jsx(Fallback, {}) : null;
|
|
1004
1022
|
}
|
|
1005
1023
|
try {
|
|
1006
1024
|
const Cmp = di.get({ token: CHILD_APP_INTERNAL_RENDER_TOKEN, optional: true });
|
|
@@ -1014,14 +1032,7 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
1014
1032
|
});
|
|
1015
1033
|
return null;
|
|
1016
1034
|
}
|
|
1017
|
-
|
|
1018
|
-
di,
|
|
1019
|
-
props,
|
|
1020
|
-
});
|
|
1021
|
-
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1022
|
-
return (jsx(Suspense, { fallback: jsx(FailedChildAppFallback, { name: name, version: version, tag: tag, logger: log, fallback: fallback }), children: result }));
|
|
1023
|
-
}
|
|
1024
|
-
return result;
|
|
1035
|
+
return jsx(Cmp, { di: di, props: props });
|
|
1025
1036
|
}
|
|
1026
1037
|
catch (error) {
|
|
1027
1038
|
log.error({
|
|
@@ -1034,6 +1045,16 @@ const ChildApp = memo(({ name, version, tag, props, fallback }) => {
|
|
|
1034
1045
|
});
|
|
1035
1046
|
return null;
|
|
1036
1047
|
}
|
|
1048
|
+
};
|
|
1049
|
+
const ChildApp = memo((config) => {
|
|
1050
|
+
const { fallback } = config;
|
|
1051
|
+
const url = useUrl();
|
|
1052
|
+
const result = (jsx(UniversalErrorBoundary, { url: url, fallback: fallback, children: jsx(ChildAppWrapper, { ...config }) }));
|
|
1053
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1054
|
+
const fallbackRender = FailedChildAppFallback(config);
|
|
1055
|
+
return jsx(Suspense, { fallback: fallbackRender, children: result });
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1037
1058
|
});
|
|
1038
1059
|
|
|
1039
1060
|
let ChildAppModule = class ChildAppModule {
|
package/lib/server.js
CHANGED
|
@@ -19,6 +19,7 @@ var envValidators = require('@tinkoff/env-validators');
|
|
|
19
19
|
var safeStrings = require('@tramvai/safe-strings');
|
|
20
20
|
var moduleLoaderServer = require('@tinkoff/module-loader-server');
|
|
21
21
|
var noop = require('@tinkoff/utils/function/noop');
|
|
22
|
+
var moduleRouter = require('@tramvai/module-router');
|
|
22
23
|
|
|
23
24
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
24
25
|
|
|
@@ -101,7 +102,6 @@ class SingletonDiManager {
|
|
|
101
102
|
error,
|
|
102
103
|
config,
|
|
103
104
|
});
|
|
104
|
-
return null;
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
forEachChildDi(cb) {
|
|
@@ -170,7 +170,7 @@ const getChildProviders = (appDi) => {
|
|
|
170
170
|
dispatcher,
|
|
171
171
|
// context will be set later by the CONTEXT_TOKEN
|
|
172
172
|
context: {},
|
|
173
|
-
initialState,
|
|
173
|
+
initialState: initialState !== null && initialState !== void 0 ? initialState : { stores: [] },
|
|
174
174
|
middlewares: flatten__default["default"](middlewares || []),
|
|
175
175
|
parentDispatcherContext,
|
|
176
176
|
parentAllowedStores: flatten__default["default"](parentAllowedStores || []),
|
|
@@ -231,7 +231,7 @@ class DiManager {
|
|
|
231
231
|
|
|
232
232
|
class CommandLineRunner {
|
|
233
233
|
constructor({ logger, rootCommandLineRunner, diManager, }) {
|
|
234
|
-
this.log = logger('child-app:
|
|
234
|
+
this.log = logger('child-app:command-line-runner');
|
|
235
235
|
this.rootCommandLineRunner = rootCommandLineRunner;
|
|
236
236
|
this.diManager = diManager;
|
|
237
237
|
}
|
|
@@ -331,10 +331,11 @@ const getModuleFederation = async (container, name = 'entry') => {
|
|
|
331
331
|
};
|
|
332
332
|
|
|
333
333
|
class ChildAppResolutionConfigManager {
|
|
334
|
-
constructor({ configs, }) {
|
|
334
|
+
constructor({ configs, logger, }) {
|
|
335
335
|
this.hasInitialized = false;
|
|
336
336
|
this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
|
|
337
337
|
this.mapping = new Map();
|
|
338
|
+
this.log = logger('child-app:resolution-config');
|
|
338
339
|
}
|
|
339
340
|
async init() {
|
|
340
341
|
if (this.hasInitialized) {
|
|
@@ -345,10 +346,18 @@ class ChildAppResolutionConfigManager {
|
|
|
345
346
|
}
|
|
346
347
|
this.initPromise = (async () => {
|
|
347
348
|
const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
|
|
348
|
-
return
|
|
349
|
+
return Promise.resolve()
|
|
350
|
+
.then(() => {
|
|
351
|
+
return applyOrReturn__default["default"]([], rawConfig);
|
|
352
|
+
})
|
|
353
|
+
.catch((error) => {
|
|
354
|
+
this.log.error(error, 'Failed while resolving resolution config');
|
|
355
|
+
});
|
|
349
356
|
}));
|
|
350
357
|
flatten__default["default"](configs).forEach((config) => {
|
|
351
|
-
|
|
358
|
+
if (config) {
|
|
359
|
+
this.mapping.set(config.name, config);
|
|
360
|
+
}
|
|
352
361
|
});
|
|
353
362
|
this.hasInitialized = true;
|
|
354
363
|
})();
|
|
@@ -358,7 +367,7 @@ class ChildAppResolutionConfigManager {
|
|
|
358
367
|
var _a;
|
|
359
368
|
const fromMapping = this.mapping.get(name);
|
|
360
369
|
if (!fromMapping) {
|
|
361
|
-
return
|
|
370
|
+
return;
|
|
362
371
|
}
|
|
363
372
|
const cfg = fromMapping.byTag[tag];
|
|
364
373
|
if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
|
|
@@ -391,6 +400,7 @@ const sharedProviders = [
|
|
|
391
400
|
useClass: ChildAppResolutionConfigManager,
|
|
392
401
|
deps: {
|
|
393
402
|
configs: { token: tokensChildApp.CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
|
|
403
|
+
logger: tokensCommon.LOGGER_TOKEN,
|
|
394
404
|
},
|
|
395
405
|
}),
|
|
396
406
|
core.provide({
|
|
@@ -407,8 +417,9 @@ const sharedProviders = [
|
|
|
407
417
|
}),
|
|
408
418
|
core.provide({
|
|
409
419
|
provide: tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN,
|
|
410
|
-
useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
|
|
420
|
+
useFactory: ({ envManager, logger, rootBaseUrl, resolutionConfigManager }) => {
|
|
411
421
|
const rawEnv = envManager.get('CHILD_APP_DEBUG');
|
|
422
|
+
const log = logger('child-app:resolve-config');
|
|
412
423
|
const debug = new Map();
|
|
413
424
|
rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
|
|
414
425
|
const [name, url] = entry.split('=');
|
|
@@ -420,7 +431,8 @@ const sharedProviders = [
|
|
|
420
431
|
const req = { name, tag, version: request.version };
|
|
421
432
|
const config = resolutionConfigManager.resolve(req);
|
|
422
433
|
if (!config) {
|
|
423
|
-
|
|
434
|
+
log.error(`Child-app "${name}" with tag "${tag}" has not found`);
|
|
435
|
+
return;
|
|
424
436
|
}
|
|
425
437
|
const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
|
|
426
438
|
const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
|
|
@@ -452,6 +464,7 @@ const sharedProviders = [
|
|
|
452
464
|
},
|
|
453
465
|
deps: {
|
|
454
466
|
envManager: tokensCommon.ENV_MANAGER_TOKEN,
|
|
467
|
+
logger: tokensCommon.LOGGER_TOKEN,
|
|
455
468
|
rootBaseUrl: tokensChildApp.CHILD_APP_RESOLVE_BASE_URL_TOKEN,
|
|
456
469
|
resolutionConfigManager: tokensChildApp.CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
|
|
457
470
|
},
|
|
@@ -649,6 +662,9 @@ class PreloadManager {
|
|
|
649
662
|
async preload(request) {
|
|
650
663
|
await this.resolutionConfigManager.init();
|
|
651
664
|
const config = this.resolveFullConfig(request);
|
|
665
|
+
if (!config) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
652
668
|
const { key } = config;
|
|
653
669
|
if (this.map.has(key)) {
|
|
654
670
|
await this.map.get(key);
|
|
@@ -673,8 +689,7 @@ class PreloadManager {
|
|
|
673
689
|
}
|
|
674
690
|
isPreloaded(request) {
|
|
675
691
|
const config = this.resolveFullConfig(request);
|
|
676
|
-
|
|
677
|
-
return this.map.has(key);
|
|
692
|
+
return !!config && this.map.has(config.key);
|
|
678
693
|
}
|
|
679
694
|
async runPreloaded() {
|
|
680
695
|
this.shouldRunImmediately = true;
|
|
@@ -757,7 +772,6 @@ class StateManager {
|
|
|
757
772
|
class RenderManager {
|
|
758
773
|
constructor({ logger, preloadManager, diManager, resolveFullConfig, }) {
|
|
759
774
|
this.hasRenderedSet = new Set();
|
|
760
|
-
this.loadingInProgress = new Map();
|
|
761
775
|
this.log = logger('child-app:render');
|
|
762
776
|
this.preloadManager = preloadManager;
|
|
763
777
|
this.diManager = diManager;
|
|
@@ -765,37 +779,24 @@ class RenderManager {
|
|
|
765
779
|
}
|
|
766
780
|
getChildDi(request) {
|
|
767
781
|
const config = this.resolveFullConfig(request);
|
|
782
|
+
if (!config) {
|
|
783
|
+
throw new Error(`Child app "${request.name}" not found`);
|
|
784
|
+
}
|
|
768
785
|
this.hasRenderedSet.add(config.key);
|
|
769
786
|
if (this.preloadManager.isPreloaded(request)) {
|
|
770
|
-
return [this.diManager.getChildDi(config),
|
|
787
|
+
return [this.diManager.getChildDi(config), undefined];
|
|
771
788
|
}
|
|
772
789
|
this.log.warn({
|
|
773
790
|
message: 'Child-app has been used but not preloaded before React render',
|
|
774
791
|
request,
|
|
775
792
|
});
|
|
776
|
-
|
|
777
|
-
const promiseDi = this.preloadManager.preload(request).then(() => {
|
|
778
|
-
return this.diManager.getChildDi(config);
|
|
779
|
-
});
|
|
780
|
-
return [null, promiseDi];
|
|
781
|
-
}
|
|
782
|
-
async flush() {
|
|
783
|
-
const promises = [];
|
|
784
|
-
for (const [_, request] of this.loadingInProgress.entries()) {
|
|
785
|
-
promises.push(this.preloadManager.preload(request));
|
|
786
|
-
}
|
|
787
|
-
this.loadingInProgress.clear();
|
|
788
|
-
if (promises.length) {
|
|
789
|
-
await Promise.all(promises);
|
|
790
|
-
return true;
|
|
791
|
-
}
|
|
792
|
-
return false;
|
|
793
|
+
return [undefined, undefined];
|
|
793
794
|
}
|
|
794
795
|
clear() {
|
|
795
796
|
const preloadedList = this.preloadManager.getPreloadedList();
|
|
796
797
|
for (const request of preloadedList) {
|
|
797
798
|
const config = this.resolveFullConfig(request);
|
|
798
|
-
if (!this.hasRenderedSet.has(config.key)) {
|
|
799
|
+
if (!config || !this.hasRenderedSet.has(config.key)) {
|
|
799
800
|
this.log.warn({
|
|
800
801
|
message: 'Child-app has been preloaded but not used in React render',
|
|
801
802
|
request,
|
|
@@ -810,7 +811,11 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
|
|
|
810
811
|
const log = logger('child-app:render:slots');
|
|
811
812
|
const result = [];
|
|
812
813
|
preloadManager.getPreloadedList().forEach((requestConfig) => {
|
|
814
|
+
var _a;
|
|
813
815
|
const config = resolveFullConfig(requestConfig);
|
|
816
|
+
if (!config) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
814
819
|
const di = diManager.getChildDi(config);
|
|
815
820
|
result.push({
|
|
816
821
|
type: tokensRender.ResourceType.script,
|
|
@@ -824,7 +829,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
|
|
|
824
829
|
result.push({
|
|
825
830
|
type: tokensRender.ResourceType.style,
|
|
826
831
|
slot: tokensRender.ResourceSlot.HEAD_CORE_STYLES,
|
|
827
|
-
payload: config.css.entry,
|
|
832
|
+
payload: (_a = config.css.entry) !== null && _a !== void 0 ? _a : null,
|
|
828
833
|
attrs: {
|
|
829
834
|
'data-critical': 'true',
|
|
830
835
|
},
|
|
@@ -966,7 +971,9 @@ const serverProviders = [
|
|
|
966
971
|
}),
|
|
967
972
|
];
|
|
968
973
|
|
|
969
|
-
const FailedChildAppFallback = ({ name, version, tag,
|
|
974
|
+
const FailedChildAppFallback = ({ name, version, tag, fallback: Fallback, }) => {
|
|
975
|
+
const logger = react$1.useDi(tokensCommon.LOGGER_TOKEN);
|
|
976
|
+
const log = logger('child-app:render');
|
|
970
977
|
// On client-side hydration errors will be handled in `hydrateRoot` `onRecoverableError` property,
|
|
971
978
|
// and update errors will be handled in Error Boundaries.
|
|
972
979
|
//
|
|
@@ -976,7 +983,7 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
976
983
|
// On server-side, we still use `renderToString`,
|
|
977
984
|
// and need to manually log render errors for components, wrapped in Suspense Boundaries.
|
|
978
985
|
if (typeof window === 'undefined') {
|
|
979
|
-
|
|
986
|
+
log.error({
|
|
980
987
|
event: 'failed-render',
|
|
981
988
|
message: 'child-app failed to render, will try to recover during hydration',
|
|
982
989
|
name,
|
|
@@ -986,21 +993,29 @@ const FailedChildAppFallback = ({ name, version, tag, logger, fallback: Fallback
|
|
|
986
993
|
}
|
|
987
994
|
return Fallback ? jsxRuntime.jsx(Fallback, {}) : null;
|
|
988
995
|
};
|
|
989
|
-
const
|
|
996
|
+
const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
|
|
990
997
|
const renderManager = react.useContext(RenderContext);
|
|
991
|
-
const resolveExternalConfig = react$1.useDi(tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN);
|
|
992
998
|
const logger = react$1.useDi(tokensCommon.LOGGER_TOKEN);
|
|
993
999
|
const log = logger('child-app:render');
|
|
994
|
-
const [maybeDi,
|
|
995
|
-
return renderManager.getChildDi(
|
|
996
|
-
}, [name, version, tag, renderManager
|
|
1000
|
+
const [maybeDi, maybePromiseDi] = react.useMemo(() => {
|
|
1001
|
+
return renderManager.getChildDi({ name, version, tag });
|
|
1002
|
+
}, [name, version, tag, renderManager]);
|
|
997
1003
|
const [di, setDi] = react.useState(maybeDi);
|
|
1004
|
+
const [promiseDi, setPromiseDi] = react.useState(maybePromiseDi);
|
|
998
1005
|
react.useEffect(() => {
|
|
999
1006
|
if (!di && promiseDi) {
|
|
1000
1007
|
// any errors with loading child-app should be handled in some other place
|
|
1001
|
-
promiseDi
|
|
1008
|
+
promiseDi
|
|
1009
|
+
.then(setDi)
|
|
1010
|
+
.finally(() => setPromiseDi(undefined))
|
|
1011
|
+
.catch(noop__default["default"]);
|
|
1002
1012
|
}
|
|
1003
1013
|
}, [di, promiseDi]);
|
|
1014
|
+
if (!di && promiseDi) {
|
|
1015
|
+
// in case child-app was not rendered on ssr
|
|
1016
|
+
// and we have to wait before it's loading
|
|
1017
|
+
return Fallback ? jsxRuntime.jsx(Fallback, {}) : null;
|
|
1018
|
+
}
|
|
1004
1019
|
if (!di) {
|
|
1005
1020
|
log.error({
|
|
1006
1021
|
event: 'not-found',
|
|
@@ -1009,7 +1024,10 @@ const ChildApp = react.memo(({ name, version, tag, props, fallback }) => {
|
|
|
1009
1024
|
tag,
|
|
1010
1025
|
message: 'child-app was not initialized',
|
|
1011
1026
|
});
|
|
1012
|
-
|
|
1027
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES || typeof window !== 'undefined') {
|
|
1028
|
+
throw new Error(`Child-app was not initialized, check the loading error for child-app "${name}"`);
|
|
1029
|
+
}
|
|
1030
|
+
return Fallback ? jsxRuntime.jsx(Fallback, {}) : null;
|
|
1013
1031
|
}
|
|
1014
1032
|
try {
|
|
1015
1033
|
const Cmp = di.get({ token: tokensChildApp.CHILD_APP_INTERNAL_RENDER_TOKEN, optional: true });
|
|
@@ -1023,14 +1041,7 @@ const ChildApp = react.memo(({ name, version, tag, props, fallback }) => {
|
|
|
1023
1041
|
});
|
|
1024
1042
|
return null;
|
|
1025
1043
|
}
|
|
1026
|
-
|
|
1027
|
-
di,
|
|
1028
|
-
props,
|
|
1029
|
-
});
|
|
1030
|
-
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1031
|
-
return (jsxRuntime.jsx(react.Suspense, { fallback: jsxRuntime.jsx(FailedChildAppFallback, { name: name, version: version, tag: tag, logger: log, fallback: fallback }), children: result }));
|
|
1032
|
-
}
|
|
1033
|
-
return result;
|
|
1044
|
+
return jsxRuntime.jsx(Cmp, { di: di, props: props });
|
|
1034
1045
|
}
|
|
1035
1046
|
catch (error) {
|
|
1036
1047
|
log.error({
|
|
@@ -1043,6 +1054,16 @@ const ChildApp = react.memo(({ name, version, tag, props, fallback }) => {
|
|
|
1043
1054
|
});
|
|
1044
1055
|
return null;
|
|
1045
1056
|
}
|
|
1057
|
+
};
|
|
1058
|
+
const ChildApp = react.memo((config) => {
|
|
1059
|
+
const { fallback } = config;
|
|
1060
|
+
const url = moduleRouter.useUrl();
|
|
1061
|
+
const result = (jsxRuntime.jsx(react$1.UniversalErrorBoundary, { url: url, fallback: fallback, children: jsxRuntime.jsx(ChildAppWrapper, { ...config }) }));
|
|
1062
|
+
if (process.env.__TRAMVAI_CONCURRENT_FEATURES) {
|
|
1063
|
+
const fallbackRender = FailedChildAppFallback(config);
|
|
1064
|
+
return jsxRuntime.jsx(react.Suspense, { fallback: fallbackRender, children: result });
|
|
1065
|
+
}
|
|
1066
|
+
return result;
|
|
1046
1067
|
});
|
|
1047
1068
|
|
|
1048
1069
|
exports.ChildAppModule = class ChildAppModule {
|
package/lib/shared/di.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export declare class DiManager implements ChildAppDiManager {
|
|
|
11
11
|
loader: ChildAppLoader;
|
|
12
12
|
singletonDiManager: ChildAppDiManager;
|
|
13
13
|
});
|
|
14
|
-
getChildDi(config: ChildAppFinalConfig): Container | ChildContainer;
|
|
14
|
+
getChildDi(config: ChildAppFinalConfig): Container | ChildContainer | undefined;
|
|
15
15
|
forEachChildDi(cb: (di: Container) => void): void;
|
|
16
16
|
private resolveDi;
|
|
17
17
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ChildAppReactConfig } from '@tramvai/tokens-child-app';
|
|
2
|
-
export declare const ChildApp: import("react").MemoExoticComponent<(
|
|
2
|
+
export declare const ChildApp: import("react").MemoExoticComponent<(config: ChildAppReactConfig) => JSX.Element>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ChildAppRenderManager } from '@tramvai/tokens-child-app';
|
|
2
|
-
export declare const RenderContext: import("react").Context<ChildAppRenderManager>;
|
|
2
|
+
export declare const RenderContext: import("react").Context<ChildAppRenderManager | null>;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { ChildAppRequestConfig, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, ResolutionConfig } from '@tramvai/tokens-child-app';
|
|
2
2
|
import type { ExtractDependencyType, ExtractTokenType } from '@tinkoff/dippy';
|
|
3
|
+
import type { LOGGER_TOKEN } from '@tramvai/tokens-common';
|
|
3
4
|
type Interface = ExtractTokenType<typeof CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN>;
|
|
4
5
|
export declare class ChildAppResolutionConfigManager implements Interface {
|
|
5
6
|
private rawConfigs;
|
|
6
7
|
private mapping;
|
|
8
|
+
private log;
|
|
7
9
|
private hasInitialized;
|
|
8
|
-
private initPromise
|
|
9
|
-
constructor({ configs, }: {
|
|
10
|
+
private initPromise?;
|
|
11
|
+
constructor({ configs, logger, }: {
|
|
10
12
|
configs: ExtractDependencyType<typeof CHILD_APP_RESOLUTION_CONFIGS_TOKEN> | null;
|
|
13
|
+
logger: typeof LOGGER_TOKEN;
|
|
11
14
|
});
|
|
12
15
|
init(): Promise<void>;
|
|
13
|
-
resolve({ name, version, tag }: ChildAppRequestConfig): ResolutionConfig;
|
|
16
|
+
resolve({ name, version, tag }: ChildAppRequestConfig): ResolutionConfig | undefined;
|
|
14
17
|
}
|
|
15
18
|
export {};
|
|
@@ -11,7 +11,7 @@ export declare class SingletonDiManager implements ChildAppDiManager {
|
|
|
11
11
|
appDi: Container;
|
|
12
12
|
loader: ChildAppLoader;
|
|
13
13
|
});
|
|
14
|
-
getChildDi(config: ChildAppFinalConfig): Container;
|
|
14
|
+
getChildDi(config: ChildAppFinalConfig): Container | undefined;
|
|
15
15
|
forEachChildDi(cb: (di: Container) => void): void;
|
|
16
16
|
private resolveDi;
|
|
17
17
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/module-child-app",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.63.0",
|
|
4
4
|
"description": "Module for child apps",
|
|
5
5
|
"browser": {
|
|
6
6
|
"./lib/server.js": "./lib/browser.js",
|
|
@@ -30,21 +30,22 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@tinkoff/env-validators": "0.1.4",
|
|
32
32
|
"@tinkoff/module-loader-client": "0.4.4",
|
|
33
|
-
"@tinkoff/module-loader-server": "0.5.
|
|
34
|
-
"@tramvai/child-app-core": "2.
|
|
33
|
+
"@tinkoff/module-loader-server": "0.5.6",
|
|
34
|
+
"@tramvai/child-app-core": "2.63.0",
|
|
35
|
+
"@tramvai/module-router": "2.63.0",
|
|
35
36
|
"@tramvai/safe-strings": "0.5.6",
|
|
36
|
-
"@tramvai/tokens-child-app": "2.
|
|
37
|
+
"@tramvai/tokens-child-app": "2.63.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {},
|
|
39
40
|
"peerDependencies": {
|
|
40
41
|
"@tinkoff/dippy": "0.8.11",
|
|
41
42
|
"@tinkoff/utils": "^2.1.2",
|
|
42
|
-
"@tramvai/core": "2.
|
|
43
|
-
"@tramvai/state": "2.
|
|
44
|
-
"@tramvai/react": "2.
|
|
45
|
-
"@tramvai/tokens-common": "2.
|
|
46
|
-
"@tramvai/tokens-render": "2.
|
|
47
|
-
"@tramvai/tokens-router": "2.
|
|
43
|
+
"@tramvai/core": "2.63.0",
|
|
44
|
+
"@tramvai/state": "2.63.0",
|
|
45
|
+
"@tramvai/react": "2.63.0",
|
|
46
|
+
"@tramvai/tokens-common": "2.63.0",
|
|
47
|
+
"@tramvai/tokens-render": "2.63.0",
|
|
48
|
+
"@tramvai/tokens-router": "2.63.0",
|
|
48
49
|
"react": ">=16.14.0",
|
|
49
50
|
"react-dom": ">=16.14.0",
|
|
50
51
|
"object-assign": "^4.1.1",
|