@tramvai/module-child-app 2.70.0 → 2.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/child/singletonProviders.browser.js +91 -0
- package/lib/browser/loader.browser.js +64 -0
- package/lib/browser/preload.browser.js +115 -0
- package/lib/browser/providers.browser.js +113 -0
- package/lib/browser/render.browser.js +28 -0
- package/lib/browser/runCommand.browser.js +8 -0
- package/lib/browser.browser.js +17 -0
- package/lib/server/child/singletonProviders.es.js +24 -0
- package/lib/server/child/singletonProviders.js +32 -0
- package/lib/server/loader.es.js +48 -0
- package/lib/server/loader.js +52 -0
- package/lib/server/preload.es.js +77 -0
- package/lib/server/preload.js +81 -0
- package/lib/server/providers.es.js +131 -0
- package/lib/server/providers.js +135 -0
- package/lib/server/render-slots.es.js +50 -0
- package/lib/server/render-slots.js +54 -0
- package/lib/server/render.es.js +39 -0
- package/lib/server/render.js +43 -0
- package/lib/server/stateManager.es.js +49 -0
- package/lib/server/stateManager.js +54 -0
- package/lib/server.browser.js +2 -1082
- package/lib/server.es.js +5 -1067
- package/lib/server.js +5 -1072
- package/lib/shared/child/providers.browser.js +36 -0
- package/lib/shared/child/providers.es.js +36 -0
- package/lib/shared/child/providers.js +44 -0
- package/lib/shared/child/singletonProviders.browser.js +24 -0
- package/lib/shared/child/singletonProviders.es.js +24 -0
- package/lib/shared/child/singletonProviders.js +28 -0
- package/lib/shared/child/stubs.browser.js +18 -0
- package/lib/shared/child/stubs.es.js +18 -0
- package/lib/shared/child/stubs.js +22 -0
- package/lib/shared/child/validate.browser.js +11 -0
- package/lib/shared/child/validate.es.js +11 -0
- package/lib/shared/child/validate.js +15 -0
- package/lib/shared/command.browser.js +38 -0
- package/lib/shared/command.es.js +38 -0
- package/lib/shared/command.js +42 -0
- package/lib/shared/constants.browser.js +3 -0
- package/lib/shared/constants.es.js +3 -0
- package/lib/shared/constants.js +7 -0
- package/lib/shared/di.browser.js +44 -0
- package/lib/shared/di.es.js +44 -0
- package/lib/shared/di.js +48 -0
- package/lib/shared/loader.browser.js +7 -0
- package/lib/shared/loader.es.js +7 -0
- package/lib/shared/loader.js +11 -0
- package/lib/shared/providers.browser.js +231 -0
- package/lib/shared/providers.es.js +231 -0
- package/lib/shared/providers.js +235 -0
- package/lib/shared/react/component.browser.js +104 -0
- package/lib/shared/react/component.es.js +104 -0
- package/lib/shared/react/component.js +112 -0
- package/lib/shared/react/render-context.browser.js +5 -0
- package/lib/shared/react/render-context.es.js +5 -0
- package/lib/shared/react/render-context.js +9 -0
- package/lib/shared/render.browser.js +10 -0
- package/lib/shared/render.es.js +10 -0
- package/lib/shared/render.js +14 -0
- package/lib/shared/resolutionConfigManager.browser.js +58 -0
- package/lib/shared/resolutionConfigManager.es.js +58 -0
- package/lib/shared/resolutionConfigManager.js +67 -0
- package/lib/shared/singletonDi.browser.js +95 -0
- package/lib/shared/singletonDi.es.js +95 -0
- package/lib/shared/singletonDi.js +103 -0
- package/lib/shared/store.browser.js +13 -0
- package/lib/shared/store.es.js +13 -0
- package/lib/shared/store.js +18 -0
- package/lib/shared/webpack/moduleFederation.browser.js +49 -0
- package/lib/shared/webpack/moduleFederation.es.js +49 -0
- package/lib/shared/webpack/moduleFederation.js +54 -0
- package/package.json +17 -18
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import noop from '@tinkoff/utils/function/noop';
|
|
2
|
+
import flatten from '@tinkoff/utils/array/flatten';
|
|
3
|
+
import { provide } from '@tramvai/core';
|
|
4
|
+
import { commandLineListTokens, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_INTERNAL_ACTION_TOKEN } from '@tramvai/tokens-child-app';
|
|
5
|
+
import { CONTEXT_TOKEN, ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
|
|
6
|
+
import { Subscription } from '@tramvai/state';
|
|
7
|
+
import { ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN } from '@tramvai/tokens-router';
|
|
8
|
+
|
|
9
|
+
const getChildProviders = (appDi) => {
|
|
10
|
+
const context = appDi.get(CONTEXT_TOKEN);
|
|
11
|
+
return [
|
|
12
|
+
provide({
|
|
13
|
+
provide: commandLineListTokens.customerStart,
|
|
14
|
+
multi: true,
|
|
15
|
+
useFactory: ({ subscriptions }) => {
|
|
16
|
+
return async function resolveRootStateForChild() {
|
|
17
|
+
if (!subscriptions) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const state = context.getState();
|
|
21
|
+
return Promise.all(subscriptions.map((sub) => {
|
|
22
|
+
const subscription = new Subscription(sub.stores.map(context.getStore));
|
|
23
|
+
subscription.setOnStateChange(() => {
|
|
24
|
+
sub.listener(context.getState());
|
|
25
|
+
});
|
|
26
|
+
subscription.trySubscribe();
|
|
27
|
+
return sub.listener(state);
|
|
28
|
+
}));
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
deps: {
|
|
32
|
+
subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
provide({
|
|
36
|
+
provide: commandLineListTokens.clear,
|
|
37
|
+
multi: true,
|
|
38
|
+
useFactory: ({ actionRunner, actions }) => {
|
|
39
|
+
return function childAppRunActions() {
|
|
40
|
+
return actionRunner.runActions(flatten(actions));
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
deps: {
|
|
44
|
+
actionRunner: ACTION_PAGE_RUNNER_TOKEN,
|
|
45
|
+
actions: CHILD_APP_INTERNAL_ACTION_TOKEN,
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
provide({
|
|
49
|
+
provide: commandLineListTokens.spaTransition,
|
|
50
|
+
multi: true,
|
|
51
|
+
useFactory: ({ spaMode, actionRunner, actions }) => {
|
|
52
|
+
if (spaMode !== 'after') {
|
|
53
|
+
return function childAppRunActions() {
|
|
54
|
+
return actionRunner.runActions(flatten(actions));
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return noop;
|
|
58
|
+
},
|
|
59
|
+
deps: {
|
|
60
|
+
actionRunner: ACTION_PAGE_RUNNER_TOKEN,
|
|
61
|
+
actions: CHILD_APP_INTERNAL_ACTION_TOKEN,
|
|
62
|
+
spaMode: {
|
|
63
|
+
token: ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN,
|
|
64
|
+
optional: true,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
provide({
|
|
69
|
+
provide: commandLineListTokens.afterSpaTransition,
|
|
70
|
+
multi: true,
|
|
71
|
+
useFactory: ({ spaMode, actionRunner, actions }) => {
|
|
72
|
+
if (spaMode === 'after') {
|
|
73
|
+
return function childAppRunActions() {
|
|
74
|
+
return actionRunner.runActions(flatten(actions));
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return noop;
|
|
78
|
+
},
|
|
79
|
+
deps: {
|
|
80
|
+
actionRunner: ACTION_PAGE_RUNNER_TOKEN,
|
|
81
|
+
actions: CHILD_APP_INTERNAL_ACTION_TOKEN,
|
|
82
|
+
spaMode: {
|
|
83
|
+
token: ROUTER_SPA_ACTIONS_RUN_MODE_TOKEN,
|
|
84
|
+
optional: true,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export { getChildProviders };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { loadModule } from '@tinkoff/module-loader-client';
|
|
2
|
+
import { Loader } from '../shared/loader.browser.js';
|
|
3
|
+
import { initModuleFederation, getModuleFederation } from '../shared/webpack/moduleFederation.browser.js';
|
|
4
|
+
|
|
5
|
+
const getModuleFromGlobal = (entry) => {
|
|
6
|
+
return window[`child-app__${entry}`];
|
|
7
|
+
};
|
|
8
|
+
class BrowserLoader extends Loader {
|
|
9
|
+
constructor({ logger }) {
|
|
10
|
+
super();
|
|
11
|
+
this.initializedMap = new WeakMap();
|
|
12
|
+
this.log = logger('child-app:loader');
|
|
13
|
+
}
|
|
14
|
+
async load(config) {
|
|
15
|
+
var _a;
|
|
16
|
+
const moduleName = config.name;
|
|
17
|
+
const childApp = await this.get(config);
|
|
18
|
+
if (childApp) {
|
|
19
|
+
this.log.debug({
|
|
20
|
+
event: 'load-cache',
|
|
21
|
+
moduleName,
|
|
22
|
+
});
|
|
23
|
+
return childApp;
|
|
24
|
+
}
|
|
25
|
+
let container = getModuleFromGlobal(config.client.entry);
|
|
26
|
+
if (!container) {
|
|
27
|
+
this.log.debug({
|
|
28
|
+
event: 'load-fetch',
|
|
29
|
+
moduleName,
|
|
30
|
+
});
|
|
31
|
+
await loadModule(config.client.entry, { cssUrl: (_a = config.css) === null || _a === void 0 ? void 0 : _a.entry });
|
|
32
|
+
container = getModuleFromGlobal(config.client.entry);
|
|
33
|
+
if (container) {
|
|
34
|
+
this.log.debug({
|
|
35
|
+
event: 'load-success',
|
|
36
|
+
moduleName,
|
|
37
|
+
});
|
|
38
|
+
await this.init(config);
|
|
39
|
+
return this.get(config);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
this.log.error({
|
|
43
|
+
event: 'load-failed',
|
|
44
|
+
moduleName,
|
|
45
|
+
});
|
|
46
|
+
return Promise.reject(new Error(`Error resolving child-app ${moduleName}`));
|
|
47
|
+
}
|
|
48
|
+
async init(config) {
|
|
49
|
+
const container = getModuleFromGlobal(config.client.entry);
|
|
50
|
+
if (container) {
|
|
51
|
+
await initModuleFederation(container);
|
|
52
|
+
const factory = (await getModuleFederation(container, 'entry'));
|
|
53
|
+
const entry = factory();
|
|
54
|
+
this.initializedMap.set(container, entry);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
get(config) {
|
|
58
|
+
const container = getModuleFromGlobal(config.client.entry);
|
|
59
|
+
const entry = container && this.initializedMap.get(container);
|
|
60
|
+
return entry && this.resolve(entry);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { BrowserLoader, getModuleFromGlobal };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { ChildAppStore } from '../shared/store.browser.js';
|
|
2
|
+
|
|
3
|
+
class PreloadManager {
|
|
4
|
+
constructor({ loader, runner, resolutionConfigManager, resolveExternalConfig, store, }) {
|
|
5
|
+
this.pageHasRendered = false;
|
|
6
|
+
this.pageHasLoaded = false;
|
|
7
|
+
this.currentlyPreloaded = new Map();
|
|
8
|
+
this.hasPreloadBefore = new Set();
|
|
9
|
+
this.hasInitialized = false;
|
|
10
|
+
this.map = new Map();
|
|
11
|
+
this.loader = loader;
|
|
12
|
+
this.runner = runner;
|
|
13
|
+
this.store = store;
|
|
14
|
+
this.resolutionConfigManager = resolutionConfigManager;
|
|
15
|
+
this.resolveExternalConfig = resolveExternalConfig;
|
|
16
|
+
}
|
|
17
|
+
async preload(request) {
|
|
18
|
+
await this.init();
|
|
19
|
+
const config = this.resolveExternalConfig(request);
|
|
20
|
+
if (!config) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const { key } = config;
|
|
24
|
+
if (this.pageHasRendered) {
|
|
25
|
+
this.currentlyPreloaded.set(key, config);
|
|
26
|
+
}
|
|
27
|
+
if (!this.isPreloaded(config)) {
|
|
28
|
+
if (this.map.has(key)) {
|
|
29
|
+
return this.map.get(key);
|
|
30
|
+
}
|
|
31
|
+
// TODO: remove after dropping support for react@<18 as it can handle hydration errors with Suspense
|
|
32
|
+
// in case React render yet has not been executed do not load any external child-app app as
|
|
33
|
+
// as it will lead to markup mismatch on markup hydration
|
|
34
|
+
if (this.pageHasRendered) {
|
|
35
|
+
// but in case render has happened load child-app as soon as possible
|
|
36
|
+
const promise = (async () => {
|
|
37
|
+
try {
|
|
38
|
+
await this.loader.load(config);
|
|
39
|
+
await this.run('customer', config);
|
|
40
|
+
await this.run('clear', config);
|
|
41
|
+
}
|
|
42
|
+
catch (error) { }
|
|
43
|
+
this.hasPreloadBefore.add(key);
|
|
44
|
+
})();
|
|
45
|
+
this.map.set(key, promise);
|
|
46
|
+
return promise;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
isPreloaded(request) {
|
|
51
|
+
const config = this.resolveExternalConfig(request);
|
|
52
|
+
return !!config && this.hasPreloadBefore.has(config.key);
|
|
53
|
+
}
|
|
54
|
+
async runPreloaded() {
|
|
55
|
+
await this.init();
|
|
56
|
+
if (this.pageHasRendered) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const promises = [];
|
|
60
|
+
this.currentlyPreloaded.forEach((config) => {
|
|
61
|
+
promises.push((async () => {
|
|
62
|
+
await this.loader.init(config);
|
|
63
|
+
await this.run('customer', config);
|
|
64
|
+
})());
|
|
65
|
+
});
|
|
66
|
+
await Promise.all(promises);
|
|
67
|
+
}
|
|
68
|
+
pageRender() {
|
|
69
|
+
this.pageHasRendered = true;
|
|
70
|
+
}
|
|
71
|
+
async clearPreloaded() {
|
|
72
|
+
if (this.pageHasLoaded) {
|
|
73
|
+
this.currentlyPreloaded.clear();
|
|
74
|
+
this.map.clear();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.pageHasLoaded = true;
|
|
78
|
+
const promises = [];
|
|
79
|
+
this.currentlyPreloaded.forEach((config) => {
|
|
80
|
+
promises.push(this.run('clear', config));
|
|
81
|
+
});
|
|
82
|
+
this.currentlyPreloaded.clear();
|
|
83
|
+
this.map.clear();
|
|
84
|
+
await Promise.all(promises);
|
|
85
|
+
}
|
|
86
|
+
getPreloadedList() {
|
|
87
|
+
return Array.from(this.currentlyPreloaded.values());
|
|
88
|
+
}
|
|
89
|
+
initServerPreloaded() {
|
|
90
|
+
if (!this.hasInitialized) {
|
|
91
|
+
const { preloaded } = this.store.getState(ChildAppStore);
|
|
92
|
+
preloaded.forEach((request) => {
|
|
93
|
+
const config = this.resolveExternalConfig(request);
|
|
94
|
+
if (config) {
|
|
95
|
+
this.currentlyPreloaded.set(config.key, config);
|
|
96
|
+
this.hasPreloadBefore.add(config.key);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
this.hasInitialized = true;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async init() {
|
|
103
|
+
await this.resolutionConfigManager.init();
|
|
104
|
+
this.initServerPreloaded();
|
|
105
|
+
}
|
|
106
|
+
async run(status, config) {
|
|
107
|
+
const childApp = this.loader.get(config);
|
|
108
|
+
if (!childApp) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await this.runner.run('client', status, config);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { PreloadManager };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Scope } from '@tinkoff/dippy';
|
|
2
|
+
import { provide, commandLineListTokens } from '@tramvai/core';
|
|
3
|
+
import { CHILD_APP_LOADER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_COMMON_INITIAL_STATE_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
|
|
4
|
+
import { LOGGER_TOKEN, STORE_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
+
import { ROUTER_TOKEN } from '@tramvai/tokens-router';
|
|
6
|
+
import { BrowserLoader } from './loader.browser.js';
|
|
7
|
+
import { PreloadManager } from './preload.browser.js';
|
|
8
|
+
import { RenderManager } from './render.browser.js';
|
|
9
|
+
import { runCommand } from './runCommand.browser.js';
|
|
10
|
+
import { GLOBAL_CHILD_STATE } from '../shared/constants.browser.js';
|
|
11
|
+
|
|
12
|
+
const browserProviders = [
|
|
13
|
+
provide({
|
|
14
|
+
provide: CHILD_APP_LOADER_TOKEN,
|
|
15
|
+
useClass: BrowserLoader,
|
|
16
|
+
scope: Scope.SINGLETON,
|
|
17
|
+
deps: {
|
|
18
|
+
logger: LOGGER_TOKEN,
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
provide({
|
|
22
|
+
provide: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
23
|
+
useClass: PreloadManager,
|
|
24
|
+
deps: {
|
|
25
|
+
loader: CHILD_APP_LOADER_TOKEN,
|
|
26
|
+
runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
|
|
27
|
+
resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
|
|
28
|
+
resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
|
|
29
|
+
store: STORE_TOKEN,
|
|
30
|
+
},
|
|
31
|
+
}),
|
|
32
|
+
provide({
|
|
33
|
+
provide: CHILD_APP_COMMON_INITIAL_STATE_TOKEN,
|
|
34
|
+
useFactory: () => { var _a, _b; return JSON.parse((_b = (_a = document.getElementById(GLOBAL_CHILD_STATE)) === null || _a === void 0 ? void 0 : _a.textContent) !== null && _b !== void 0 ? _b : '{}'); },
|
|
35
|
+
}),
|
|
36
|
+
provide({
|
|
37
|
+
provide: CHILD_APP_RENDER_MANAGER_TOKEN,
|
|
38
|
+
useClass: RenderManager,
|
|
39
|
+
deps: {
|
|
40
|
+
logger: LOGGER_TOKEN,
|
|
41
|
+
diManager: CHILD_APP_DI_MANAGER_TOKEN,
|
|
42
|
+
preloadManager: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
43
|
+
resolutionConfigManager: CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN,
|
|
44
|
+
resolveExternalConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
|
|
45
|
+
},
|
|
46
|
+
}),
|
|
47
|
+
provide({
|
|
48
|
+
provide: commandLineListTokens.resolvePageDeps,
|
|
49
|
+
multi: true,
|
|
50
|
+
useFactory: ({ preloader }) => {
|
|
51
|
+
let hasCalled = false;
|
|
52
|
+
return function childAppRunPreloaded() {
|
|
53
|
+
if (hasCalled)
|
|
54
|
+
return;
|
|
55
|
+
hasCalled = true;
|
|
56
|
+
return preloader.runPreloaded();
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
deps: {
|
|
60
|
+
preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
provide({
|
|
64
|
+
provide: commandLineListTokens.customerStart,
|
|
65
|
+
multi: true,
|
|
66
|
+
useFactory: ({ router, preloader }) => {
|
|
67
|
+
return function childAppRegisterClear() {
|
|
68
|
+
router.registerHook('beforeNavigate', () => preloader.clearPreloaded());
|
|
69
|
+
router.registerHook('beforeUpdateCurrent', () => preloader.clearPreloaded());
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
deps: {
|
|
73
|
+
router: ROUTER_TOKEN,
|
|
74
|
+
preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
75
|
+
},
|
|
76
|
+
}),
|
|
77
|
+
provide({
|
|
78
|
+
provide: commandLineListTokens.spaTransition,
|
|
79
|
+
multi: true,
|
|
80
|
+
useFactory: ({ preloader, runner }) => {
|
|
81
|
+
return async function childAppRunPreloaded() {
|
|
82
|
+
await runCommand({
|
|
83
|
+
preloader,
|
|
84
|
+
runner,
|
|
85
|
+
status: 'spa',
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
deps: {
|
|
90
|
+
preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
91
|
+
runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
|
|
92
|
+
},
|
|
93
|
+
}),
|
|
94
|
+
provide({
|
|
95
|
+
provide: commandLineListTokens.afterSpaTransition,
|
|
96
|
+
multi: true,
|
|
97
|
+
useFactory: ({ preloader, runner }) => {
|
|
98
|
+
return async function childAppRunPreloaded() {
|
|
99
|
+
await runCommand({
|
|
100
|
+
preloader,
|
|
101
|
+
runner,
|
|
102
|
+
status: 'afterSpa',
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
deps: {
|
|
107
|
+
preloader: CHILD_APP_PRELOAD_MANAGER_TOKEN,
|
|
108
|
+
runner: CHILD_APP_COMMAND_LINE_RUNNER_TOKEN,
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
];
|
|
112
|
+
|
|
113
|
+
export { browserProviders };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class RenderManager {
|
|
2
|
+
constructor({ logger, preloadManager, diManager, resolveExternalConfig, }) {
|
|
3
|
+
this.log = logger('child-app:render');
|
|
4
|
+
this.preloadManager = preloadManager;
|
|
5
|
+
this.diManager = diManager;
|
|
6
|
+
this.resolveExternalConfig = resolveExternalConfig;
|
|
7
|
+
}
|
|
8
|
+
getChildDi(request) {
|
|
9
|
+
const config = this.resolveExternalConfig(request);
|
|
10
|
+
if (!config) {
|
|
11
|
+
throw new Error(`Child app "${request.name}" not found`);
|
|
12
|
+
}
|
|
13
|
+
if (this.preloadManager.isPreloaded(request)) {
|
|
14
|
+
return [this.diManager.getChildDi(config), undefined];
|
|
15
|
+
}
|
|
16
|
+
this.log.warn({
|
|
17
|
+
message: 'Child-app has been used but not preloaded before React render',
|
|
18
|
+
request,
|
|
19
|
+
});
|
|
20
|
+
const promiseDi = this.preloadManager.preload(request).then(() => {
|
|
21
|
+
return this.diManager.getChildDi(config);
|
|
22
|
+
});
|
|
23
|
+
return [undefined, promiseDi];
|
|
24
|
+
}
|
|
25
|
+
clear() { }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { RenderManager };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
|
+
import { Module } from '@tramvai/core';
|
|
3
|
+
import { sharedProviders } from './shared/providers.browser.js';
|
|
4
|
+
import { browserProviders } from './browser/providers.browser.js';
|
|
5
|
+
export * from '@tramvai/tokens-child-app';
|
|
6
|
+
export { ChildApp } from './shared/react/component.browser.js';
|
|
7
|
+
|
|
8
|
+
let ChildAppModule = class ChildAppModule {
|
|
9
|
+
};
|
|
10
|
+
ChildAppModule = __decorate([
|
|
11
|
+
Module({
|
|
12
|
+
imports: [],
|
|
13
|
+
providers: [...sharedProviders, ...browserProviders],
|
|
14
|
+
})
|
|
15
|
+
], ChildAppModule);
|
|
16
|
+
|
|
17
|
+
export { ChildAppModule };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import flatten from '@tinkoff/utils/array/flatten';
|
|
2
|
+
import { provide } from '@tramvai/core';
|
|
3
|
+
import { commandLineListTokens, CHILD_APP_INTERNAL_ACTION_TOKEN } from '@tramvai/tokens-child-app';
|
|
4
|
+
import { ACTION_PAGE_RUNNER_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
+
|
|
6
|
+
const getChildProviders = (appDi) => {
|
|
7
|
+
return [
|
|
8
|
+
provide({
|
|
9
|
+
provide: commandLineListTokens.resolvePageDeps,
|
|
10
|
+
multi: true,
|
|
11
|
+
useFactory: ({ actionRunner, actions }) => {
|
|
12
|
+
return function childAppRunActions() {
|
|
13
|
+
return actionRunner.runActions(flatten(actions));
|
|
14
|
+
};
|
|
15
|
+
},
|
|
16
|
+
deps: {
|
|
17
|
+
actionRunner: ACTION_PAGE_RUNNER_TOKEN,
|
|
18
|
+
actions: CHILD_APP_INTERNAL_ACTION_TOKEN,
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { getChildProviders };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var flatten = require('@tinkoff/utils/array/flatten');
|
|
6
|
+
var core = require('@tramvai/core');
|
|
7
|
+
var tokensChildApp = require('@tramvai/tokens-child-app');
|
|
8
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
9
|
+
|
|
10
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
|
+
|
|
12
|
+
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
13
|
+
|
|
14
|
+
const getChildProviders = (appDi) => {
|
|
15
|
+
return [
|
|
16
|
+
core.provide({
|
|
17
|
+
provide: tokensChildApp.commandLineListTokens.resolvePageDeps,
|
|
18
|
+
multi: true,
|
|
19
|
+
useFactory: ({ actionRunner, actions }) => {
|
|
20
|
+
return function childAppRunActions() {
|
|
21
|
+
return actionRunner.runActions(flatten__default["default"](actions));
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
deps: {
|
|
25
|
+
actionRunner: tokensCommon.ACTION_PAGE_RUNNER_TOKEN,
|
|
26
|
+
actions: tokensChildApp.CHILD_APP_INTERNAL_ACTION_TOKEN,
|
|
27
|
+
},
|
|
28
|
+
}),
|
|
29
|
+
];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
exports.getChildProviders = getChildProviders;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ServerLoader as ServerLoader$1 } from '@tinkoff/module-loader-server';
|
|
2
|
+
import { Loader } from '../shared/loader.es.js';
|
|
3
|
+
import { initModuleFederation, getModuleFederation } from '../shared/webpack/moduleFederation.es.js';
|
|
4
|
+
|
|
5
|
+
class ServerLoader extends Loader {
|
|
6
|
+
constructor({ logger, createCache, }) {
|
|
7
|
+
super();
|
|
8
|
+
this.initializedMap = new WeakMap();
|
|
9
|
+
const cache = createCache('memory', {
|
|
10
|
+
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
11
|
+
max: 20,
|
|
12
|
+
});
|
|
13
|
+
this.internalLoadCache = cache;
|
|
14
|
+
this.loader = new ServerLoader$1({
|
|
15
|
+
cache,
|
|
16
|
+
log: logger('child-app:loader'),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async load(config) {
|
|
20
|
+
await this.loader.resolveByUrl(config.server.entry, {
|
|
21
|
+
codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
|
|
22
|
+
displayName: config.name,
|
|
23
|
+
kind: 'child-app',
|
|
24
|
+
});
|
|
25
|
+
await this.init(config);
|
|
26
|
+
if (config.tag === 'debug') {
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
this.internalLoadCache.set(config.server.entry, null);
|
|
29
|
+
}, 10000);
|
|
30
|
+
}
|
|
31
|
+
return this.get(config);
|
|
32
|
+
}
|
|
33
|
+
async init(config) {
|
|
34
|
+
const container = this.loader.getByUrl(config.server.entry);
|
|
35
|
+
if (container) {
|
|
36
|
+
await initModuleFederation(container, 'default');
|
|
37
|
+
const factory = (await getModuleFederation(container, 'entry'));
|
|
38
|
+
const entry = factory();
|
|
39
|
+
this.initializedMap.set(container, entry);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
get(config) {
|
|
43
|
+
const container = this.loader.getByUrl(config.server.entry);
|
|
44
|
+
return container && this.resolve(this.initializedMap.get(container));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { ServerLoader };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var moduleLoaderServer = require('@tinkoff/module-loader-server');
|
|
6
|
+
var loader = require('../shared/loader.js');
|
|
7
|
+
var moduleFederation = require('../shared/webpack/moduleFederation.js');
|
|
8
|
+
|
|
9
|
+
class ServerLoader extends loader.Loader {
|
|
10
|
+
constructor({ logger, createCache, }) {
|
|
11
|
+
super();
|
|
12
|
+
this.initializedMap = new WeakMap();
|
|
13
|
+
const cache = createCache('memory', {
|
|
14
|
+
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
15
|
+
max: 20,
|
|
16
|
+
});
|
|
17
|
+
this.internalLoadCache = cache;
|
|
18
|
+
this.loader = new moduleLoaderServer.ServerLoader({
|
|
19
|
+
cache,
|
|
20
|
+
log: logger('child-app:loader'),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async load(config) {
|
|
24
|
+
await this.loader.resolveByUrl(config.server.entry, {
|
|
25
|
+
codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
|
|
26
|
+
displayName: config.name,
|
|
27
|
+
kind: 'child-app',
|
|
28
|
+
});
|
|
29
|
+
await this.init(config);
|
|
30
|
+
if (config.tag === 'debug') {
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
this.internalLoadCache.set(config.server.entry, null);
|
|
33
|
+
}, 10000);
|
|
34
|
+
}
|
|
35
|
+
return this.get(config);
|
|
36
|
+
}
|
|
37
|
+
async init(config) {
|
|
38
|
+
const container = this.loader.getByUrl(config.server.entry);
|
|
39
|
+
if (container) {
|
|
40
|
+
await moduleFederation.initModuleFederation(container, 'default');
|
|
41
|
+
const factory = (await moduleFederation.getModuleFederation(container, 'entry'));
|
|
42
|
+
const entry = factory();
|
|
43
|
+
this.initializedMap.set(container, entry);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
get(config) {
|
|
47
|
+
const container = this.loader.getByUrl(config.server.entry);
|
|
48
|
+
return container && this.resolve(this.initializedMap.get(container));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.ServerLoader = ServerLoader;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
class PreloadManager {
|
|
2
|
+
constructor({ loader, runner, stateManager, resolutionConfigManager, resolveFullConfig, }) {
|
|
3
|
+
this.shouldRunImmediately = false;
|
|
4
|
+
this.map = new Map();
|
|
5
|
+
this.preloadMap = new Map();
|
|
6
|
+
this.loader = loader;
|
|
7
|
+
this.runner = runner;
|
|
8
|
+
this.stateManager = stateManager;
|
|
9
|
+
this.resolutionConfigManager = resolutionConfigManager;
|
|
10
|
+
this.resolveFullConfig = resolveFullConfig;
|
|
11
|
+
}
|
|
12
|
+
async preload(request) {
|
|
13
|
+
await this.resolutionConfigManager.init();
|
|
14
|
+
const config = this.resolveFullConfig(request);
|
|
15
|
+
if (!config) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const { key } = config;
|
|
19
|
+
if (this.map.has(key)) {
|
|
20
|
+
await this.map.get(key);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const promise = this.loader
|
|
24
|
+
.load(config)
|
|
25
|
+
.catch(() => {
|
|
26
|
+
// Actual error will be logged by the internals of this.loader
|
|
27
|
+
})
|
|
28
|
+
.then(() => {
|
|
29
|
+
if (this.shouldRunImmediately) {
|
|
30
|
+
return this.run('customer', config);
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
.then(() => config);
|
|
34
|
+
this.map.set(key, promise);
|
|
35
|
+
this.preloadMap.set(config.key, config);
|
|
36
|
+
if (this.shouldRunImmediately) {
|
|
37
|
+
await promise;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
isPreloaded(request) {
|
|
41
|
+
const config = this.resolveFullConfig(request);
|
|
42
|
+
return !!config && this.map.has(config.key);
|
|
43
|
+
}
|
|
44
|
+
async runPreloaded() {
|
|
45
|
+
this.shouldRunImmediately = true;
|
|
46
|
+
const promises = [];
|
|
47
|
+
this.map.forEach((childAppPromise) => {
|
|
48
|
+
promises.push((async () => {
|
|
49
|
+
await this.run('customer', await childAppPromise);
|
|
50
|
+
})());
|
|
51
|
+
});
|
|
52
|
+
await Promise.all(promises);
|
|
53
|
+
}
|
|
54
|
+
pageRender() { }
|
|
55
|
+
async clearPreloaded() {
|
|
56
|
+
const promises = [];
|
|
57
|
+
this.map.forEach((childAppPromise) => {
|
|
58
|
+
promises.push((async () => {
|
|
59
|
+
await this.run('clear', await childAppPromise);
|
|
60
|
+
})());
|
|
61
|
+
});
|
|
62
|
+
await Promise.all(promises);
|
|
63
|
+
}
|
|
64
|
+
getPreloadedList() {
|
|
65
|
+
return Array.from(this.preloadMap.values());
|
|
66
|
+
}
|
|
67
|
+
async run(status, config) {
|
|
68
|
+
const childApp = this.loader.get(config);
|
|
69
|
+
if (!childApp) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await this.runner.run('server', status, config);
|
|
73
|
+
await this.stateManager.registerChildApp(config);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { PreloadManager };
|