@tramvai/module-child-app 5.49.1 → 6.59.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/loader.browser.js +18 -5
- package/lib/browser/loader.d.ts +10 -2
- package/lib/browser/preload.browser.js +85 -29
- package/lib/browser/preload.d.ts +14 -2
- package/lib/browser/providers.browser.js +17 -2
- package/lib/browser/render.browser.js +15 -1
- package/lib/browser/render.d.ts +10 -2
- package/lib/browser/runCommand.browser.js +1 -1
- package/lib/browser/runCommand.d.ts +1 -1
- package/lib/browser/timing.browser.js +100 -0
- package/lib/browser/timing.d.ts +4 -0
- package/lib/browser.js +2 -1
- package/lib/contracts/contractManager.base.browser.js +4 -0
- package/lib/contracts/contractManager.base.es.js +4 -0
- package/lib/contracts/contractManager.base.js +4 -0
- package/lib/contracts/contractManager.server.es.js +1 -0
- package/lib/contracts/contractManager.server.js +1 -0
- package/lib/server/cache/cache.d.ts +39 -0
- package/lib/server/cache/cache.es.js +76 -0
- package/lib/server/cache/cache.js +80 -0
- package/lib/server/cache/cacheCleanup.d.ts +4 -0
- package/lib/server/cache/cacheCleanup.es.js +16 -0
- package/lib/server/cache/cacheCleanup.js +21 -0
- package/lib/server/loader.d.ts +14 -7
- package/lib/server/loader.es.js +34 -19
- package/lib/server/loader.js +34 -19
- package/lib/server/module-federation/best-loaded-shared-modules.d.ts +15 -0
- package/lib/server/module-federation/best-loaded-shared-modules.es.js +26 -0
- package/lib/server/module-federation/best-loaded-shared-modules.js +30 -0
- package/lib/server/module-federation/best-shared-modules.d.ts +15 -0
- package/lib/server/module-federation/utils.d.ts +18 -0
- package/lib/server/module-federation/utils.es.js +38 -0
- package/lib/server/module-federation/utils.js +43 -0
- package/lib/server/preload.d.ts +13 -2
- package/lib/server/preload.es.js +58 -19
- package/lib/server/preload.js +58 -19
- package/lib/server/providers.es.js +17 -4
- package/lib/server/providers.js +14 -1
- package/lib/server/render-slots.es.js +62 -50
- package/lib/server/render-slots.js +62 -50
- package/lib/server/render.d.ts +9 -2
- package/lib/server/render.es.js +13 -2
- package/lib/server/render.js +13 -2
- package/lib/server/stateManager.es.js +3 -1
- package/lib/server/stateManager.js +3 -1
- package/lib/shared/command.browser.js +4 -0
- package/lib/shared/command.es.js +4 -0
- package/lib/shared/command.js +4 -0
- package/lib/shared/di.browser.js +5 -1
- package/lib/shared/di.es.js +5 -1
- package/lib/shared/di.js +5 -1
- package/lib/shared/pageService.browser.js +8 -3
- package/lib/shared/pageService.es.js +8 -3
- package/lib/shared/pageService.js +8 -3
- package/lib/shared/providers.browser.js +8 -3
- package/lib/shared/providers.es.js +8 -3
- package/lib/shared/providers.js +6 -1
- package/lib/shared/react/ChildAppErrorBoundary/ChildAppErrorBoundary.browser.js +56 -0
- package/lib/shared/react/ChildAppErrorBoundary/ChildAppErrorBoundary.d.ts +45 -0
- package/lib/shared/react/ChildAppErrorBoundary/ChildAppErrorBoundary.es.js +56 -0
- package/lib/shared/react/ChildAppErrorBoundary/ChildAppErrorBoundary.js +60 -0
- package/lib/shared/react/ChildAppErrorBoundary/FallbackError.browser.js +21 -0
- package/lib/shared/react/ChildAppErrorBoundary/FallbackError.d.ts +5 -0
- package/lib/shared/react/ChildAppErrorBoundary/FallbackError.es.js +21 -0
- package/lib/shared/react/ChildAppErrorBoundary/FallbackError.js +25 -0
- package/lib/shared/react/ChildAppFallbackWrapper.browser.js +14 -0
- package/lib/shared/react/ChildAppFallbackWrapper.d.ts +10 -0
- package/lib/shared/react/ChildAppFallbackWrapper.es.js +14 -0
- package/lib/shared/react/ChildAppFallbackWrapper.js +18 -0
- package/lib/shared/react/childAppErrorBoundaryWrapper.browser.js +22 -0
- package/lib/shared/react/childAppErrorBoundaryWrapper.d.ts +8 -0
- package/lib/shared/react/childAppErrorBoundaryWrapper.es.js +22 -0
- package/lib/shared/react/childAppErrorBoundaryWrapper.js +26 -0
- package/lib/shared/react/component.browser.js +31 -6
- package/lib/shared/react/component.es.js +31 -6
- package/lib/shared/react/component.js +29 -4
- package/lib/shared/resolutionConfigManager.browser.js +35 -15
- package/lib/shared/resolutionConfigManager.d.ts +8 -2
- package/lib/shared/resolutionConfigManager.es.js +35 -15
- package/lib/shared/resolutionConfigManager.js +35 -15
- package/lib/shared/singletonDi.browser.js +18 -2
- package/lib/shared/singletonDi.d.ts +1 -0
- package/lib/shared/singletonDi.es.js +18 -2
- package/lib/shared/singletonDi.js +18 -2
- package/lib/shared/store.browser.js +15 -2
- package/lib/shared/store.d.ts +6 -0
- package/lib/shared/store.es.js +15 -2
- package/lib/shared/store.js +15 -1
- package/lib/shared/webpack/moduleFederation.browser.js +42 -0
- package/lib/shared/webpack/moduleFederation.d.ts +27 -18
- package/lib/shared/webpack/moduleFederation.es.js +42 -0
- package/lib/shared/webpack/moduleFederation.js +42 -0
- package/package.json +22 -23
- package/lib/shared/react/childAppErrorBoundary.browser.js +0 -14
- package/lib/shared/react/childAppErrorBoundary.d.ts +0 -8
- package/lib/shared/react/childAppErrorBoundary.es.js +0 -14
- package/lib/shared/react/childAppErrorBoundary.js +0 -18
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { provide, commandLineListTokens } from '@tramvai/core';
|
|
2
|
+
import { optional, Scope } from '@tinkoff/dippy';
|
|
3
|
+
import { CHILD_APP_LOADER_CACHE_CLEANUP_CONFIG_TOKEN, CHILD_APP_LOADER_CACHE_TOKEN, CHILD_APP_LOADER_CACHE_OPTIONS_TOKEN } from '@tramvai/tokens-child-app';
|
|
4
|
+
import { ASYNC_LOCAL_STORAGE_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
|
|
5
|
+
import { setCacheCleanupInterval } from './cacheCleanup.es.js';
|
|
6
|
+
|
|
7
|
+
const cache = [
|
|
8
|
+
provide({
|
|
9
|
+
provide: commandLineListTokens.listen,
|
|
10
|
+
useFactory: ({ childAppLoaderCache, cacheCleanupConfig }) => {
|
|
11
|
+
return () => {
|
|
12
|
+
setCacheCleanupInterval(childAppLoaderCache, cacheCleanupConfig?.cleanupIntervalMs);
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
deps: {
|
|
16
|
+
cacheCleanupConfig: optional(CHILD_APP_LOADER_CACHE_CLEANUP_CONFIG_TOKEN),
|
|
17
|
+
childAppLoaderCache: CHILD_APP_LOADER_CACHE_TOKEN,
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
provide({
|
|
21
|
+
provide: CHILD_APP_LOADER_CACHE_TOKEN,
|
|
22
|
+
scope: Scope.SINGLETON,
|
|
23
|
+
useFactory: ({ createCache, cacheOptions, asyncLocalStorage }) => {
|
|
24
|
+
const inMemoryCache = createCache('memory', {
|
|
25
|
+
name: 'child-app-loader',
|
|
26
|
+
// When Child App script is evicted from server loader cache, we get a small memory leak,
|
|
27
|
+
// because providers in singleton child DI, page components / actions, will store a reference to removed script,
|
|
28
|
+
// and server loader cache will contain a new instance of the same script.
|
|
29
|
+
//
|
|
30
|
+
// So, it is better to have bigger cache size to prevent evicting from cache,
|
|
31
|
+
// also for one Child App we need to save 3 elements - server JS, stats JSON and loadable stats JSON.
|
|
32
|
+
max: 100,
|
|
33
|
+
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
34
|
+
...cacheOptions,
|
|
35
|
+
});
|
|
36
|
+
let childAppLoaderCache = inMemoryCache;
|
|
37
|
+
// Cache is not compatible with HMR (Hot Module Replacement) because after HMR and page reload,
|
|
38
|
+
// we get the page from the cache. To solve this, we use Async Local Storage to ensure the
|
|
39
|
+
// cache is only valid within the context of a single request.
|
|
40
|
+
if (process.env.NODE_ENV === 'development' && !!asyncLocalStorage) {
|
|
41
|
+
childAppLoaderCache = {
|
|
42
|
+
get(key) {
|
|
43
|
+
if (key?.startsWith('__DEBUG__')) {
|
|
44
|
+
const store = asyncLocalStorage.getStore();
|
|
45
|
+
if (store) {
|
|
46
|
+
return store[key];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
return inMemoryCache.get(key);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
set(key, module) {
|
|
54
|
+
if (key?.startsWith('__DEBUG__')) {
|
|
55
|
+
const store = asyncLocalStorage.getStore();
|
|
56
|
+
if (store) {
|
|
57
|
+
store[key] = module;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
inMemoryCache.set(key, module);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return childAppLoaderCache;
|
|
67
|
+
},
|
|
68
|
+
deps: {
|
|
69
|
+
asyncLocalStorage: optional(ASYNC_LOCAL_STORAGE_TOKEN),
|
|
70
|
+
cacheOptions: optional(CHILD_APP_LOADER_CACHE_OPTIONS_TOKEN),
|
|
71
|
+
createCache: CREATE_CACHE_TOKEN,
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
export { cache };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var core = require('@tramvai/core');
|
|
6
|
+
var dippy = require('@tinkoff/dippy');
|
|
7
|
+
var tokensChildApp = require('@tramvai/tokens-child-app');
|
|
8
|
+
var tokensCommon = require('@tramvai/tokens-common');
|
|
9
|
+
var cacheCleanup = require('./cacheCleanup.js');
|
|
10
|
+
|
|
11
|
+
const cache = [
|
|
12
|
+
core.provide({
|
|
13
|
+
provide: core.commandLineListTokens.listen,
|
|
14
|
+
useFactory: ({ childAppLoaderCache, cacheCleanupConfig }) => {
|
|
15
|
+
return () => {
|
|
16
|
+
cacheCleanup.setCacheCleanupInterval(childAppLoaderCache, cacheCleanupConfig?.cleanupIntervalMs);
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
deps: {
|
|
20
|
+
cacheCleanupConfig: dippy.optional(tokensChildApp.CHILD_APP_LOADER_CACHE_CLEANUP_CONFIG_TOKEN),
|
|
21
|
+
childAppLoaderCache: tokensChildApp.CHILD_APP_LOADER_CACHE_TOKEN,
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
core.provide({
|
|
25
|
+
provide: tokensChildApp.CHILD_APP_LOADER_CACHE_TOKEN,
|
|
26
|
+
scope: dippy.Scope.SINGLETON,
|
|
27
|
+
useFactory: ({ createCache, cacheOptions, asyncLocalStorage }) => {
|
|
28
|
+
const inMemoryCache = createCache('memory', {
|
|
29
|
+
name: 'child-app-loader',
|
|
30
|
+
// When Child App script is evicted from server loader cache, we get a small memory leak,
|
|
31
|
+
// because providers in singleton child DI, page components / actions, will store a reference to removed script,
|
|
32
|
+
// and server loader cache will contain a new instance of the same script.
|
|
33
|
+
//
|
|
34
|
+
// So, it is better to have bigger cache size to prevent evicting from cache,
|
|
35
|
+
// also for one Child App we need to save 3 elements - server JS, stats JSON and loadable stats JSON.
|
|
36
|
+
max: 100,
|
|
37
|
+
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
38
|
+
...cacheOptions,
|
|
39
|
+
});
|
|
40
|
+
let childAppLoaderCache = inMemoryCache;
|
|
41
|
+
// Cache is not compatible with HMR (Hot Module Replacement) because after HMR and page reload,
|
|
42
|
+
// we get the page from the cache. To solve this, we use Async Local Storage to ensure the
|
|
43
|
+
// cache is only valid within the context of a single request.
|
|
44
|
+
if (process.env.NODE_ENV === 'development' && !!asyncLocalStorage) {
|
|
45
|
+
childAppLoaderCache = {
|
|
46
|
+
get(key) {
|
|
47
|
+
if (key?.startsWith('__DEBUG__')) {
|
|
48
|
+
const store = asyncLocalStorage.getStore();
|
|
49
|
+
if (store) {
|
|
50
|
+
return store[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return inMemoryCache.get(key);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
set(key, module) {
|
|
58
|
+
if (key?.startsWith('__DEBUG__')) {
|
|
59
|
+
const store = asyncLocalStorage.getStore();
|
|
60
|
+
if (store) {
|
|
61
|
+
store[key] = module;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
inMemoryCache.set(key, module);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return childAppLoaderCache;
|
|
71
|
+
},
|
|
72
|
+
deps: {
|
|
73
|
+
asyncLocalStorage: dippy.optional(tokensCommon.ASYNC_LOCAL_STORAGE_TOKEN),
|
|
74
|
+
cacheOptions: dippy.optional(tokensChildApp.CHILD_APP_LOADER_CACHE_OPTIONS_TOKEN),
|
|
75
|
+
createCache: tokensCommon.CREATE_CACHE_TOKEN,
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
exports.cache = cache;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function cleanupStaleElementsInCache(cache) {
|
|
2
|
+
const entries = cache.dump();
|
|
3
|
+
const now = Date.now();
|
|
4
|
+
for (const [key, value] of entries) {
|
|
5
|
+
if (value.start + value.ttl < now) {
|
|
6
|
+
cache.delete(key);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function setCacheCleanupInterval(cache, intervalMs = 1000 * 60 * 60 * 24) {
|
|
11
|
+
setInterval(() => {
|
|
12
|
+
cleanupStaleElementsInCache(cache);
|
|
13
|
+
}, intervalMs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { cleanupStaleElementsInCache, setCacheCleanupInterval };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
function cleanupStaleElementsInCache(cache) {
|
|
6
|
+
const entries = cache.dump();
|
|
7
|
+
const now = Date.now();
|
|
8
|
+
for (const [key, value] of entries) {
|
|
9
|
+
if (value.start + value.ttl < now) {
|
|
10
|
+
cache.delete(key);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function setCacheCleanupInterval(cache, intervalMs = 1000 * 60 * 60 * 24) {
|
|
15
|
+
setInterval(() => {
|
|
16
|
+
cleanupStaleElementsInCache(cache);
|
|
17
|
+
}, intervalMs);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.cleanupStaleElementsInCache = cleanupStaleElementsInCache;
|
|
21
|
+
exports.setCacheCleanupInterval = setCacheCleanupInterval;
|
package/lib/server/loader.d.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
import type { ChildApp } from '@tramvai/child-app-core';
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
1
|
+
import type { CHILD_APP_LOADER_PLUGIN, ChildApp } from '@tramvai/child-app-core';
|
|
2
|
+
import { CHILD_APP_LOADER_CACHE_TOKEN, type ChildAppFinalConfig } from '@tramvai/tokens-child-app';
|
|
3
|
+
import type { LOGGER_TOKEN, ENV_MANAGER_TOKEN } from '@tramvai/tokens-common';
|
|
4
|
+
import { AsyncTapableHookInstance, TAPABLE_HOOK_FACTORY_TOKEN } from '@tramvai/core';
|
|
4
5
|
import { Loader } from '../shared/loader';
|
|
5
6
|
import type { LoadableStats, ModuleFederationStats } from '../shared/webpack/moduleFederation';
|
|
6
7
|
export declare class ServerLoader extends Loader {
|
|
7
8
|
private readonly loader;
|
|
8
9
|
private readonly initializedMap;
|
|
9
|
-
private internalLoadCache;
|
|
10
10
|
private log;
|
|
11
|
-
|
|
11
|
+
private hookFactory;
|
|
12
|
+
loadModuleHook: AsyncTapableHookInstance<{
|
|
13
|
+
config: ChildAppFinalConfig;
|
|
14
|
+
}, ChildApp | undefined>;
|
|
15
|
+
constructor({ logger, envManager, cache, hookFactory, plugins, }: {
|
|
16
|
+
hookFactory: typeof TAPABLE_HOOK_FACTORY_TOKEN;
|
|
12
17
|
logger: typeof LOGGER_TOKEN;
|
|
13
|
-
createCache: typeof CREATE_CACHE_TOKEN;
|
|
14
18
|
envManager: typeof ENV_MANAGER_TOKEN;
|
|
19
|
+
cache: typeof CHILD_APP_LOADER_CACHE_TOKEN;
|
|
20
|
+
plugins: (typeof CHILD_APP_LOADER_PLUGIN)[] | null;
|
|
15
21
|
});
|
|
22
|
+
private loadModule;
|
|
16
23
|
load(config: ChildAppFinalConfig): Promise<ChildApp | void>;
|
|
17
24
|
init(config: ChildAppFinalConfig): Promise<void>;
|
|
18
|
-
get(config: ChildAppFinalConfig): ChildApp |
|
|
25
|
+
get(config: ChildAppFinalConfig): ChildApp | undefined;
|
|
19
26
|
getStats(config: ChildAppFinalConfig): ModuleFederationStats | void;
|
|
20
27
|
getLoadableStats(config: ChildAppFinalConfig): LoadableStats | void;
|
|
21
28
|
waitFor(): Promise<void>;
|
package/lib/server/loader.es.js
CHANGED
|
@@ -4,15 +4,14 @@ import { Loader } from '../shared/loader.es.js';
|
|
|
4
4
|
import { initModuleFederation, getModuleFederation } from '../shared/webpack/moduleFederation.es.js';
|
|
5
5
|
|
|
6
6
|
class ServerLoader extends Loader {
|
|
7
|
-
|
|
7
|
+
loader;
|
|
8
|
+
initializedMap = new WeakMap();
|
|
9
|
+
log;
|
|
10
|
+
hookFactory;
|
|
11
|
+
loadModuleHook;
|
|
12
|
+
constructor({ logger, envManager, cache, hookFactory, plugins, }) {
|
|
8
13
|
super();
|
|
9
|
-
this.
|
|
10
|
-
const cache = createCache('memory', {
|
|
11
|
-
name: 'child-app-loader',
|
|
12
|
-
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
13
|
-
max: 20,
|
|
14
|
-
});
|
|
15
|
-
this.internalLoadCache = cache;
|
|
14
|
+
this.hookFactory = hookFactory;
|
|
16
15
|
this.log = logger('child-app:loader');
|
|
17
16
|
this.loader = new ServerLoader$1({
|
|
18
17
|
cache,
|
|
@@ -21,13 +20,21 @@ class ServerLoader extends Loader {
|
|
|
21
20
|
circuitBreakerEnabled: isNil(envManager.get('HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED')),
|
|
22
21
|
},
|
|
23
22
|
});
|
|
23
|
+
this.loadModuleHook = this.hookFactory.createAsync('childAppLoadModule');
|
|
24
|
+
this.loadModuleHook.tapPromise('childAppLoadModule', async (_, payload) => {
|
|
25
|
+
return this.loadModule(payload);
|
|
26
|
+
});
|
|
27
|
+
plugins?.forEach((plugin) => {
|
|
28
|
+
plugin.apply({ loadModule: this.loadModuleHook });
|
|
29
|
+
});
|
|
24
30
|
}
|
|
25
|
-
async
|
|
31
|
+
async loadModule({ config }) {
|
|
26
32
|
const promises = [
|
|
27
33
|
this.loader.resolveByUrl(config.server.entry, {
|
|
28
34
|
codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
|
|
29
35
|
displayName: config.name,
|
|
30
36
|
kind: 'child-app',
|
|
37
|
+
debug: config.tag === 'debug',
|
|
31
38
|
}),
|
|
32
39
|
this.loader
|
|
33
40
|
.resolveByUrl(config.client.stats, {
|
|
@@ -35,6 +42,7 @@ class ServerLoader extends Loader {
|
|
|
35
42
|
kind: 'child-app stats',
|
|
36
43
|
displayName: config.name,
|
|
37
44
|
silent: true,
|
|
45
|
+
debug: config.tag === 'debug',
|
|
38
46
|
})
|
|
39
47
|
// we can live without stats
|
|
40
48
|
.catch(() => { }),
|
|
@@ -46,6 +54,7 @@ class ServerLoader extends Loader {
|
|
|
46
54
|
kind: 'child-app loadable stats',
|
|
47
55
|
displayName: config.name,
|
|
48
56
|
silent: true,
|
|
57
|
+
debug: config.tag === 'debug',
|
|
49
58
|
})
|
|
50
59
|
// we can live without loadable stats, for backward compatibility is ok
|
|
51
60
|
// but hydration errors will occur when lazy component will loaded at client-side at demand
|
|
@@ -53,17 +62,16 @@ class ServerLoader extends Loader {
|
|
|
53
62
|
}
|
|
54
63
|
await Promise.all(promises);
|
|
55
64
|
await this.init(config);
|
|
56
|
-
if (config.tag === 'debug') {
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
this.internalLoadCache.set(config.server.entry, null);
|
|
59
|
-
this.internalLoadCache.set(config.client.stats, null);
|
|
60
|
-
this.internalLoadCache.set(config.client.statsLoadable, null);
|
|
61
|
-
}, 10000);
|
|
62
|
-
}
|
|
63
65
|
return this.get(config);
|
|
64
66
|
}
|
|
67
|
+
async load(config) {
|
|
68
|
+
const childApp = await this.loadModuleHook.callPromise({ config });
|
|
69
|
+
return childApp;
|
|
70
|
+
}
|
|
65
71
|
async init(config) {
|
|
66
|
-
const container = this.loader.getByUrl(config.server.entry
|
|
72
|
+
const container = this.loader.getByUrl(config.server.entry, {
|
|
73
|
+
debug: config.tag === 'debug',
|
|
74
|
+
});
|
|
67
75
|
if (!container) {
|
|
68
76
|
return;
|
|
69
77
|
}
|
|
@@ -86,12 +94,19 @@ class ServerLoader extends Loader {
|
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
get(config) {
|
|
89
|
-
const container = this.loader.getByUrl(config.server.entry
|
|
97
|
+
const container = this.loader.getByUrl(config.server.entry, {
|
|
98
|
+
debug: config.tag === 'debug',
|
|
99
|
+
});
|
|
100
|
+
if (!container) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
90
103
|
const entry = container && this.initializedMap.get(container);
|
|
91
104
|
return entry && this.resolve(entry);
|
|
92
105
|
}
|
|
93
106
|
getStats(config) {
|
|
94
|
-
return this.loader.getByUrl(config.client.stats
|
|
107
|
+
return this.loader.getByUrl(config.client.stats, {
|
|
108
|
+
debug: config.tag === 'debug',
|
|
109
|
+
});
|
|
95
110
|
}
|
|
96
111
|
getLoadableStats(config) {
|
|
97
112
|
if (!config.client.statsLoadable) {
|
package/lib/server/loader.js
CHANGED
|
@@ -12,15 +12,14 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
12
12
|
var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
|
|
13
13
|
|
|
14
14
|
class ServerLoader extends loader.Loader {
|
|
15
|
-
|
|
15
|
+
loader;
|
|
16
|
+
initializedMap = new WeakMap();
|
|
17
|
+
log;
|
|
18
|
+
hookFactory;
|
|
19
|
+
loadModuleHook;
|
|
20
|
+
constructor({ logger, envManager, cache, hookFactory, plugins, }) {
|
|
16
21
|
super();
|
|
17
|
-
this.
|
|
18
|
-
const cache = createCache('memory', {
|
|
19
|
-
name: 'child-app-loader',
|
|
20
|
-
ttl: 1000 * 60 * 60 * 24 * 5,
|
|
21
|
-
max: 20,
|
|
22
|
-
});
|
|
23
|
-
this.internalLoadCache = cache;
|
|
22
|
+
this.hookFactory = hookFactory;
|
|
24
23
|
this.log = logger('child-app:loader');
|
|
25
24
|
this.loader = new moduleLoaderServer.ServerLoader({
|
|
26
25
|
cache,
|
|
@@ -29,13 +28,21 @@ class ServerLoader extends loader.Loader {
|
|
|
29
28
|
circuitBreakerEnabled: isNil__default["default"](envManager.get('HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED')),
|
|
30
29
|
},
|
|
31
30
|
});
|
|
31
|
+
this.loadModuleHook = this.hookFactory.createAsync('childAppLoadModule');
|
|
32
|
+
this.loadModuleHook.tapPromise('childAppLoadModule', async (_, payload) => {
|
|
33
|
+
return this.loadModule(payload);
|
|
34
|
+
});
|
|
35
|
+
plugins?.forEach((plugin) => {
|
|
36
|
+
plugin.apply({ loadModule: this.loadModuleHook });
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
|
-
async
|
|
39
|
+
async loadModule({ config }) {
|
|
34
40
|
const promises = [
|
|
35
41
|
this.loader.resolveByUrl(config.server.entry, {
|
|
36
42
|
codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
|
|
37
43
|
displayName: config.name,
|
|
38
44
|
kind: 'child-app',
|
|
45
|
+
debug: config.tag === 'debug',
|
|
39
46
|
}),
|
|
40
47
|
this.loader
|
|
41
48
|
.resolveByUrl(config.client.stats, {
|
|
@@ -43,6 +50,7 @@ class ServerLoader extends loader.Loader {
|
|
|
43
50
|
kind: 'child-app stats',
|
|
44
51
|
displayName: config.name,
|
|
45
52
|
silent: true,
|
|
53
|
+
debug: config.tag === 'debug',
|
|
46
54
|
})
|
|
47
55
|
// we can live without stats
|
|
48
56
|
.catch(() => { }),
|
|
@@ -54,6 +62,7 @@ class ServerLoader extends loader.Loader {
|
|
|
54
62
|
kind: 'child-app loadable stats',
|
|
55
63
|
displayName: config.name,
|
|
56
64
|
silent: true,
|
|
65
|
+
debug: config.tag === 'debug',
|
|
57
66
|
})
|
|
58
67
|
// we can live without loadable stats, for backward compatibility is ok
|
|
59
68
|
// but hydration errors will occur when lazy component will loaded at client-side at demand
|
|
@@ -61,17 +70,16 @@ class ServerLoader extends loader.Loader {
|
|
|
61
70
|
}
|
|
62
71
|
await Promise.all(promises);
|
|
63
72
|
await this.init(config);
|
|
64
|
-
if (config.tag === 'debug') {
|
|
65
|
-
setTimeout(() => {
|
|
66
|
-
this.internalLoadCache.set(config.server.entry, null);
|
|
67
|
-
this.internalLoadCache.set(config.client.stats, null);
|
|
68
|
-
this.internalLoadCache.set(config.client.statsLoadable, null);
|
|
69
|
-
}, 10000);
|
|
70
|
-
}
|
|
71
73
|
return this.get(config);
|
|
72
74
|
}
|
|
75
|
+
async load(config) {
|
|
76
|
+
const childApp = await this.loadModuleHook.callPromise({ config });
|
|
77
|
+
return childApp;
|
|
78
|
+
}
|
|
73
79
|
async init(config) {
|
|
74
|
-
const container = this.loader.getByUrl(config.server.entry
|
|
80
|
+
const container = this.loader.getByUrl(config.server.entry, {
|
|
81
|
+
debug: config.tag === 'debug',
|
|
82
|
+
});
|
|
75
83
|
if (!container) {
|
|
76
84
|
return;
|
|
77
85
|
}
|
|
@@ -94,12 +102,19 @@ class ServerLoader extends loader.Loader {
|
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
get(config) {
|
|
97
|
-
const container = this.loader.getByUrl(config.server.entry
|
|
105
|
+
const container = this.loader.getByUrl(config.server.entry, {
|
|
106
|
+
debug: config.tag === 'debug',
|
|
107
|
+
});
|
|
108
|
+
if (!container) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
98
111
|
const entry = container && this.initializedMap.get(container);
|
|
99
112
|
return entry && this.resolve(entry);
|
|
100
113
|
}
|
|
101
114
|
getStats(config) {
|
|
102
|
-
return this.loader.getByUrl(config.client.stats
|
|
115
|
+
return this.loader.getByUrl(config.client.stats, {
|
|
116
|
+
debug: config.tag === 'debug',
|
|
117
|
+
});
|
|
103
118
|
}
|
|
104
119
|
getLoadableStats(config) {
|
|
105
120
|
if (!config.client.statsLoadable) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SharedModule, SharedScopeItem } from './utils';
|
|
2
|
+
export type SharedModuleWithChunks = {
|
|
3
|
+
shareKey: string;
|
|
4
|
+
from: string;
|
|
5
|
+
version: string;
|
|
6
|
+
eager: boolean;
|
|
7
|
+
childAppName?: string;
|
|
8
|
+
childAppVersion?: string;
|
|
9
|
+
chunks?: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveBestLoadedSharedModules({ sharedModules, sharedScopeItems, }: {
|
|
12
|
+
sharedModules: SharedModule[];
|
|
13
|
+
sharedScopeItems: SharedScopeItem[];
|
|
14
|
+
}): SharedModuleWithChunks[];
|
|
15
|
+
//# sourceMappingURL=best-loaded-shared-modules.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function resolveBestLoadedSharedModules({ sharedModules, sharedScopeItems, }) {
|
|
2
|
+
const result = [];
|
|
3
|
+
for (const sharedScopeItem of sharedScopeItems) {
|
|
4
|
+
const { shareKey, from, eager, loaded } = sharedScopeItem;
|
|
5
|
+
// we need only Child Apps deps, host app shared modules is always loaded on the client
|
|
6
|
+
// and we need to get only used shared modules, `loaded` flag means that module was required by MF runtime
|
|
7
|
+
// https://github.com/webpack/webpack/blob/97d4961cd1de9c69dba0f050a63f3b56bb64fab2/lib/sharing/ConsumeSharedRuntimeModule.js#L104
|
|
8
|
+
if (from.startsWith('child-app') && !!loaded) {
|
|
9
|
+
const sharedModule = sharedModules.find((m) => m.from === from && m.provides?.[0]?.shareKey === shareKey);
|
|
10
|
+
if (sharedModule) {
|
|
11
|
+
result.push({
|
|
12
|
+
shareKey,
|
|
13
|
+
from: sharedScopeItem.from,
|
|
14
|
+
eager,
|
|
15
|
+
version: sharedScopeItem.version,
|
|
16
|
+
childAppName: sharedModule?.childAppName,
|
|
17
|
+
childAppVersion: sharedModule?.childAppVersion,
|
|
18
|
+
chunks: sharedModule?.chunks,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { resolveBestLoadedSharedModules };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
function resolveBestLoadedSharedModules({ sharedModules, sharedScopeItems, }) {
|
|
6
|
+
const result = [];
|
|
7
|
+
for (const sharedScopeItem of sharedScopeItems) {
|
|
8
|
+
const { shareKey, from, eager, loaded } = sharedScopeItem;
|
|
9
|
+
// we need only Child Apps deps, host app shared modules is always loaded on the client
|
|
10
|
+
// and we need to get only used shared modules, `loaded` flag means that module was required by MF runtime
|
|
11
|
+
// https://github.com/webpack/webpack/blob/97d4961cd1de9c69dba0f050a63f3b56bb64fab2/lib/sharing/ConsumeSharedRuntimeModule.js#L104
|
|
12
|
+
if (from.startsWith('child-app') && !!loaded) {
|
|
13
|
+
const sharedModule = sharedModules.find((m) => m.from === from && m.provides?.[0]?.shareKey === shareKey);
|
|
14
|
+
if (sharedModule) {
|
|
15
|
+
result.push({
|
|
16
|
+
shareKey,
|
|
17
|
+
from: sharedScopeItem.from,
|
|
18
|
+
eager,
|
|
19
|
+
version: sharedScopeItem.version,
|
|
20
|
+
childAppName: sharedModule?.childAppName,
|
|
21
|
+
childAppVersion: sharedModule?.childAppVersion,
|
|
22
|
+
chunks: sharedModule?.chunks,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.resolveBestLoadedSharedModules = resolveBestLoadedSharedModules;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SharedModule, SharedScopeItem } from './utils';
|
|
2
|
+
export type SharedModuleWithChunks = {
|
|
3
|
+
shareKey: string;
|
|
4
|
+
from: string;
|
|
5
|
+
version: string;
|
|
6
|
+
eager: boolean;
|
|
7
|
+
childAppName?: string;
|
|
8
|
+
childAppVersion?: string;
|
|
9
|
+
chunks?: string[];
|
|
10
|
+
};
|
|
11
|
+
export declare function resolveBestSharedModules({ sharedModules, sharedScopeItems, }: {
|
|
12
|
+
sharedModules: SharedModule[];
|
|
13
|
+
sharedScopeItems: SharedScopeItem[];
|
|
14
|
+
}): SharedModuleWithChunks[];
|
|
15
|
+
//# sourceMappingURL=best-shared-modules.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ChildAppFinalConfig } from '@tramvai/tokens-child-app';
|
|
2
|
+
import { ModuleFederationSharedModule, ModuleFederationSharedScope, ModuleFederationSharedScopeItem } from '../../shared/webpack/moduleFederation';
|
|
3
|
+
import { ServerLoader } from '../loader';
|
|
4
|
+
export type SharedScopeItem = ModuleFederationSharedScopeItem & {
|
|
5
|
+
shareKey: string;
|
|
6
|
+
version: string;
|
|
7
|
+
};
|
|
8
|
+
export type SharedModule = ModuleFederationSharedModule & {
|
|
9
|
+
from: string;
|
|
10
|
+
childAppName: string;
|
|
11
|
+
childAppVersion: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function getFlatSharedScopeItemsList(sharedScope: ModuleFederationSharedScope): SharedScopeItem[];
|
|
14
|
+
export declare function getFlatSharedModulesList({ preloadedConfigs, loader, }: {
|
|
15
|
+
preloadedConfigs: ChildAppFinalConfig[];
|
|
16
|
+
loader: ServerLoader;
|
|
17
|
+
}): SharedModule[];
|
|
18
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function getFlatSharedScopeItemsList(sharedScope) {
|
|
2
|
+
// flat list of all shared items initialized in shared scope
|
|
3
|
+
const sharedScopeItems = [];
|
|
4
|
+
for (const shareKey in sharedScope) {
|
|
5
|
+
const sharedDependency = sharedScope[shareKey];
|
|
6
|
+
for (const version in sharedDependency) {
|
|
7
|
+
const sharedScopeItem = sharedDependency[version];
|
|
8
|
+
sharedScopeItems.push({
|
|
9
|
+
...sharedScopeItem,
|
|
10
|
+
shareKey,
|
|
11
|
+
version,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return sharedScopeItems;
|
|
16
|
+
}
|
|
17
|
+
function getFlatSharedModulesList({ preloadedConfigs, loader, }) {
|
|
18
|
+
const sharedModules = [];
|
|
19
|
+
for (const config of preloadedConfigs) {
|
|
20
|
+
const stats = 'getStats' in loader ? loader.getStats(config) : undefined;
|
|
21
|
+
const from = `child-app:${config.name}:${config.version}`;
|
|
22
|
+
if (stats && stats.federatedModules) {
|
|
23
|
+
for (const federatedModule of stats.federatedModules) {
|
|
24
|
+
for (const sharedModule of federatedModule.sharedModules) {
|
|
25
|
+
sharedModules.push({
|
|
26
|
+
...sharedModule,
|
|
27
|
+
from,
|
|
28
|
+
childAppName: config.name,
|
|
29
|
+
childAppVersion: config.version,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return sharedModules;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { getFlatSharedModulesList, getFlatSharedScopeItemsList };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
function getFlatSharedScopeItemsList(sharedScope) {
|
|
6
|
+
// flat list of all shared items initialized in shared scope
|
|
7
|
+
const sharedScopeItems = [];
|
|
8
|
+
for (const shareKey in sharedScope) {
|
|
9
|
+
const sharedDependency = sharedScope[shareKey];
|
|
10
|
+
for (const version in sharedDependency) {
|
|
11
|
+
const sharedScopeItem = sharedDependency[version];
|
|
12
|
+
sharedScopeItems.push({
|
|
13
|
+
...sharedScopeItem,
|
|
14
|
+
shareKey,
|
|
15
|
+
version,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return sharedScopeItems;
|
|
20
|
+
}
|
|
21
|
+
function getFlatSharedModulesList({ preloadedConfigs, loader, }) {
|
|
22
|
+
const sharedModules = [];
|
|
23
|
+
for (const config of preloadedConfigs) {
|
|
24
|
+
const stats = 'getStats' in loader ? loader.getStats(config) : undefined;
|
|
25
|
+
const from = `child-app:${config.name}:${config.version}`;
|
|
26
|
+
if (stats && stats.federatedModules) {
|
|
27
|
+
for (const federatedModule of stats.federatedModules) {
|
|
28
|
+
for (const sharedModule of federatedModule.sharedModules) {
|
|
29
|
+
sharedModules.push({
|
|
30
|
+
...sharedModule,
|
|
31
|
+
from,
|
|
32
|
+
childAppName: config.name,
|
|
33
|
+
childAppVersion: config.version,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return sharedModules;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.getFlatSharedModulesList = getFlatSharedModulesList;
|
|
43
|
+
exports.getFlatSharedScopeItemsList = getFlatSharedScopeItemsList;
|