@tramvai/module-child-app 1.46.5

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.
@@ -0,0 +1,793 @@
1
+ import { __decorate } from 'tslib';
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
+ 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';
6
+ 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 } from '@tramvai/tokens-common';
8
+ import { RENDER_SLOTS, EXTEND_RENDER } from '@tramvai/tokens-render';
9
+ import { Subscription, createEvent, createReducer } from '@tramvai/state';
10
+ import React, { createContext, useContext, useMemo, useState, useEffect, createElement } from 'react';
11
+ import { loadModule } from '@tinkoff/module-loader-client';
12
+ import noop from '@tinkoff/utils/function/noop';
13
+ import { useDi } from '@tramvai/react';
14
+
15
+ const getChildProviders$1 = (appDi) => {
16
+ const context = appDi.get(CONTEXT_TOKEN);
17
+ return [
18
+ {
19
+ provide: commandLineListTokens.customerStart,
20
+ multi: true,
21
+ useFactory: ({ subscriptions, }) => {
22
+ return async function resolveRootStateForChild() {
23
+ if (!subscriptions) {
24
+ return;
25
+ }
26
+ const state = context.getState();
27
+ return Promise.all(subscriptions.map((sub) => {
28
+ const subscription = new Subscription(sub.stores.map(context.getStore));
29
+ subscription.setOnStateChange(() => {
30
+ sub.listener(context.getState());
31
+ });
32
+ subscription.trySubscribe();
33
+ return sub.listener(state);
34
+ }));
35
+ };
36
+ },
37
+ deps: {
38
+ subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
39
+ },
40
+ },
41
+ provide({
42
+ provide: commandLineListTokens.clear,
43
+ multi: true,
44
+ useFactory: ({ actionRunner, actions }) => {
45
+ return function childAppRunActions() {
46
+ return actionRunner.runActions(flatten(actions));
47
+ };
48
+ },
49
+ deps: {
50
+ actionRunner: ACTION_PAGE_RUNNER_TOKEN,
51
+ actions: CHILD_APP_INTERNAL_ACTION_TOKEN,
52
+ },
53
+ }),
54
+ ];
55
+ };
56
+
57
+ const getChildProviders = (appDi) => {
58
+ const logger = appDi.get(LOGGER_TOKEN);
59
+ return [
60
+ provide({
61
+ provide: LOGGER_TOKEN,
62
+ useValue: Object.assign((opts) => {
63
+ return logger('child-app').child(opts);
64
+ }, logger),
65
+ }),
66
+ provide({
67
+ provide: RENDER_SLOTS,
68
+ multi: true,
69
+ useValue: [],
70
+ }),
71
+ ...getChildProviders$1(appDi),
72
+ ];
73
+ };
74
+
75
+ const commonModuleStubs = [
76
+ DISPATCHER_TOKEN,
77
+ STORE_TOKEN,
78
+ CONTEXT_TOKEN,
79
+ COMMAND_LINE_RUNNER_TOKEN,
80
+ ].map((provide) => {
81
+ return {
82
+ provide,
83
+ useFactory: () => {
84
+ throw Object.assign(new Error('Pure usage of the token is not allowed inside ChildApp, please add `CommonChildAppModule` from module `@tramvai/module-common` to your ChildApp'), { code: 'E_STUB' });
85
+ },
86
+ };
87
+ });
88
+
89
+ class SingletonDiManager {
90
+ constructor({ logger, appDi, loader, }) {
91
+ this.cache = new Map();
92
+ this.log = logger('child-app:singleton-di-manager');
93
+ this.appDi = appDi;
94
+ this.loader = loader;
95
+ }
96
+ getChildDi(config) {
97
+ const { key, tag } = config;
98
+ if (this.cache.has(key)) {
99
+ return this.cache.get(key);
100
+ }
101
+ try {
102
+ const di = this.resolveDi(config);
103
+ if (di && tag !== 'debug') {
104
+ this.cache.set(key, di);
105
+ }
106
+ return di;
107
+ }
108
+ catch (error) {
109
+ this.log.error({
110
+ event: 'resolve-di-fail',
111
+ error,
112
+ config,
113
+ });
114
+ return null;
115
+ }
116
+ }
117
+ forEachChildDi(cb) {
118
+ this.cache.forEach((di) => {
119
+ cb(di);
120
+ });
121
+ }
122
+ resolveDi(config) {
123
+ const children = this.loader.get(config);
124
+ if (!children) {
125
+ return;
126
+ }
127
+ const di = new Container([
128
+ {
129
+ provide: CHILD_APP_INTERNAL_CONFIG_TOKEN,
130
+ useValue: config,
131
+ },
132
+ {
133
+ provide: IS_CHILD_APP_DI_TOKEN,
134
+ useValue: true,
135
+ },
136
+ ], this.appDi);
137
+ const { modules = [], providers = [], actions = [] } = children;
138
+ const childProviders = getChildProviders(this.appDi);
139
+ childProviders.forEach((provider) => {
140
+ di.register(provider);
141
+ });
142
+ const resolvedModules = walkOfModules(modules);
143
+ resolvedModules.forEach((mod) => {
144
+ const moduleParameters = getModuleParameters(mod);
145
+ moduleParameters.providers.forEach((provider) => {
146
+ di.register(provider);
147
+ });
148
+ });
149
+ providers.forEach((provider) => {
150
+ di.register(provider);
151
+ });
152
+ di.register({
153
+ provide: CHILD_APP_INTERNAL_ACTION_TOKEN,
154
+ multi: true,
155
+ useValue: actions,
156
+ });
157
+ const borrowTokens = di.get({ token: CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, optional: true });
158
+ if (borrowTokens) {
159
+ flatten(borrowTokens).forEach((token) => {
160
+ di.borrowToken(this.appDi, token);
161
+ });
162
+ }
163
+ commonModuleStubs.forEach((stub) => {
164
+ if (!di.has(stub.provide)) {
165
+ di.register(stub);
166
+ }
167
+ });
168
+ return di;
169
+ }
170
+ }
171
+
172
+ class DiManager {
173
+ constructor({ appDi, loader, singletonDiManager, }) {
174
+ this.cache = new Map();
175
+ this.appDi = appDi;
176
+ this.loader = loader;
177
+ this.singletonDiManager = singletonDiManager;
178
+ }
179
+ getChildDi(config) {
180
+ const { key } = config;
181
+ if (this.cache.has(key)) {
182
+ return this.cache.get(key);
183
+ }
184
+ const di = this.resolveDi(config);
185
+ di && this.cache.set(key, di);
186
+ return di;
187
+ }
188
+ forEachChildDi(cb) {
189
+ this.cache.forEach((di) => {
190
+ cb(di);
191
+ });
192
+ }
193
+ resolveDi(config) {
194
+ const children = this.loader.get(config);
195
+ if (!children) {
196
+ return;
197
+ }
198
+ const singletonDi = this.singletonDiManager.getChildDi(config);
199
+ if (!singletonDi) {
200
+ return;
201
+ }
202
+ return new ChildContainer(singletonDi, this.appDi);
203
+ }
204
+ }
205
+
206
+ class CommandLineRunner {
207
+ constructor({ logger, rootCommandLineRunner, diManager, }) {
208
+ this.log = logger('child-app:commandlinerunner');
209
+ this.rootCommandLineRunner = rootCommandLineRunner;
210
+ this.diManager = diManager;
211
+ }
212
+ async run(type, status, config) {
213
+ const di = this.diManager.getChildDi(config);
214
+ if (!di) {
215
+ return;
216
+ }
217
+ try {
218
+ const commandLineRunner = di.get({ token: COMMAND_LINE_RUNNER_TOKEN, optional: true });
219
+ if (commandLineRunner && commandLineRunner !== this.rootCommandLineRunner) {
220
+ // TODO:child-app create independent metrics instance for child apps
221
+ // for now just reuse metrics implementation from root as otherwise it fails after attempt to create metrics instance with the same name
222
+ // @ts-ignore
223
+ commandLineRunner.metricsInstance = this.rootCommandLineRunner.metricsInstance;
224
+ await commandLineRunner.run(type, status, [], di);
225
+ }
226
+ }
227
+ catch (error) {
228
+ if (error.code !== 'E_STUB') {
229
+ this.log.error({
230
+ event: 'run-failed',
231
+ error,
232
+ type,
233
+ status,
234
+ config,
235
+ });
236
+ }
237
+ }
238
+ }
239
+ }
240
+
241
+ const setPreloaded = createEvent('child-app set preloaded');
242
+ const initialState = {
243
+ preloaded: [],
244
+ };
245
+ const ChildAppStore = createReducer('child-app', initialState).on(setPreloaded, (_, preloaded) => {
246
+ return {
247
+ preloaded,
248
+ };
249
+ });
250
+
251
+ const RenderContext = createContext(null);
252
+
253
+ const extendRender = ({ renderManager, }) => {
254
+ return (render) => {
255
+ return React.createElement(RenderContext.Provider, { value: renderManager }, render);
256
+ };
257
+ };
258
+
259
+ const initModuleFederation = async (container, scope = 'default') => {
260
+ if (container) {
261
+ await container.init(__webpack_share_scopes__[scope]);
262
+ return;
263
+ }
264
+ await __webpack_init_sharing__('default');
265
+ // currently module federation has problems with external modules
266
+ // and unfourtanelly react and react-dom are marked as externals in defaults
267
+ // fill sharedScope manually here
268
+ const shareScope = __webpack_share_scopes__[scope];
269
+ if (!shareScope.react) {
270
+ shareScope.react = {
271
+ '*': {
272
+ get: () => () => require('react'),
273
+ from: 'tramvai-mf-fix',
274
+ eager: true,
275
+ loaded: true,
276
+ },
277
+ };
278
+ }
279
+ if (!shareScope['react-dom']) {
280
+ shareScope['react-dom'] = {
281
+ '*': {
282
+ get: () => () => require('react-dom'),
283
+ from: 'tramvai-mf-fix',
284
+ eager: true,
285
+ loaded: true,
286
+ },
287
+ };
288
+ }
289
+ };
290
+ const getModuleFederation = async (container, name = 'entry') => {
291
+ return container.get(name);
292
+ };
293
+
294
+ const sharedProviders = [
295
+ provide({
296
+ provide: COMBINE_REDUCERS,
297
+ multi: true,
298
+ useValue: ChildAppStore,
299
+ }),
300
+ provide({
301
+ provide: commandLineListTokens$1.init,
302
+ multi: true,
303
+ useValue: initModuleFederation,
304
+ }),
305
+ provide({
306
+ provide: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
307
+ useFactory: ({ configs }) => {
308
+ const mapping = flatten(configs !== null && configs !== void 0 ? configs : []).reduce((map, config) => {
309
+ return map.set(config.name, config);
310
+ }, new Map());
311
+ return (({ name, version, tag = 'latest' }) => {
312
+ var _a;
313
+ const fromMapping = mapping.get(name);
314
+ if (!fromMapping) {
315
+ return null;
316
+ }
317
+ const cfg = fromMapping.byTag[tag];
318
+ if (process.env.NODE_ENV === 'development' && tag === 'debug' && !cfg) {
319
+ return {
320
+ baseUrl: 'http://localhost:4040/',
321
+ version: '0.0.0-stub',
322
+ };
323
+ }
324
+ return {
325
+ ...cfg,
326
+ baseUrl: (_a = cfg.baseUrl) !== null && _a !== void 0 ? _a : fromMapping.baseUrl,
327
+ version: version !== null && version !== void 0 ? version : cfg.version,
328
+ };
329
+ });
330
+ },
331
+ deps: {
332
+ configs: { token: CHILD_APP_RESOLUTION_CONFIGS_TOKEN, optional: true },
333
+ },
334
+ }),
335
+ provide({
336
+ provide: CHILD_APP_RESOLVE_CONFIG_TOKEN,
337
+ useFactory: ({ envManager, rootBaseUrl, getResolutionConfig }) => {
338
+ const rawEnv = envManager.get('CHILD_APP_DEBUG');
339
+ const debug = new Map();
340
+ rawEnv === null || rawEnv === void 0 ? void 0 : rawEnv.split(';').reduce((acc, entry) => {
341
+ const [name, url] = entry.split('=');
342
+ return acc.set(name, url);
343
+ }, debug);
344
+ return (request) => {
345
+ var _a, _b;
346
+ const { name, tag = debug.has(name) ? 'debug' : 'latest' } = request;
347
+ const req = { name, tag, version: request.version };
348
+ const config = getResolutionConfig(req);
349
+ const { version, baseUrl: configBaseUrl, client, server, css, withoutCss } = config;
350
+ const baseUrl = (_b = (_a = debug.get(name)) !== null && _a !== void 0 ? _a : configBaseUrl) !== null && _b !== void 0 ? _b : rootBaseUrl;
351
+ if (!baseUrl) {
352
+ throw new Error('CHILD_APP_EXTERNAL_URL was not defined');
353
+ }
354
+ return {
355
+ name,
356
+ tag,
357
+ version,
358
+ key: `${name}@${version}`,
359
+ server: {
360
+ entry: `${baseUrl}${name}/${name}_server@${version}.js`,
361
+ ...server,
362
+ },
363
+ client: {
364
+ baseUrl: `${baseUrl}${name}/`,
365
+ entry: `${baseUrl}${name}/${name}_client@${version}.js`,
366
+ ...client,
367
+ },
368
+ css: withoutCss
369
+ ? undefined
370
+ : {
371
+ entry: `${baseUrl}${name}/${name}@${version}.css`,
372
+ ...css,
373
+ },
374
+ };
375
+ };
376
+ },
377
+ deps: {
378
+ envManager: ENV_MANAGER_TOKEN,
379
+ rootBaseUrl: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
380
+ getResolutionConfig: CHILD_APP_GET_RESOLUTION_CONFIG_TOKEN,
381
+ },
382
+ }),
383
+ provide({
384
+ provide: CHILD_APP_RESOLVE_BASE_URL_TOKEN,
385
+ useFactory: ({ envManager }) => {
386
+ return envManager.get('CHILD_APP_EXTERNAL_URL');
387
+ },
388
+ deps: {
389
+ envManager: ENV_MANAGER_TOKEN,
390
+ },
391
+ }),
392
+ provide({
393
+ provide: CHILD_APP_SINGLETON_DI_MANAGER_TOKEN,
394
+ scope: Scope.SINGLETON,
395
+ useClass: SingletonDiManager,
396
+ deps: {
397
+ logger: LOGGER_TOKEN,
398
+ appDi: DI_TOKEN,
399
+ loader: CHILD_APP_LOADER_TOKEN,
400
+ },
401
+ }),
402
+ provide({
403
+ provide: CHILD_APP_DI_MANAGER_TOKEN,
404
+ useClass: DiManager,
405
+ deps: {
406
+ appDi: DI_TOKEN,
407
+ loader: CHILD_APP_LOADER_TOKEN,
408
+ singletonDiManager: CHILD_APP_SINGLETON_DI_MANAGER_TOKEN,
409
+ },
410
+ }),
411
+ provide({
412
+ provide: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
413
+ useClass: CommandLineRunner,
414
+ deps: {
415
+ logger: LOGGER_TOKEN,
416
+ rootCommandLineRunner: COMMAND_LINE_RUNNER_TOKEN,
417
+ diManager: CHILD_APP_DI_MANAGER_TOKEN,
418
+ },
419
+ }),
420
+ provide({
421
+ provide: commandLineListTokens$1.clear,
422
+ multi: true,
423
+ useFactory: ({ preloader }) => {
424
+ return function childAppClear() {
425
+ return preloader.clearPreloaded();
426
+ };
427
+ },
428
+ deps: {
429
+ preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
430
+ },
431
+ }),
432
+ provide({
433
+ provide: REGISTER_CLEAR_CACHE_TOKEN,
434
+ multi: true,
435
+ useFactory: ({ diManager }) => {
436
+ return (type) => {
437
+ diManager.forEachChildDi((di) => {
438
+ var _a;
439
+ const clearCache = di.get({ token: CLEAR_CACHE_TOKEN, optional: true });
440
+ if (clearCache) {
441
+ // first if child-app has its own CLEAR_CACHE_TOKEN implementation use only it
442
+ return clearCache(type);
443
+ }
444
+ // otherwise pick up any REGISTER_CLEAR_CACHE_TOKEN hooks and call it
445
+ const registeredClearCache = (_a = di.get({
446
+ token: REGISTER_CLEAR_CACHE_TOKEN,
447
+ optional: true,
448
+ })) !== null && _a !== void 0 ? _a : [];
449
+ return Promise.all(registeredClearCache.map((clear) => clear(type)));
450
+ });
451
+ };
452
+ },
453
+ deps: {
454
+ diManager: CHILD_APP_SINGLETON_DI_MANAGER_TOKEN,
455
+ },
456
+ }),
457
+ provide({
458
+ provide: EXTEND_RENDER,
459
+ multi: true,
460
+ useFactory: extendRender,
461
+ deps: {
462
+ renderManager: CHILD_APP_RENDER_MANAGER_TOKEN,
463
+ },
464
+ }),
465
+ provide({
466
+ provide: ENV_USED_TOKEN,
467
+ multi: true,
468
+ useValue: [
469
+ {
470
+ key: 'CHILD_APP_DEBUG',
471
+ dehydrate: true,
472
+ optional: true,
473
+ },
474
+ ],
475
+ }),
476
+ ];
477
+
478
+ class Loader {
479
+ resolve(entry) {
480
+ return entry.default;
481
+ }
482
+ }
483
+
484
+ const getModuleFromGlobal = (entry) => {
485
+ return window[`child-app__${entry}`];
486
+ };
487
+ class BrowserLoader extends Loader {
488
+ constructor({ logger }) {
489
+ super();
490
+ this.initializedMap = new WeakMap();
491
+ this.log = logger('child-app:loader');
492
+ }
493
+ async load(config) {
494
+ const moduleName = config.name;
495
+ const childApp = await this.get(config);
496
+ if (childApp) {
497
+ this.log.debug({
498
+ event: 'load-cache',
499
+ moduleName,
500
+ });
501
+ return childApp;
502
+ }
503
+ let container = getModuleFromGlobal(config.client.entry);
504
+ if (!container) {
505
+ this.log.debug({
506
+ event: 'load-fetch',
507
+ moduleName,
508
+ });
509
+ await loadModule(config.client.entry);
510
+ container = getModuleFromGlobal(config.client.entry);
511
+ if (container) {
512
+ this.log.debug({
513
+ event: 'load-success',
514
+ moduleName,
515
+ });
516
+ await this.init(config);
517
+ return this.get(config);
518
+ }
519
+ }
520
+ this.log.error({
521
+ event: 'load-failed',
522
+ moduleName,
523
+ });
524
+ return Promise.reject(new Error(`Error resolving module ${moduleName}`));
525
+ }
526
+ async init(config) {
527
+ const container = getModuleFromGlobal(config.client.entry);
528
+ if (container) {
529
+ await initModuleFederation(container);
530
+ const factory = (await getModuleFederation(container, 'entry'));
531
+ const entry = factory();
532
+ this.initializedMap.set(container, entry);
533
+ }
534
+ }
535
+ get(config) {
536
+ const container = getModuleFromGlobal(config.client.entry);
537
+ const entry = container && this.initializedMap.get(container);
538
+ return entry && this.resolve(entry);
539
+ }
540
+ }
541
+
542
+ class PreloadManager {
543
+ constructor({ loader, runner, resolveExternalConfig, store, }) {
544
+ this.pageHasLoaded = false;
545
+ this.map = new Map();
546
+ this.serverPreloaded = new Map();
547
+ this.preloadMap = new Map();
548
+ this.loader = loader;
549
+ this.runner = runner;
550
+ this.resolveExternalConfig = resolveExternalConfig;
551
+ const { preloaded } = store.getState(ChildAppStore);
552
+ preloaded.forEach((request) => {
553
+ const config = this.resolveExternalConfig(request);
554
+ this.serverPreloaded.set(config.key, config);
555
+ });
556
+ }
557
+ async preload(request) {
558
+ const config = this.resolveExternalConfig(request);
559
+ const { key } = config;
560
+ this.preloadMap.set(key, config);
561
+ if (!this.map.has(key)) {
562
+ if (this.pageHasLoaded) {
563
+ const promise = (async () => {
564
+ try {
565
+ await this.loader.load(config);
566
+ await this.run('customer', config);
567
+ await this.run('clear', config);
568
+ }
569
+ catch (error) { }
570
+ return config;
571
+ })();
572
+ this.map.set(key, promise);
573
+ }
574
+ }
575
+ }
576
+ isPreloaded(request) {
577
+ const config = this.resolveExternalConfig(request);
578
+ const { key } = config;
579
+ return this.map.has(key) || this.serverPreloaded.has(key);
580
+ }
581
+ async runPreloaded() {
582
+ const promises = [];
583
+ if (this.pageHasLoaded) {
584
+ this.map.forEach((childAppPromise) => {
585
+ promises.push((async () => {
586
+ await this.run('spa', await childAppPromise);
587
+ })());
588
+ });
589
+ }
590
+ else {
591
+ this.serverPreloaded.forEach((config) => {
592
+ promises.push((async () => {
593
+ await this.loader.init(config);
594
+ await this.run('customer', config);
595
+ })());
596
+ });
597
+ }
598
+ await Promise.all(promises);
599
+ }
600
+ async clearPreloaded() {
601
+ this.pageHasLoaded = true;
602
+ const promises = [];
603
+ this.preloadMap.forEach((config) => {
604
+ promises.push((async () => {
605
+ if (this.serverPreloaded.has(config.key)) {
606
+ promises.push(this.run('clear', config));
607
+ }
608
+ else {
609
+ const promise = this.loader
610
+ .load(config)
611
+ .catch(noop)
612
+ .then(() => config);
613
+ this.map.set(config.key, promise);
614
+ await promise;
615
+ await this.run('customer', config);
616
+ await this.run('clear', config);
617
+ }
618
+ })());
619
+ });
620
+ this.serverPreloaded.clear();
621
+ await Promise.all(promises);
622
+ }
623
+ getPreloadedList() {
624
+ return [...this.preloadMap.values()];
625
+ }
626
+ async run(status, config) {
627
+ const childApp = this.loader.get(config);
628
+ if (!childApp) {
629
+ return;
630
+ }
631
+ await this.runner.run('client', status, config);
632
+ }
633
+ }
634
+
635
+ class RenderManager {
636
+ constructor({ logger, preloadManager, diManager, resolveExternalConfig, }) {
637
+ this.hasRenderedSet = new Set();
638
+ this.loadingInProgress = new Map();
639
+ this.log = logger('child-app:render');
640
+ this.preloadManager = preloadManager;
641
+ this.diManager = diManager;
642
+ this.resolveExternalConfig = resolveExternalConfig;
643
+ }
644
+ getChildDi(request) {
645
+ const config = this.resolveExternalConfig(request);
646
+ this.hasRenderedSet.add(config.key);
647
+ if (this.preloadManager.isPreloaded(request)) {
648
+ return [this.diManager.getChildDi(config), null];
649
+ }
650
+ this.log.warn({
651
+ message: 'Child-app has been used but not preloaded before React render',
652
+ request,
653
+ });
654
+ this.loadingInProgress.set(config.key, config);
655
+ const promiseDi = this.preloadManager.preload(request).then(() => {
656
+ return this.diManager.getChildDi(config);
657
+ });
658
+ return [null, promiseDi];
659
+ }
660
+ async flush() {
661
+ return false;
662
+ }
663
+ clear() { }
664
+ }
665
+
666
+ const browserProviders = [
667
+ provide({
668
+ provide: CHILD_APP_LOADER_TOKEN,
669
+ useClass: BrowserLoader,
670
+ scope: Scope.SINGLETON,
671
+ deps: {
672
+ logger: LOGGER_TOKEN,
673
+ },
674
+ }),
675
+ provide({
676
+ provide: CHILD_APP_PRELOAD_MANAGER_TOKEN,
677
+ useClass: PreloadManager,
678
+ deps: {
679
+ loader: CHILD_APP_LOADER_TOKEN,
680
+ runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
681
+ resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
682
+ store: STORE_TOKEN,
683
+ },
684
+ }),
685
+ provide({
686
+ provide: CHILD_APP_COMMON_INITIAL_STATE_TOKEN,
687
+ useFactory: () => JSON.parse(window.childAppInitialState || '{}'),
688
+ }),
689
+ provide({
690
+ provide: CHILD_APP_RENDER_MANAGER_TOKEN,
691
+ useClass: RenderManager,
692
+ deps: {
693
+ logger: LOGGER_TOKEN,
694
+ diManager: CHILD_APP_DI_MANAGER_TOKEN,
695
+ preloadManager: CHILD_APP_PRELOAD_MANAGER_TOKEN,
696
+ resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
697
+ },
698
+ }),
699
+ provide({
700
+ provide: commandLineListTokens$1.resolvePageDeps,
701
+ multi: true,
702
+ useFactory: ({ preloader }) => {
703
+ let hasCalled = false;
704
+ return function childAppRunPreloaded() {
705
+ if (hasCalled)
706
+ return;
707
+ hasCalled = true;
708
+ return preloader.runPreloaded();
709
+ };
710
+ },
711
+ deps: {
712
+ preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
713
+ },
714
+ }),
715
+ provide({
716
+ provide: commandLineListTokens$1.spaTransition,
717
+ multi: true,
718
+ useFactory: ({ preloader }) => {
719
+ return function childAppRunPreloaded() {
720
+ return preloader.runPreloaded();
721
+ };
722
+ },
723
+ deps: {
724
+ preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
725
+ },
726
+ }),
727
+ ];
728
+
729
+ const ChildApp = ({ name, version, tag, props }) => {
730
+ const renderManager = useContext(RenderContext);
731
+ const resolveExternalConfig = useDi(CHILD_APP_RESOLVE_CONFIG_TOKEN);
732
+ const logger = useDi(LOGGER_TOKEN);
733
+ const log = logger('child-app:render');
734
+ const [maybeDi, promiseDi] = useMemo(() => {
735
+ return renderManager.getChildDi(resolveExternalConfig({ name, version, tag }));
736
+ }, [name, version, tag, renderManager, resolveExternalConfig]);
737
+ const [di, setDi] = useState(maybeDi);
738
+ useEffect(() => {
739
+ if (!di && promiseDi) {
740
+ // any errors with loading child-app should be handled in some other place
741
+ promiseDi.then(setDi).catch(noop);
742
+ }
743
+ }, [di, promiseDi]);
744
+ if (!di) {
745
+ log.error({
746
+ event: 'not-found',
747
+ name,
748
+ version,
749
+ tag,
750
+ message: 'child-app was not initialized',
751
+ });
752
+ return null;
753
+ }
754
+ try {
755
+ const Cmp = di.get({ token: CHILD_APP_INTERNAL_RENDER_TOKEN, optional: true });
756
+ if (!Cmp) {
757
+ log.error({
758
+ event: 'empty-render',
759
+ message: 'Child-app does not provide render token',
760
+ name,
761
+ version,
762
+ tag,
763
+ });
764
+ return null;
765
+ }
766
+ return createElement(Cmp, {
767
+ di,
768
+ props,
769
+ });
770
+ }
771
+ catch (error) {
772
+ log.error({
773
+ event: 'get-render',
774
+ message: 'Cannot get render token from child-app',
775
+ error,
776
+ name,
777
+ version,
778
+ tag,
779
+ });
780
+ return null;
781
+ }
782
+ };
783
+
784
+ let ChildAppModule = class ChildAppModule {
785
+ };
786
+ ChildAppModule = __decorate([
787
+ Module({
788
+ imports: [],
789
+ providers: [...sharedProviders, ...browserProviders],
790
+ })
791
+ ], ChildAppModule);
792
+
793
+ export { ChildApp, ChildAppModule };