@tramvai/module-child-app 1.65.0 → 1.67.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 CHANGED
@@ -129,14 +129,70 @@ State for child-apps will be dehydrated on server as separate variable in the re
129
129
 
130
130
  Usually child-app cannot read data from root-app stores, but the dangerous workaround that allows to subscribe on any root-app store exists.
131
131
 
132
- It may be done using `CHILD_APP_ROOT_STATE_SUBSCRIPTION_TOKEN` token.
132
+ It may be done using `CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN` token.
133
133
 
134
- This token is considered dangerous as it leads to high coupling with stores from root-app and this way stores in root-app might not change their public interface. But, in most cases, changes in stores ignore breaking change tracking and often breaks backward-compatibility. So **do not use this token if you can**, and if you should - use as little as possible from root-app and provide some fallback in case of wrong data.
134
+ This token is considered dangerous as it leads to high coupling with stores from root-app and this way stores in root-app might not change their public interface. But, in most cases, changes in stores ignore breaking change tracking and often breaks backward-compatibility. So **do not use this token if you can**, and if you should - use as little as possible from root-app and provide some fallback in case of wrong data.
135
+
136
+ [See how to do it](#child_app_internal_root_state_subscription_token)
135
137
 
136
138
  :::
137
139
 
138
140
  ## API
139
141
 
142
+ ### CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN
143
+
144
+ Allows to subscribe to any store from the root app and execute actions based on its state, e.g. to fill internal child-app state.
145
+
146
+ 1. Create a new store and a new event within child-app. This store might be used inside child-app as usual store.
147
+
148
+ ```ts
149
+ import { createReducer, createEvent } from '@tramvai/state';
150
+
151
+ interface State {
152
+ value: string;
153
+ }
154
+ export const setRootState = createEvent<string>('child-root set state');
155
+
156
+ export const rootStore = createReducer('child-root', { value: 'child' } as State).on(
157
+ setRootState,
158
+ (state, value) => {
159
+ return { value };
160
+ }
161
+ );
162
+ ```
163
+
164
+ 2. Add provider for the `CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN` in order to subscribe to store. In subscription you can dispatch internal event from the child-app
165
+
166
+ ```ts
167
+ provide({
168
+ provide: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN,
169
+ multi: true,
170
+ useFactory: ({ context }) => {
171
+ return {
172
+ stores: ['root'],
173
+ listener: (state: Record<string, any>) => {
174
+ return context.dispatch(setRootState(`root ${state.root.value}`));
175
+ },
176
+ };
177
+ },
178
+ deps: {
179
+ context: CONTEXT_TOKEN,
180
+ },
181
+ });
182
+ ```
183
+
184
+ 3. Use internal child-app store anywhere in the child-app
185
+
186
+ ```tsx
187
+ export const StateCmp = () => {
188
+ const value = useSelector([rootStore], (state) => {
189
+ return state['child-root'].value;
190
+ });
191
+
192
+ return <div id="child-state">Current Value from Root Store: {value}</div>;
193
+ };
194
+ ```
195
+
140
196
  ## How to
141
197
 
142
198
  ### Connect a child app
@@ -1,3 +1,3 @@
1
1
  import type { Container } from '@tinkoff/dippy';
2
2
  import type { Provider } from '@tramvai/core';
3
- export declare const getChildProviders: (appDi: Container) => Provider[];
3
+ export declare const getChildProviders: (_: Container) => Provider[];
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
@@ -1,16 +1,20 @@
1
- import type { ChildAppCommandLineRunner, ChildAppRequestConfig, ChildAppLoader, ChildAppPreloadManager, CHILD_APP_RESOLVE_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
1
+ import type { ChildAppCommandLineRunner, ChildAppRequestConfig, ChildAppLoader, ChildAppPreloadManager, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
2
2
  import type { STORE_TOKEN } from '@tramvai/tokens-common';
3
3
  export declare class PreloadManager implements ChildAppPreloadManager {
4
4
  private loader;
5
5
  private runner;
6
+ private store;
7
+ private resolutionConfigManager;
6
8
  private resolveExternalConfig;
7
9
  private pageHasLoaded;
8
10
  private map;
9
11
  private serverPreloaded;
10
12
  private preloadMap;
11
- constructor({ loader, runner, resolveExternalConfig, store, }: {
13
+ private hasInitialized;
14
+ constructor({ loader, runner, resolutionConfigManager, resolveExternalConfig, store, }: {
12
15
  loader: ChildAppLoader;
13
16
  runner: ChildAppCommandLineRunner;
17
+ resolutionConfigManager: typeof CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN;
14
18
  resolveExternalConfig: typeof CHILD_APP_RESOLVE_CONFIG_TOKEN;
15
19
  store: typeof STORE_TOKEN;
16
20
  });
@@ -19,5 +23,7 @@ export declare class PreloadManager implements ChildAppPreloadManager {
19
23
  runPreloaded(): Promise<void>;
20
24
  clearPreloaded(): Promise<void>;
21
25
  getPreloadedList(): ChildAppRequestConfig[];
26
+ private initServerPreloaded;
27
+ private init;
22
28
  private run;
23
29
  }
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
@@ -1,20 +1,19 @@
1
- import type { ChildAppCommandLineRunner, ChildAppRequestConfig, ChildAppLoader, ChildAppPreloadManager, ChildAppStateManager, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_PRELOAD_EXTERNAL_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
1
+ import type { ChildAppCommandLineRunner, ChildAppRequestConfig, ChildAppLoader, ChildAppPreloadManager, ChildAppStateManager, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
2
2
  export declare class PreloadManager implements ChildAppPreloadManager {
3
3
  private loader;
4
4
  private runner;
5
5
  private stateManager;
6
- private preloadExternalConfig;
6
+ private resolutionConfigManager;
7
7
  private readonly resolveFullConfig;
8
8
  private shouldRunImmediately;
9
9
  private map;
10
10
  private preloadMap;
11
- private configHasBeenPreloaded;
12
- constructor({ loader, runner, stateManager, preloadExternalConfig, resolveFullConfig, }: {
11
+ constructor({ loader, runner, stateManager, resolutionConfigManager, resolveFullConfig, }: {
13
12
  loader: ChildAppLoader;
14
13
  runner: ChildAppCommandLineRunner;
15
14
  stateManager: ChildAppStateManager;
15
+ resolutionConfigManager: typeof CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN;
16
16
  resolveFullConfig: typeof CHILD_APP_RESOLVE_CONFIG_TOKEN;
17
- preloadExternalConfig: typeof CHILD_APP_PRELOAD_EXTERNAL_CONFIG_TOKEN | null;
18
17
  });
19
18
  preload(request: ChildAppRequestConfig): Promise<void>;
20
19
  isPreloaded(request: ChildAppRequestConfig): boolean;
@@ -2,8 +2,9 @@ import type { CUSTOM_RENDER } from '@tramvai/tokens-render';
2
2
  import type { Container } from '@tinkoff/dippy';
3
3
  import type { ChildAppDiManager, ChildAppPreloadManager, ChildAppRenderManager, ChildAppRequestConfig, CHILD_APP_RESOLVE_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
4
4
  import type { LOGGER_TOKEN } from '@tramvai/tokens-common';
5
- export declare const customRender: ({ renderManager, }: {
5
+ export declare const customRender: ({ renderManager, diManager, }: {
6
6
  renderManager: ChildAppRenderManager;
7
+ diManager: ChildAppDiManager;
7
8
  }) => typeof CUSTOM_RENDER;
8
9
  export declare class RenderManager implements ChildAppRenderManager {
9
10
  private readonly preloadManager;
@@ -1,19 +1,20 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { provide, COMMAND_LINE_RUNNER_TOKEN, walkOfModules, getModuleParameters, commandLineListTokens as commandLineListTokens$1, Module } from '@tramvai/core';
3
- import flatten from '@tinkoff/utils/array/flatten';
4
3
  import { Container, ChildContainer, Scope, DI_TOKEN } from '@tinkoff/dippy';
5
- import { commandLineListTokens, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
4
+ import { commandLineListTokens, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
6
5
  export * from '@tramvai/tokens-child-app';
7
6
  import { ACTION_PAGE_RUNNER_TOKEN, CONTEXT_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN } from '@tramvai/tokens-common';
8
7
  import { RENDER_SLOTS, EXTEND_RENDER } from '@tramvai/tokens-render';
9
8
  import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
9
+ import flatten from '@tinkoff/utils/array/flatten';
10
10
  import { Subscription, createEvent, createReducer } from '@tramvai/state';
11
11
  import React, { createContext, useContext, useMemo, useState, useEffect, createElement } from 'react';
12
+ import applyOrReturn from '@tinkoff/utils/function/applyOrReturn';
12
13
  import { loadModule } from '@tinkoff/module-loader-client';
13
14
  import noop from '@tinkoff/utils/function/noop';
14
15
  import { useDi } from '@tramvai/react';
15
16
 
16
- const getChildProviders$1 = (appDi) => {
17
+ const getChildProviders$3 = (appDi) => {
17
18
  const context = appDi.get(CONTEXT_TOKEN);
18
19
  return [
19
20
  {
@@ -55,7 +56,7 @@ const getChildProviders$1 = (appDi) => {
55
56
  ];
56
57
  };
57
58
 
58
- const getChildProviders = (appDi) => {
59
+ const getChildProviders$2 = (appDi) => {
59
60
  const logger = appDi.get(LOGGER_TOKEN);
60
61
  return [
61
62
  provide({
@@ -69,7 +70,7 @@ const getChildProviders = (appDi) => {
69
70
  multi: true,
70
71
  useValue: [],
71
72
  }),
72
- ...getChildProviders$1(appDi),
73
+ ...getChildProviders$3(appDi),
73
74
  ];
74
75
  };
75
76
 
@@ -136,7 +137,7 @@ class SingletonDiManager {
136
137
  },
137
138
  ], this.appDi);
138
139
  const { modules = [], providers = [], actions = [] } = children;
139
- const childProviders = getChildProviders(this.appDi);
140
+ const childProviders = getChildProviders$2(this.appDi);
140
141
  childProviders.forEach((provider) => {
141
142
  di.register(provider);
142
143
  });
@@ -170,6 +171,14 @@ class SingletonDiManager {
170
171
  }
171
172
  }
172
173
 
174
+ const getChildProviders$1 = (_) => {
175
+ return [];
176
+ };
177
+
178
+ const getChildProviders = (appDi) => {
179
+ return getChildProviders$1();
180
+ };
181
+
173
182
  class DiManager {
174
183
  constructor({ appDi, loader, singletonDiManager, }) {
175
184
  this.cache = new Map();
@@ -200,7 +209,12 @@ class DiManager {
200
209
  if (!singletonDi) {
201
210
  return;
202
211
  }
203
- return new ChildContainer(singletonDi, this.appDi);
212
+ const di = new ChildContainer(singletonDi, this.appDi);
213
+ const childProviders = getChildProviders(this.appDi);
214
+ childProviders.forEach((provider) => {
215
+ di.register(provider);
216
+ });
217
+ return di;
204
218
  }
205
219
  }
206
220
 
@@ -298,6 +312,51 @@ const resolveComponent = async (componentOrLoader) => {
298
312
  : componentOrLoader;
299
313
  };
300
314
 
315
+ class ChildAppResolutionConfigManager {
316
+ constructor({ configs }) {
317
+ this.hasInitialized = false;
318
+ this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
319
+ this.mapping = new Map();
320
+ }
321
+ async init() {
322
+ if (this.hasInitialized) {
323
+ return;
324
+ }
325
+ if (this.initPromise) {
326
+ return this.initPromise;
327
+ }
328
+ this.initPromise = (async () => {
329
+ const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
330
+ return applyOrReturn([], rawConfig);
331
+ }));
332
+ flatten(configs).forEach((config) => {
333
+ this.mapping.set(config.name, config);
334
+ });
335
+ this.hasInitialized = true;
336
+ })();
337
+ return this.initPromise;
338
+ }
339
+ resolve({ name, version, tag = 'latest' }) {
340
+ var _a;
341
+ const fromMapping = this.mapping.get(name);
342
+ if (!fromMapping) {
343
+ return null;
344
+ }
345
+ const cfg = fromMapping.byTag[tag];
346
+ if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
347
+ return {
348
+ baseUrl: 'http://localhost:4040/',
349
+ version: '0.0.0-stub',
350
+ };
351
+ }
352
+ return {
353
+ ...cfg,
354
+ baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
355
+ version: version !== null && version !== void 0 ? version : cfg.version,
356
+ };
357
+ }
358
+ }
359
+
301
360
  const sharedProviders = [
302
361
  provide({
303
362
  provide: COMBINE_REDUCERS,
@@ -310,38 +369,27 @@ const sharedProviders = [
310
369
  useValue: initModuleFederation,
311
370
  }),
312
371
  provide({
313
- provide: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
314
- useFactory: ({ configs }) => {
315
- const mapping = flatten(configs !== null && configs !== void 0 ? configs : []).reduce((map, config) => {
316
- return map.set(config.name, config);
317
- }, new Map());
318
- return (({ name, version, tag = 'latest' }) => {
319
- var _a;
320
- const fromMapping = mapping.get(name);
321
- if (!fromMapping) {
322
- return null;
323
- }
324
- const cfg = fromMapping.byTag[tag];
325
- if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
326
- return {
327
- baseUrl: 'http://localhost:4040/',
328
- version: '0.0.0-stub',
329
- };
330
- }
331
- return {
332
- ...cfg,
333
- baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
334
- version: version !== null && version !== void 0 ? version : cfg.version,
335
- };
336
- });
337
- },
372
+ provide: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
373
+ useClass: ChildAppResolutionConfigManager,
338
374
  deps: {
339
375
  configs: { token: CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
340
376
  },
341
377
  }),
378
+ provide({
379
+ provide: commandLineListTokens$1.resolvePageDeps,
380
+ multi: true,
381
+ useFactory: ({ resolutionConfigManager }) => {
382
+ return async function fallbackResolutionConfigManagerInit() {
383
+ await resolutionConfigManager.init();
384
+ };
385
+ },
386
+ deps: {
387
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
388
+ },
389
+ }),
342
390
  provide({
343
391
  provide: CHILD_APP_RESOLVE_CONFIG_TOKEN,
344
- useFactory: ({ envManager, rootBaseUrl, getResolutionConfig }) => {
392
+ useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
345
393
  const rawEnv = envManager.get('CHILD_APP_DEBUG');
346
394
  const debug = new Map();
347
395
  rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
@@ -352,7 +400,10 @@ const sharedProviders = [
352
400
  var _a, _b;
353
401
  const { name, tag = debug.has(name) ? 'debug' : 'latest' } = request;
354
402
  const req = { name, tag, version: request.version };
355
- const config = getResolutionConfig(req);
403
+ const config = resolutionConfigManager.resolve(req);
404
+ if (!config) {
405
+ throw new Error(`Child-app "${name}" with tag "${tag}" has not found`);
406
+ }
356
407
  const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
357
408
  const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
358
409
  if (!baseUrl) {
@@ -384,7 +435,7 @@ const sharedProviders = [
384
435
  deps: {
385
436
  envManager: ENV_MANAGER_TOKEN,
386
437
  rootBaseUrl: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
387
- getResolutionConfig: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
438
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
388
439
  },
389
440
  }),
390
441
  provide({
@@ -568,21 +619,20 @@ class BrowserLoader extends Loader {
568
619
  }
569
620
 
570
621
  class PreloadManager {
571
- constructor({ loader, runner, resolveExternalConfig, store, }) {
622
+ constructor({ loader, runner, resolutionConfigManager, resolveExternalConfig, store, }) {
572
623
  this.pageHasLoaded = false;
573
624
  this.map = new Map();
574
625
  this.serverPreloaded = new Map();
575
626
  this.preloadMap = new Map();
627
+ this.hasInitialized = false;
576
628
  this.loader = loader;
577
629
  this.runner = runner;
630
+ this.store = store;
631
+ this.resolutionConfigManager = resolutionConfigManager;
578
632
  this.resolveExternalConfig = resolveExternalConfig;
579
- const { preloaded } = store.getState(ChildAppStore);
580
- preloaded.forEach((request) => {
581
- const config = this.resolveExternalConfig(request);
582
- this.serverPreloaded.set(config.key, config);
583
- });
584
633
  }
585
634
  async preload(request) {
635
+ await this.init();
586
636
  const config = this.resolveExternalConfig(request);
587
637
  const { key } = config;
588
638
  this.preloadMap.set(key, config);
@@ -607,6 +657,7 @@ class PreloadManager {
607
657
  return this.map.has(key) || this.serverPreloaded.has(key);
608
658
  }
609
659
  async runPreloaded() {
660
+ await this.init();
610
661
  const promises = [];
611
662
  if (this.pageHasLoaded) {
612
663
  this.map.forEach((childAppPromise) => {
@@ -651,6 +702,20 @@ class PreloadManager {
651
702
  getPreloadedList() {
652
703
  return [...this.preloadMap.values()];
653
704
  }
705
+ initServerPreloaded() {
706
+ if (!this.hasInitialized) {
707
+ const { preloaded } = this.store.getState(ChildAppStore);
708
+ preloaded.forEach((request) => {
709
+ const config = this.resolveExternalConfig(request);
710
+ this.serverPreloaded.set(config.key, config);
711
+ });
712
+ this.hasInitialized = true;
713
+ }
714
+ }
715
+ async init() {
716
+ await this.resolutionConfigManager.init();
717
+ this.initServerPreloaded();
718
+ }
654
719
  async run(status, config) {
655
720
  const childApp = this.loader.get(config);
656
721
  if (!childApp) {
@@ -706,6 +771,7 @@ const browserProviders = [
706
771
  deps: {
707
772
  loader: CHILD_APP_LOADER_TOKEN,
708
773
  runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
774
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
709
775
  resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
710
776
  store: STORE_TOKEN,
711
777
  },
@@ -721,6 +787,7 @@ const browserProviders = [
721
787
  logger: LOGGER_TOKEN,
722
788
  diManager: CHILD_APP_DI_MANAGER_TOKEN,
723
789
  preloadManager: CHILD_APP_PRELOAD_MANAGER_TOKEN,
790
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
724
791
  resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
725
792
  },
726
793
  }),
package/lib/server.es.js CHANGED
@@ -1,14 +1,15 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { provide, COMMAND_LINE_RUNNER_TOKEN, walkOfModules, getModuleParameters, commandLineListTokens as commandLineListTokens$1, Module } from '@tramvai/core';
3
- import flatten from '@tinkoff/utils/array/flatten';
4
3
  import { Container, ChildContainer, Scope, DI_TOKEN } from '@tinkoff/dippy';
5
- import { commandLineListTokens, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_PRELOAD_EXTERNAL_CONFIG_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
4
+ import { commandLineListTokens, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
6
5
  export * from '@tramvai/tokens-child-app';
7
- import { ACTION_PAGE_RUNNER_TOKEN, CONTEXT_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
6
+ import { ACTION_PAGE_RUNNER_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, CONTEXT_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
8
7
  import { RENDER_SLOTS, EXTEND_RENDER, ResourceType, ResourceSlot, RESOURCES_REGISTRY, CUSTOM_RENDER } from '@tramvai/tokens-render';
9
8
  import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
9
+ import flatten from '@tinkoff/utils/array/flatten';
10
10
  import { createEvent, createReducer } from '@tramvai/state';
11
11
  import React, { createContext, useContext, useMemo, useState, useEffect, createElement } from 'react';
12
+ import applyOrReturn from '@tinkoff/utils/function/applyOrReturn';
12
13
  import { combineValidators, isUrl, endsWith } from '@tinkoff/env-validators';
13
14
  import { safeDehydrate } from '@tramvai/safe-strings';
14
15
  import { ServerLoader as ServerLoader$1 } from '@tinkoff/module-loader-server';
@@ -16,27 +17,8 @@ import noop from '@tinkoff/utils/function/noop';
16
17
  import { renderToString } from 'react-dom/server';
17
18
  import { useDi } from '@tramvai/react';
18
19
 
19
- const getChildProviders$1 = (appDi) => {
20
- const context = appDi.get(CONTEXT_TOKEN);
20
+ const getChildProviders$3 = (appDi) => {
21
21
  return [
22
- {
23
- provide: commandLineListTokens.customerStart,
24
- multi: true,
25
- useFactory: ({ subscriptions, }) => {
26
- return function resolveRootStateForChild() {
27
- if (!subscriptions) {
28
- return;
29
- }
30
- const state = context.getState();
31
- return Promise.all(subscriptions.map((sub) => {
32
- return sub.listener(state);
33
- }));
34
- };
35
- },
36
- deps: {
37
- subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
38
- },
39
- },
40
22
  provide({
41
23
  provide: commandLineListTokens.resolvePageDeps,
42
24
  multi: true,
@@ -53,7 +35,7 @@ const getChildProviders$1 = (appDi) => {
53
35
  ];
54
36
  };
55
37
 
56
- const getChildProviders = (appDi) => {
38
+ const getChildProviders$2 = (appDi) => {
57
39
  const logger = appDi.get(LOGGER_TOKEN);
58
40
  return [
59
41
  provide({
@@ -67,7 +49,7 @@ const getChildProviders = (appDi) => {
67
49
  multi: true,
68
50
  useValue: [],
69
51
  }),
70
- ...getChildProviders$1(appDi),
52
+ ...getChildProviders$3(),
71
53
  ];
72
54
  };
73
55
 
@@ -134,7 +116,7 @@ class SingletonDiManager {
134
116
  },
135
117
  ], this.appDi);
136
118
  const { modules = [], providers = [], actions = [] } = children;
137
- const childProviders = getChildProviders(this.appDi);
119
+ const childProviders = getChildProviders$2(this.appDi);
138
120
  childProviders.forEach((provider) => {
139
121
  di.register(provider);
140
122
  });
@@ -168,6 +150,34 @@ class SingletonDiManager {
168
150
  }
169
151
  }
170
152
 
153
+ const getChildProviders$1 = (appDi) => {
154
+ const store = appDi.get(STORE_TOKEN);
155
+ return [
156
+ {
157
+ provide: CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN,
158
+ multi: true,
159
+ useFactory: ({ subscriptions, }) => {
160
+ return function resolveRootStateForChild() {
161
+ if (!subscriptions) {
162
+ return;
163
+ }
164
+ const state = store.getState();
165
+ return Promise.all(subscriptions.map((sub) => {
166
+ return sub.listener(state);
167
+ }));
168
+ };
169
+ },
170
+ deps: {
171
+ subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
172
+ },
173
+ },
174
+ ];
175
+ };
176
+
177
+ const getChildProviders = (appDi) => {
178
+ return getChildProviders$1(appDi);
179
+ };
180
+
171
181
  class DiManager {
172
182
  constructor({ appDi, loader, singletonDiManager, }) {
173
183
  this.cache = new Map();
@@ -198,7 +208,12 @@ class DiManager {
198
208
  if (!singletonDi) {
199
209
  return;
200
210
  }
201
- return new ChildContainer(singletonDi, this.appDi);
211
+ const di = new ChildContainer(singletonDi, this.appDi);
212
+ const childProviders = getChildProviders(this.appDi);
213
+ childProviders.forEach((provider) => {
214
+ di.register(provider);
215
+ });
216
+ return di;
202
217
  }
203
218
  }
204
219
 
@@ -296,6 +311,51 @@ const resolveComponent = async (componentOrLoader) => {
296
311
  : componentOrLoader;
297
312
  };
298
313
 
314
+ class ChildAppResolutionConfigManager {
315
+ constructor({ configs }) {
316
+ this.hasInitialized = false;
317
+ this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
318
+ this.mapping = new Map();
319
+ }
320
+ async init() {
321
+ if (this.hasInitialized) {
322
+ return;
323
+ }
324
+ if (this.initPromise) {
325
+ return this.initPromise;
326
+ }
327
+ this.initPromise = (async () => {
328
+ const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
329
+ return applyOrReturn([], rawConfig);
330
+ }));
331
+ flatten(configs).forEach((config) => {
332
+ this.mapping.set(config.name, config);
333
+ });
334
+ this.hasInitialized = true;
335
+ })();
336
+ return this.initPromise;
337
+ }
338
+ resolve({ name, version, tag = 'latest' }) {
339
+ var _a;
340
+ const fromMapping = this.mapping.get(name);
341
+ if (!fromMapping) {
342
+ return null;
343
+ }
344
+ const cfg = fromMapping.byTag[tag];
345
+ if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
346
+ return {
347
+ baseUrl: 'http://localhost:4040/',
348
+ version: '0.0.0-stub',
349
+ };
350
+ }
351
+ return {
352
+ ...cfg,
353
+ baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
354
+ version: version !== null && version !== void 0 ? version : cfg.version,
355
+ };
356
+ }
357
+ }
358
+
299
359
  const sharedProviders = [
300
360
  provide({
301
361
  provide: COMBINE_REDUCERS,
@@ -308,38 +368,27 @@ const sharedProviders = [
308
368
  useValue: initModuleFederation,
309
369
  }),
310
370
  provide({
311
- provide: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
312
- useFactory: ({ configs }) => {
313
- const mapping = flatten(configs !== null && configs !== void 0 ? configs : []).reduce((map, config) => {
314
- return map.set(config.name, config);
315
- }, new Map());
316
- return (({ name, version, tag = 'latest' }) => {
317
- var _a;
318
- const fromMapping = mapping.get(name);
319
- if (!fromMapping) {
320
- return null;
321
- }
322
- const cfg = fromMapping.byTag[tag];
323
- if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
324
- return {
325
- baseUrl: 'http://localhost:4040/',
326
- version: '0.0.0-stub',
327
- };
328
- }
329
- return {
330
- ...cfg,
331
- baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
332
- version: version !== null && version !== void 0 ? version : cfg.version,
333
- };
334
- });
335
- },
371
+ provide: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
372
+ useClass: ChildAppResolutionConfigManager,
336
373
  deps: {
337
374
  configs: { token: CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
338
375
  },
339
376
  }),
377
+ provide({
378
+ provide: commandLineListTokens$1.resolvePageDeps,
379
+ multi: true,
380
+ useFactory: ({ resolutionConfigManager }) => {
381
+ return async function fallbackResolutionConfigManagerInit() {
382
+ await resolutionConfigManager.init();
383
+ };
384
+ },
385
+ deps: {
386
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
387
+ },
388
+ }),
340
389
  provide({
341
390
  provide: CHILD_APP_RESOLVE_CONFIG_TOKEN,
342
- useFactory: ({ envManager, rootBaseUrl, getResolutionConfig }) => {
391
+ useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
343
392
  const rawEnv = envManager.get('CHILD_APP_DEBUG');
344
393
  const debug = new Map();
345
394
  rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
@@ -350,7 +399,10 @@ const sharedProviders = [
350
399
  var _a, _b;
351
400
  const { name, tag = debug.has(name) ? 'debug' : 'latest' } = request;
352
401
  const req = { name, tag, version: request.version };
353
- const config = getResolutionConfig(req);
402
+ const config = resolutionConfigManager.resolve(req);
403
+ if (!config) {
404
+ throw new Error(`Child-app "${name}" with tag "${tag}" has not found`);
405
+ }
354
406
  const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
355
407
  const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
356
408
  if (!baseUrl) {
@@ -382,7 +434,7 @@ const sharedProviders = [
382
434
  deps: {
383
435
  envManager: ENV_MANAGER_TOKEN,
384
436
  rootBaseUrl: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
385
- getResolutionConfig: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
437
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
386
438
  },
387
439
  }),
388
440
  provide({
@@ -551,23 +603,18 @@ class ServerLoader extends Loader {
551
603
  }
552
604
 
553
605
  class PreloadManager {
554
- constructor({ loader, runner, stateManager, preloadExternalConfig, resolveFullConfig, }) {
606
+ constructor({ loader, runner, stateManager, resolutionConfigManager, resolveFullConfig, }) {
555
607
  this.shouldRunImmediately = false;
556
608
  this.map = new Map();
557
609
  this.preloadMap = new Map();
558
- this.configHasBeenPreloaded = false;
559
610
  this.loader = loader;
560
611
  this.runner = runner;
561
612
  this.stateManager = stateManager;
562
- this.preloadExternalConfig = preloadExternalConfig;
613
+ this.resolutionConfigManager = resolutionConfigManager;
563
614
  this.resolveFullConfig = resolveFullConfig;
564
615
  }
565
616
  async preload(request) {
566
- var _a;
567
- if (!this.configHasBeenPreloaded) {
568
- await ((_a = this.preloadExternalConfig) === null || _a === void 0 ? void 0 : _a.call(this));
569
- this.configHasBeenPreloaded = true;
570
- }
617
+ await this.resolutionConfigManager.init();
571
618
  const config = this.resolveFullConfig(request);
572
619
  const { key } = config;
573
620
  if (this.map.has(key)) {
@@ -657,8 +704,16 @@ class StateManager {
657
704
  }
658
705
 
659
706
  const LOAD_TIMEOUT = 500;
660
- const customRender = ({ renderManager, }) => {
707
+ const customRender = ({ renderManager, diManager, }) => {
661
708
  return async (content) => {
709
+ const promises = [];
710
+ diManager.forEachChildDi((di) => {
711
+ const beforeAppRender = di.get(CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN);
712
+ if (beforeAppRender) {
713
+ promises.push(Promise.all(beforeAppRender.map((fn) => fn())));
714
+ }
715
+ });
716
+ await Promise.all(promises);
662
717
  let render = renderToString(content);
663
718
  let timeouted = false;
664
719
  await Promise.race([
@@ -806,7 +861,7 @@ const serverProviders = [
806
861
  loader: CHILD_APP_LOADER_TOKEN,
807
862
  runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
808
863
  stateManager: CHILD_APP_STATE_MANAGER_TOKEN,
809
- preloadExternalConfig: { token: CHILD_APP_PRELOAD_EXTERNAL_CONFIG_TOKEN, optional: true },
864
+ resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
810
865
  resolveFullConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
811
866
  },
812
867
  }),
@@ -843,6 +898,7 @@ const serverProviders = [
843
898
  useFactory: customRender,
844
899
  deps: {
845
900
  renderManager: CHILD_APP_RENDER_MANAGER_TOKEN,
901
+ diManager: CHILD_APP_DI_MANAGER_TOKEN,
846
902
  },
847
903
  }),
848
904
  provide({
package/lib/server.js CHANGED
@@ -4,14 +4,15 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
6
  var core = require('@tramvai/core');
7
- var flatten = require('@tinkoff/utils/array/flatten');
8
7
  var dippy = require('@tinkoff/dippy');
9
8
  var tokensChildApp = require('@tramvai/tokens-child-app');
10
9
  var tokensCommon = require('@tramvai/tokens-common');
11
10
  var tokensRender = require('@tramvai/tokens-render');
12
11
  var tokensRouter = require('@tramvai/tokens-router');
12
+ var flatten = require('@tinkoff/utils/array/flatten');
13
13
  var state = require('@tramvai/state');
14
14
  var React = require('react');
15
+ var applyOrReturn = require('@tinkoff/utils/function/applyOrReturn');
15
16
  var envValidators = require('@tinkoff/env-validators');
16
17
  var safeStrings = require('@tramvai/safe-strings');
17
18
  var moduleLoaderServer = require('@tinkoff/module-loader-server');
@@ -23,29 +24,11 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
23
24
 
24
25
  var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
25
26
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
27
+ var applyOrReturn__default = /*#__PURE__*/_interopDefaultLegacy(applyOrReturn);
26
28
  var noop__default = /*#__PURE__*/_interopDefaultLegacy(noop);
27
29
 
28
- const getChildProviders$1 = (appDi) => {
29
- const context = appDi.get(tokensCommon.CONTEXT_TOKEN);
30
+ const getChildProviders$3 = (appDi) => {
30
31
  return [
31
- {
32
- provide: tokensChildApp.commandLineListTokens.customerStart,
33
- multi: true,
34
- useFactory: ({ subscriptions, }) => {
35
- return function resolveRootStateForChild() {
36
- if (!subscriptions) {
37
- return;
38
- }
39
- const state = context.getState();
40
- return Promise.all(subscriptions.map((sub) => {
41
- return sub.listener(state);
42
- }));
43
- };
44
- },
45
- deps: {
46
- subscriptions: { token: tokensChildApp.CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
47
- },
48
- },
49
32
  core.provide({
50
33
  provide: tokensChildApp.commandLineListTokens.resolvePageDeps,
51
34
  multi: true,
@@ -62,7 +45,7 @@ const getChildProviders$1 = (appDi) => {
62
45
  ];
63
46
  };
64
47
 
65
- const getChildProviders = (appDi) => {
48
+ const getChildProviders$2 = (appDi) => {
66
49
  const logger = appDi.get(tokensCommon.LOGGER_TOKEN);
67
50
  return [
68
51
  core.provide({
@@ -76,7 +59,7 @@ const getChildProviders = (appDi) => {
76
59
  multi: true,
77
60
  useValue: [],
78
61
  }),
79
- ...getChildProviders$1(appDi),
62
+ ...getChildProviders$3(),
80
63
  ];
81
64
  };
82
65
 
@@ -143,7 +126,7 @@ class SingletonDiManager {
143
126
  },
144
127
  ], this.appDi);
145
128
  const { modules = [], providers = [], actions = [] } = children;
146
- const childProviders = getChildProviders(this.appDi);
129
+ const childProviders = getChildProviders$2(this.appDi);
147
130
  childProviders.forEach((provider) => {
148
131
  di.register(provider);
149
132
  });
@@ -177,6 +160,34 @@ class SingletonDiManager {
177
160
  }
178
161
  }
179
162
 
163
+ const getChildProviders$1 = (appDi) => {
164
+ const store = appDi.get(tokensCommon.STORE_TOKEN);
165
+ return [
166
+ {
167
+ provide: tokensChildApp.CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN,
168
+ multi: true,
169
+ useFactory: ({ subscriptions, }) => {
170
+ return function resolveRootStateForChild() {
171
+ if (!subscriptions) {
172
+ return;
173
+ }
174
+ const state = store.getState();
175
+ return Promise.all(subscriptions.map((sub) => {
176
+ return sub.listener(state);
177
+ }));
178
+ };
179
+ },
180
+ deps: {
181
+ subscriptions: { token: tokensChildApp.CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
182
+ },
183
+ },
184
+ ];
185
+ };
186
+
187
+ const getChildProviders = (appDi) => {
188
+ return getChildProviders$1(appDi);
189
+ };
190
+
180
191
  class DiManager {
181
192
  constructor({ appDi, loader, singletonDiManager, }) {
182
193
  this.cache = new Map();
@@ -207,7 +218,12 @@ class DiManager {
207
218
  if (!singletonDi) {
208
219
  return;
209
220
  }
210
- return new dippy.ChildContainer(singletonDi, this.appDi);
221
+ const di = new dippy.ChildContainer(singletonDi, this.appDi);
222
+ const childProviders = getChildProviders(this.appDi);
223
+ childProviders.forEach((provider) => {
224
+ di.register(provider);
225
+ });
226
+ return di;
211
227
  }
212
228
  }
213
229
 
@@ -305,6 +321,51 @@ const resolveComponent = async (componentOrLoader) => {
305
321
  : componentOrLoader;
306
322
  };
307
323
 
324
+ class ChildAppResolutionConfigManager {
325
+ constructor({ configs }) {
326
+ this.hasInitialized = false;
327
+ this.rawConfigs = configs !== null && configs !== void 0 ? configs : [];
328
+ this.mapping = new Map();
329
+ }
330
+ async init() {
331
+ if (this.hasInitialized) {
332
+ return;
333
+ }
334
+ if (this.initPromise) {
335
+ return this.initPromise;
336
+ }
337
+ this.initPromise = (async () => {
338
+ const configs = await Promise.all(this.rawConfigs.map((rawConfig) => {
339
+ return applyOrReturn__default["default"]([], rawConfig);
340
+ }));
341
+ flatten__default["default"](configs).forEach((config) => {
342
+ this.mapping.set(config.name, config);
343
+ });
344
+ this.hasInitialized = true;
345
+ })();
346
+ return this.initPromise;
347
+ }
348
+ resolve({ name, version, tag = 'latest' }) {
349
+ var _a;
350
+ const fromMapping = this.mapping.get(name);
351
+ if (!fromMapping) {
352
+ return null;
353
+ }
354
+ const cfg = fromMapping.byTag[tag];
355
+ if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
356
+ return {
357
+ baseUrl: 'http://localhost:4040/',
358
+ version: '0.0.0-stub',
359
+ };
360
+ }
361
+ return {
362
+ ...cfg,
363
+ baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
364
+ version: version !== null && version !== void 0 ? version : cfg.version,
365
+ };
366
+ }
367
+ }
368
+
308
369
  const sharedProviders = [
309
370
  core.provide({
310
371
  provide: tokensCommon.COMBINE_REDUCERS,
@@ -317,38 +378,27 @@ const sharedProviders = [
317
378
  useValue: initModuleFederation,
318
379
  }),
319
380
  core.provide({
320
- provide: tokensChildApp.CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
321
- useFactory: ({ configs }) => {
322
- const mapping = flatten__default["default"](configs !== null && configs !== void 0 ? configs : []).reduce((map, config) => {
323
- return map.set(config.name, config);
324
- }, new Map());
325
- return (({ name, version, tag = 'latest' }) => {
326
- var _a;
327
- const fromMapping = mapping.get(name);
328
- if (!fromMapping) {
329
- return null;
330
- }
331
- const cfg = fromMapping.byTag[tag];
332
- if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
333
- return {
334
- baseUrl: 'http://localhost:4040/',
335
- version: '0.0.0-stub',
336
- };
337
- }
338
- return {
339
- ...cfg,
340
- baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
341
- version: version !== null && version !== void 0 ? version : cfg.version,
342
- };
343
- });
344
- },
381
+ provide: tokensChildApp.CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
382
+ useClass: ChildAppResolutionConfigManager,
345
383
  deps: {
346
384
  configs: { token: tokensChildApp.CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
347
385
  },
348
386
  }),
387
+ core.provide({
388
+ provide: core.commandLineListTokens.resolvePageDeps,
389
+ multi: true,
390
+ useFactory: ({ resolutionConfigManager }) => {
391
+ return async function fallbackResolutionConfigManagerInit() {
392
+ await resolutionConfigManager.init();
393
+ };
394
+ },
395
+ deps: {
396
+ resolutionConfigManager: tokensChildApp.CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
397
+ },
398
+ }),
349
399
  core.provide({
350
400
  provide: tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN,
351
- useFactory: ({ envManager, rootBaseUrl, getResolutionConfig }) => {
401
+ useFactory: ({ envManager, rootBaseUrl, resolutionConfigManager }) => {
352
402
  const rawEnv = envManager.get('CHILD_APP_DEBUG');
353
403
  const debug = new Map();
354
404
  rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
@@ -359,7 +409,10 @@ const sharedProviders = [
359
409
  var _a, _b;
360
410
  const { name, tag = debug.has(name) ? 'debug' : 'latest' } = request;
361
411
  const req = { name, tag, version: request.version };
362
- const config = getResolutionConfig(req);
412
+ const config = resolutionConfigManager.resolve(req);
413
+ if (!config) {
414
+ throw new Error(`Child-app "${name}" with tag "${tag}" has not found`);
415
+ }
363
416
  const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
364
417
  const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
365
418
  if (!baseUrl) {
@@ -391,7 +444,7 @@ const sharedProviders = [
391
444
  deps: {
392
445
  envManager: tokensCommon.ENV_MANAGER_TOKEN,
393
446
  rootBaseUrl: tokensChildApp.CHILD_APP_RESOLVE_BASE_URL_TOKEN,
394
- getResolutionConfig: tokensChildApp.CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
447
+ resolutionConfigManager: tokensChildApp.CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
395
448
  },
396
449
  }),
397
450
  core.provide({
@@ -560,23 +613,18 @@ class ServerLoader extends Loader {
560
613
  }
561
614
 
562
615
  class PreloadManager {
563
- constructor({ loader, runner, stateManager, preloadExternalConfig, resolveFullConfig, }) {
616
+ constructor({ loader, runner, stateManager, resolutionConfigManager, resolveFullConfig, }) {
564
617
  this.shouldRunImmediately = false;
565
618
  this.map = new Map();
566
619
  this.preloadMap = new Map();
567
- this.configHasBeenPreloaded = false;
568
620
  this.loader = loader;
569
621
  this.runner = runner;
570
622
  this.stateManager = stateManager;
571
- this.preloadExternalConfig = preloadExternalConfig;
623
+ this.resolutionConfigManager = resolutionConfigManager;
572
624
  this.resolveFullConfig = resolveFullConfig;
573
625
  }
574
626
  async preload(request) {
575
- var _a;
576
- if (!this.configHasBeenPreloaded) {
577
- await ((_a = this.preloadExternalConfig) === null || _a === void 0 ? void 0 : _a.call(this));
578
- this.configHasBeenPreloaded = true;
579
- }
627
+ await this.resolutionConfigManager.init();
580
628
  const config = this.resolveFullConfig(request);
581
629
  const { key } = config;
582
630
  if (this.map.has(key)) {
@@ -666,8 +714,16 @@ class StateManager {
666
714
  }
667
715
 
668
716
  const LOAD_TIMEOUT = 500;
669
- const customRender = ({ renderManager, }) => {
717
+ const customRender = ({ renderManager, diManager, }) => {
670
718
  return async (content) => {
719
+ const promises = [];
720
+ diManager.forEachChildDi((di) => {
721
+ const beforeAppRender = di.get(tokensChildApp.CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN);
722
+ if (beforeAppRender) {
723
+ promises.push(Promise.all(beforeAppRender.map((fn) => fn())));
724
+ }
725
+ });
726
+ await Promise.all(promises);
671
727
  let render = server.renderToString(content);
672
728
  let timeouted = false;
673
729
  await Promise.race([
@@ -815,7 +871,7 @@ const serverProviders = [
815
871
  loader: tokensChildApp.CHILD_APP_LOADER_TOKEN,
816
872
  runner: tokensChildApp.CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
817
873
  stateManager: tokensChildApp.CHILD_APP_STATE_MANAGER_TOKEN,
818
- preloadExternalConfig: { token: tokensChildApp.CHILD_APP_PRELOAD_EXTERNAL_CONFIG_TOKEN, optional: true },
874
+ resolutionConfigManager: tokensChildApp.CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
819
875
  resolveFullConfig: tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN,
820
876
  },
821
877
  }),
@@ -852,6 +908,7 @@ const serverProviders = [
852
908
  useFactory: customRender,
853
909
  deps: {
854
910
  renderManager: tokensChildApp.CHILD_APP_RENDER_MANAGER_TOKEN,
911
+ diManager: tokensChildApp.CHILD_APP_DI_MANAGER_TOKEN,
855
912
  },
856
913
  }),
857
914
  core.provide({
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
@@ -0,0 +1,14 @@
1
+ import type { ChildAppRequestConfig, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, ResolutionConfig } from '@tramvai/tokens-child-app';
2
+ declare type Interface = typeof CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN;
3
+ export declare class ChildAppResolutionConfigManager implements Interface {
4
+ private rawConfigs;
5
+ private mapping;
6
+ private hasInitialized;
7
+ private initPromise;
8
+ constructor({ configs }: {
9
+ configs: typeof CHILD_APP_RESOLUTION_CONFIGS_TOKEN | null;
10
+ });
11
+ init(): Promise<void>;
12
+ resolve({ name, version, tag }: ChildAppRequestConfig): ResolutionConfig;
13
+ }
14
+ export {};
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@tramvai/module-child-app",
3
- "version": "1.65.0",
3
+ "version": "1.67.0",
4
4
  "description": "Module for child apps",
5
5
  "browser": {
6
6
  "./lib/server.js": "./lib/browser.js",
7
+ "./lib/server/child/singletonProviders.js": "./lib/browser/child/singletonProviders.js",
7
8
  "./lib/server/child/providers.js": "./lib/browser/child/providers.js",
8
9
  "./lib/server.es.js": "./lib/server.browser.js"
9
10
  },
@@ -30,20 +31,20 @@
30
31
  "@tinkoff/env-validators": "0.0.3",
31
32
  "@tinkoff/module-loader-client": "0.3.25",
32
33
  "@tinkoff/module-loader-server": "0.4.41",
33
- "@tramvai/child-app-core": "1.65.0",
34
+ "@tramvai/child-app-core": "1.67.0",
34
35
  "@tramvai/safe-strings": "0.4.3",
35
- "@tramvai/tokens-child-app": "1.65.0"
36
+ "@tramvai/tokens-child-app": "1.67.0"
36
37
  },
37
38
  "devDependencies": {},
38
39
  "peerDependencies": {
39
40
  "@tinkoff/dippy": "0.7.38",
40
41
  "@tinkoff/utils": "^2.1.2",
41
- "@tramvai/core": "1.65.0",
42
- "@tramvai/state": "1.65.0",
43
- "@tramvai/react": "1.65.0",
44
- "@tramvai/tokens-common": "1.65.0",
45
- "@tramvai/tokens-render": "1.65.0",
46
- "@tramvai/tokens-router": "1.65.0",
42
+ "@tramvai/core": "1.67.0",
43
+ "@tramvai/state": "1.67.0",
44
+ "@tramvai/react": "1.67.0",
45
+ "@tramvai/tokens-common": "1.67.0",
46
+ "@tramvai/tokens-render": "1.67.0",
47
+ "@tramvai/tokens-router": "1.67.0",
47
48
  "react": ">=16.8.0",
48
49
  "react-dom": ">=16.8.0",
49
50
  "object-assign": "^4.1.1",