@tramvai/module-child-app 3.27.5 → 3.31.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.
Files changed (33) hide show
  1. package/lib/server/loader.d.ts +5 -3
  2. package/lib/server/loader.es.js +25 -3
  3. package/lib/server/loader.js +29 -3
  4. package/lib/server/providers.es.js +5 -3
  5. package/lib/server/providers.js +3 -1
  6. package/lib/server/render-slots.d.ts +5 -4
  7. package/lib/server/render-slots.es.js +16 -6
  8. package/lib/server/render-slots.js +16 -6
  9. package/lib/shared/child/extractorProviders.browser.browser.js +3 -0
  10. package/lib/shared/child/extractorProviders.browser.d.ts +2 -0
  11. package/lib/shared/child/extractorProviders.d.ts +6 -0
  12. package/lib/shared/child/extractorProviders.es.js +14 -0
  13. package/lib/shared/child/extractorProviders.js +18 -0
  14. package/lib/shared/child/providers.browser.js +3 -1
  15. package/lib/shared/child/providers.d.ts +2 -1
  16. package/lib/shared/child/providers.es.js +3 -1
  17. package/lib/shared/child/providers.js +3 -1
  18. package/lib/shared/di.browser.js +1 -0
  19. package/lib/shared/di.es.js +2 -1
  20. package/lib/shared/di.js +2 -1
  21. package/lib/shared/providers.browser.js +1 -0
  22. package/lib/shared/providers.es.js +1 -0
  23. package/lib/shared/providers.js +1 -0
  24. package/lib/shared/react/component.browser.js +3 -1
  25. package/lib/shared/react/component.es.js +3 -1
  26. package/lib/shared/react/component.js +3 -1
  27. package/lib/shared/react/extractor.browser.browser.js +5 -0
  28. package/lib/shared/react/extractor.browser.d.ts +3 -0
  29. package/lib/shared/react/extractor.d.ts +6 -0
  30. package/lib/shared/react/extractor.es.js +15 -0
  31. package/lib/shared/react/extractor.js +19 -0
  32. package/lib/shared/webpack/moduleFederation.d.ts +3 -0
  33. package/package.json +14 -11
@@ -1,20 +1,22 @@
1
1
  import type { ChildApp } from '@tramvai/child-app-core';
2
2
  import type { ChildAppFinalConfig } from '@tramvai/tokens-child-app';
3
- import type { CREATE_CACHE_TOKEN, LOGGER_TOKEN } from '@tramvai/tokens-common';
3
+ import type { CREATE_CACHE_TOKEN, LOGGER_TOKEN, ENV_MANAGER_TOKEN } from '@tramvai/tokens-common';
4
4
  import { Loader } from '../shared/loader';
5
- import type { ModuleFederationStats } from '../shared/webpack/moduleFederation';
5
+ import type { LoadableStats, ModuleFederationStats } from '../shared/webpack/moduleFederation';
6
6
  export declare class ServerLoader extends Loader {
7
7
  private readonly loader;
8
8
  private readonly initializedMap;
9
9
  private internalLoadCache;
10
10
  private log;
11
- constructor({ logger, createCache, }: {
11
+ constructor({ logger, createCache, envManager, }: {
12
12
  logger: typeof LOGGER_TOKEN;
13
13
  createCache: typeof CREATE_CACHE_TOKEN;
14
+ envManager: typeof ENV_MANAGER_TOKEN;
14
15
  });
15
16
  load(config: ChildAppFinalConfig): Promise<ChildApp | void>;
16
17
  init(config: ChildAppFinalConfig): Promise<void>;
17
18
  get(config: ChildAppFinalConfig): ChildApp | void;
18
19
  getStats(config: ChildAppFinalConfig): ModuleFederationStats | void;
20
+ getLoadableStats(config: ChildAppFinalConfig): LoadableStats | void;
19
21
  }
20
22
  //# sourceMappingURL=loader.d.ts.map
@@ -1,9 +1,10 @@
1
+ import isNil from '@tinkoff/utils/is/nil';
1
2
  import { ServerLoader as ServerLoader$1 } from '@tinkoff/module-loader-server';
2
3
  import { Loader } from '../shared/loader.es.js';
3
4
  import { initModuleFederation, getModuleFederation } from '../shared/webpack/moduleFederation.es.js';
4
5
 
5
6
  class ServerLoader extends Loader {
6
- constructor({ logger, createCache, }) {
7
+ constructor({ logger, createCache, envManager, }) {
7
8
  super();
8
9
  this.initializedMap = new WeakMap();
9
10
  const cache = createCache('memory', {
@@ -15,10 +16,13 @@ class ServerLoader extends Loader {
15
16
  this.loader = new ServerLoader$1({
16
17
  cache,
17
18
  log: this.log,
19
+ requestOptions: {
20
+ circuitBreakerEnabled: isNil(envManager.get('HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED')),
21
+ },
18
22
  });
19
23
  }
20
24
  async load(config) {
21
- await Promise.all([
25
+ const promises = [
22
26
  this.loader.resolveByUrl(config.server.entry, {
23
27
  codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
24
28
  displayName: config.name,
@@ -32,7 +36,19 @@ class ServerLoader extends Loader {
32
36
  })
33
37
  // we can live without stats
34
38
  .catch(() => { }),
35
- ]);
39
+ ];
40
+ if (config.client.statsLoadable) {
41
+ promises.push(this.loader
42
+ .resolveByUrl(config.client.statsLoadable, {
43
+ type: 'json',
44
+ kind: 'child-app loadable stats',
45
+ displayName: config.name,
46
+ })
47
+ // we can live without loadable stats, for backward compatibility is ok
48
+ // but hydration errors will occur when lazy component will loaded at client-side at demand
49
+ .catch(() => { }));
50
+ }
51
+ await Promise.all(promises);
36
52
  await this.init(config);
37
53
  if (config.tag === 'debug') {
38
54
  setTimeout(() => {
@@ -68,6 +84,12 @@ class ServerLoader extends Loader {
68
84
  getStats(config) {
69
85
  return this.loader.getByUrl(config.client.stats);
70
86
  }
87
+ getLoadableStats(config) {
88
+ if (!config.client.statsLoadable) {
89
+ return;
90
+ }
91
+ return this.loader.getByUrl(config.client.statsLoadable);
92
+ }
71
93
  }
72
94
 
73
95
  export { ServerLoader };
@@ -2,12 +2,17 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var isNil = require('@tinkoff/utils/is/nil');
5
6
  var moduleLoaderServer = require('@tinkoff/module-loader-server');
6
7
  var loader = require('../shared/loader.js');
7
8
  var moduleFederation = require('../shared/webpack/moduleFederation.js');
8
9
 
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ var isNil__default = /*#__PURE__*/_interopDefaultLegacy(isNil);
13
+
9
14
  class ServerLoader extends loader.Loader {
10
- constructor({ logger, createCache, }) {
15
+ constructor({ logger, createCache, envManager, }) {
11
16
  super();
12
17
  this.initializedMap = new WeakMap();
13
18
  const cache = createCache('memory', {
@@ -19,10 +24,13 @@ class ServerLoader extends loader.Loader {
19
24
  this.loader = new moduleLoaderServer.ServerLoader({
20
25
  cache,
21
26
  log: this.log,
27
+ requestOptions: {
28
+ circuitBreakerEnabled: isNil__default["default"](envManager.get('HTTP_CLIENT_CIRCUIT_BREAKER_DISABLED')),
29
+ },
22
30
  });
23
31
  }
24
32
  async load(config) {
25
- await Promise.all([
33
+ const promises = [
26
34
  this.loader.resolveByUrl(config.server.entry, {
27
35
  codePrefix: `var ASSETS_PREFIX="${config.client.baseUrl}";`,
28
36
  displayName: config.name,
@@ -36,7 +44,19 @@ class ServerLoader extends loader.Loader {
36
44
  })
37
45
  // we can live without stats
38
46
  .catch(() => { }),
39
- ]);
47
+ ];
48
+ if (config.client.statsLoadable) {
49
+ promises.push(this.loader
50
+ .resolveByUrl(config.client.statsLoadable, {
51
+ type: 'json',
52
+ kind: 'child-app loadable stats',
53
+ displayName: config.name,
54
+ })
55
+ // we can live without loadable stats, for backward compatibility is ok
56
+ // but hydration errors will occur when lazy component will loaded at client-side at demand
57
+ .catch(() => { }));
58
+ }
59
+ await Promise.all(promises);
40
60
  await this.init(config);
41
61
  if (config.tag === 'debug') {
42
62
  setTimeout(() => {
@@ -72,6 +92,12 @@ class ServerLoader extends loader.Loader {
72
92
  getStats(config) {
73
93
  return this.loader.getByUrl(config.client.stats);
74
94
  }
95
+ getLoadableStats(config) {
96
+ if (!config.client.statsLoadable) {
97
+ return;
98
+ }
99
+ return this.loader.getByUrl(config.client.statsLoadable);
100
+ }
75
101
  }
76
102
 
77
103
  exports.ServerLoader = ServerLoader;
@@ -1,8 +1,8 @@
1
1
  import { combineValidators, isUrl, endsWith } from '@tinkoff/env-validators';
2
2
  import { Scope, optional } from '@tinkoff/dippy';
3
3
  import { provide, commandLineListTokens } from '@tramvai/core';
4
- import { ENV_USED_TOKEN, LOGGER_TOKEN, CREATE_CACHE_TOKEN, STORE_TOKEN } from '@tramvai/tokens-common';
5
- import { RESOURCES_REGISTRY, RENDER_SLOTS, ResourceType, ResourceSlot, REACT_SERVER_RENDER_MODE, EXTEND_RENDER } from '@tramvai/tokens-render';
4
+ import { ENV_USED_TOKEN, LOGGER_TOKEN, CREATE_CACHE_TOKEN, ENV_MANAGER_TOKEN, STORE_TOKEN } from '@tramvai/tokens-common';
5
+ import { RESOURCES_REGISTRY, RENDER_SLOTS, ResourceType, ResourceSlot, RENDER_FLOW_AFTER_TOKEN, REACT_SERVER_RENDER_MODE, EXTEND_RENDER } from '@tramvai/tokens-render';
6
6
  import { CHILD_APP_LOADER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_DI_MANAGER_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_RENDER_MANAGER_TOKEN } from '@tramvai/tokens-child-app';
7
7
  import { safeStringify } from '@tramvai/safe-strings';
8
8
  import { ServerLoader } from './loader.es.js';
@@ -32,6 +32,7 @@ const serverProviders = [
32
32
  deps: {
33
33
  logger: LOGGER_TOKEN,
34
34
  createCache: CREATE_CACHE_TOKEN,
35
+ envManager: ENV_MANAGER_TOKEN,
35
36
  },
36
37
  }),
37
38
  provide({
@@ -72,10 +73,11 @@ const serverProviders = [
72
73
  },
73
74
  }),
74
75
  provide({
75
- provide: RENDER_SLOTS,
76
+ provide: RENDER_FLOW_AFTER_TOKEN,
76
77
  multi: true,
77
78
  useFactory: registerChildAppRenderSlots,
78
79
  deps: {
80
+ resourcesRegistry: RESOURCES_REGISTRY,
79
81
  logger: LOGGER_TOKEN,
80
82
  diManager: CHILD_APP_DI_MANAGER_TOKEN,
81
83
  resolveFullConfig: CHILD_APP_RESOLVE_CONFIG_TOKEN,
@@ -36,6 +36,7 @@ const serverProviders = [
36
36
  deps: {
37
37
  logger: tokensCommon.LOGGER_TOKEN,
38
38
  createCache: tokensCommon.CREATE_CACHE_TOKEN,
39
+ envManager: tokensCommon.ENV_MANAGER_TOKEN,
39
40
  },
40
41
  }),
41
42
  core.provide({
@@ -76,10 +77,11 @@ const serverProviders = [
76
77
  },
77
78
  }),
78
79
  core.provide({
79
- provide: tokensRender.RENDER_SLOTS,
80
+ provide: tokensRender.RENDER_FLOW_AFTER_TOKEN,
80
81
  multi: true,
81
82
  useFactory: renderSlots.registerChildAppRenderSlots,
82
83
  deps: {
84
+ resourcesRegistry: tokensRender.RESOURCES_REGISTRY,
83
85
  logger: tokensCommon.LOGGER_TOKEN,
84
86
  diManager: tokensChildApp.CHILD_APP_DI_MANAGER_TOKEN,
85
87
  resolveFullConfig: tokensChildApp.CHILD_APP_RESOLVE_CONFIG_TOKEN,
@@ -1,14 +1,15 @@
1
1
  import type { ExtractDependencyType } from '@tinkoff/dippy';
2
- import type { ChildAppDiManager, ChildAppLoader, ChildAppPreloadManager, CHILD_APP_RESOLVE_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
2
+ import { type ChildAppDiManager, type ChildAppLoader, type ChildAppPreloadManager, type CHILD_APP_RESOLVE_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
3
3
  import type { LOGGER_TOKEN } from '@tramvai/tokens-common';
4
- import type { PageResource, REACT_SERVER_RENDER_MODE } from '@tramvai/tokens-render';
4
+ import type { REACT_SERVER_RENDER_MODE, RESOURCES_REGISTRY } from '@tramvai/tokens-render';
5
5
  import type { ServerLoader } from './loader';
6
- export declare const registerChildAppRenderSlots: ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, }: {
6
+ export declare const registerChildAppRenderSlots: ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, resourcesRegistry, }: {
7
7
  logger: ExtractDependencyType<typeof LOGGER_TOKEN>;
8
8
  diManager: ChildAppDiManager;
9
9
  resolveFullConfig: ExtractDependencyType<typeof CHILD_APP_RESOLVE_CONFIG_TOKEN>;
10
10
  preloadManager: ChildAppPreloadManager;
11
11
  loader: ChildAppLoader | ServerLoader;
12
12
  renderMode: typeof REACT_SERVER_RENDER_MODE | null;
13
- }) => PageResource[];
13
+ resourcesRegistry: ExtractDependencyType<typeof RESOURCES_REGISTRY>;
14
+ }) => () => Promise<void>;
14
15
  //# sourceMappingURL=render-slots.d.ts.map
@@ -2,6 +2,7 @@ import { extname } from 'path';
2
2
  import { gt, eq } from 'semver';
3
3
  import flatten from '@tinkoff/utils/array/flatten';
4
4
  import { resolve } from '@tinkoff/url';
5
+ import { CHILD_APP_INTERNAL_CHUNK_EXTRACTOR } from '@tramvai/tokens-child-app';
5
6
  import { RENDER_SLOTS, ResourceType, ResourceSlot } from '@tramvai/tokens-render';
6
7
  import { getSharedScope } from '../shared/webpack/moduleFederation.es.js';
7
8
 
@@ -13,7 +14,7 @@ const deferScriptAttrs = {
13
14
  defer: 'defer',
14
15
  async: null,
15
16
  };
16
- const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, }) => {
17
+ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, resourcesRegistry, }) => async () => {
17
18
  const log = logger('child-app:render:slots');
18
19
  const result = [];
19
20
  // defer scripts is not suitable for React streaming, we need to ability to run them as early as possible
@@ -28,7 +29,8 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
28
29
  case '.js':
29
30
  result.push({
30
31
  type: ResourceType.script,
31
- slot: ResourceSlot.HEAD_CORE_SCRIPTS,
32
+ // we need to load Child Apps scripts before main application scripts
33
+ slot: ResourceSlot.HEAD_DYNAMIC_SCRIPTS,
32
34
  payload: entry,
33
35
  attrs: {
34
36
  'data-critical': 'true',
@@ -76,23 +78,31 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
76
78
  }
77
79
  // eslint-disable-next-line max-statements
78
80
  preloadedList.forEach((requestConfig) => {
79
- var _a, _b, _c;
81
+ var _a, _b, _c, _d;
80
82
  const config = resolveFullConfig(requestConfig);
81
83
  if (!config) {
82
84
  return;
83
85
  }
84
86
  const stats = 'getStats' in loader ? loader.getStats(config) : undefined;
85
87
  const di = diManager.getChildDi(config);
88
+ const loadableAssets = (_a = di === null || di === void 0 ? void 0 : di.get(CHILD_APP_INTERNAL_CHUNK_EXTRACTOR)) === null || _a === void 0 ? void 0 : _a.getMainAssets();
86
89
  addChunk(config.client.entry);
87
90
  if (config.css) {
88
91
  addChunk(config.css.entry);
89
92
  }
93
+ loadableAssets === null || loadableAssets === void 0 ? void 0 : loadableAssets.map((asset) => resolve(config.client.baseUrl, asset.filename)).filter((file) => {
94
+ var _a;
95
+ // filter entry js and css chunks
96
+ return config.client.entry !== file && ((_a = config.css) === null || _a === void 0 ? void 0 : _a.entry) !== file;
97
+ }).forEach((file) => {
98
+ addChunk(file);
99
+ });
90
100
  if (stats && stats.federatedModules) {
91
101
  for (const federatedModule of stats.federatedModules) {
92
102
  // entries are duplicated in the `exposes` field of federated stats for some reason
93
103
  // for now there anyway should be only one exposed entry so took the first available
94
104
  const files = new Set();
95
- (_b = (_a = federatedModule === null || federatedModule === void 0 ? void 0 : federatedModule.exposes) === null || _a === void 0 ? void 0 : _a.entry) === null || _b === void 0 ? void 0 : _b.forEach((entry) => {
105
+ (_c = (_b = federatedModule === null || federatedModule === void 0 ? void 0 : federatedModule.exposes) === null || _b === void 0 ? void 0 : _b.entry) === null || _c === void 0 ? void 0 : _c.forEach((entry) => {
96
106
  for (const key in entry) {
97
107
  entry[key].forEach((file) => files.add(file));
98
108
  }
@@ -101,7 +111,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
101
111
  addChunk(resolve(config.client.baseUrl, file));
102
112
  }
103
113
  for (const sharedModule of federatedModule.sharedModules) {
104
- const { shareKey } = (_c = sharedModule.provides) === null || _c === void 0 ? void 0 : _c[0];
114
+ const { shareKey } = (_d = sharedModule.provides) === null || _d === void 0 ? void 0 : _d[0];
105
115
  const { chunks } = sharedModule;
106
116
  const bestShared = mapSharedToChildApp.get(shareKey);
107
117
  if (!(bestShared === null || bestShared === void 0 ? void 0 : bestShared.eager) && (bestShared === null || bestShared === void 0 ? void 0 : bestShared.name) === config.name) {
@@ -133,7 +143,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
133
143
  });
134
144
  }
135
145
  });
136
- return result;
146
+ result.map((item) => resourcesRegistry.register(item));
137
147
  };
138
148
 
139
149
  export { registerChildAppRenderSlots };
@@ -6,6 +6,7 @@ var path = require('path');
6
6
  var semver = require('semver');
7
7
  var flatten = require('@tinkoff/utils/array/flatten');
8
8
  var url = require('@tinkoff/url');
9
+ var tokensChildApp = require('@tramvai/tokens-child-app');
9
10
  var tokensRender = require('@tramvai/tokens-render');
10
11
  var moduleFederation = require('../shared/webpack/moduleFederation.js');
11
12
 
@@ -21,7 +22,7 @@ const deferScriptAttrs = {
21
22
  defer: 'defer',
22
23
  async: null,
23
24
  };
24
- const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, }) => {
25
+ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, preloadManager, loader, renderMode, resourcesRegistry, }) => async () => {
25
26
  const log = logger('child-app:render:slots');
26
27
  const result = [];
27
28
  // defer scripts is not suitable for React streaming, we need to ability to run them as early as possible
@@ -36,7 +37,8 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
36
37
  case '.js':
37
38
  result.push({
38
39
  type: tokensRender.ResourceType.script,
39
- slot: tokensRender.ResourceSlot.HEAD_CORE_SCRIPTS,
40
+ // we need to load Child Apps scripts before main application scripts
41
+ slot: tokensRender.ResourceSlot.HEAD_DYNAMIC_SCRIPTS,
40
42
  payload: entry,
41
43
  attrs: {
42
44
  'data-critical': 'true',
@@ -84,23 +86,31 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
84
86
  }
85
87
  // eslint-disable-next-line max-statements
86
88
  preloadedList.forEach((requestConfig) => {
87
- var _a, _b, _c;
89
+ var _a, _b, _c, _d;
88
90
  const config = resolveFullConfig(requestConfig);
89
91
  if (!config) {
90
92
  return;
91
93
  }
92
94
  const stats = 'getStats' in loader ? loader.getStats(config) : undefined;
93
95
  const di = diManager.getChildDi(config);
96
+ const loadableAssets = (_a = di === null || di === void 0 ? void 0 : di.get(tokensChildApp.CHILD_APP_INTERNAL_CHUNK_EXTRACTOR)) === null || _a === void 0 ? void 0 : _a.getMainAssets();
94
97
  addChunk(config.client.entry);
95
98
  if (config.css) {
96
99
  addChunk(config.css.entry);
97
100
  }
101
+ loadableAssets === null || loadableAssets === void 0 ? void 0 : loadableAssets.map((asset) => url.resolve(config.client.baseUrl, asset.filename)).filter((file) => {
102
+ var _a;
103
+ // filter entry js and css chunks
104
+ return config.client.entry !== file && ((_a = config.css) === null || _a === void 0 ? void 0 : _a.entry) !== file;
105
+ }).forEach((file) => {
106
+ addChunk(file);
107
+ });
98
108
  if (stats && stats.federatedModules) {
99
109
  for (const federatedModule of stats.federatedModules) {
100
110
  // entries are duplicated in the `exposes` field of federated stats for some reason
101
111
  // for now there anyway should be only one exposed entry so took the first available
102
112
  const files = new Set();
103
- (_b = (_a = federatedModule === null || federatedModule === void 0 ? void 0 : federatedModule.exposes) === null || _a === void 0 ? void 0 : _a.entry) === null || _b === void 0 ? void 0 : _b.forEach((entry) => {
113
+ (_c = (_b = federatedModule === null || federatedModule === void 0 ? void 0 : federatedModule.exposes) === null || _b === void 0 ? void 0 : _b.entry) === null || _c === void 0 ? void 0 : _c.forEach((entry) => {
104
114
  for (const key in entry) {
105
115
  entry[key].forEach((file) => files.add(file));
106
116
  }
@@ -109,7 +119,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
109
119
  addChunk(url.resolve(config.client.baseUrl, file));
110
120
  }
111
121
  for (const sharedModule of federatedModule.sharedModules) {
112
- const { shareKey } = (_c = sharedModule.provides) === null || _c === void 0 ? void 0 : _c[0];
122
+ const { shareKey } = (_d = sharedModule.provides) === null || _d === void 0 ? void 0 : _d[0];
113
123
  const { chunks } = sharedModule;
114
124
  const bestShared = mapSharedToChildApp.get(shareKey);
115
125
  if (!(bestShared === null || bestShared === void 0 ? void 0 : bestShared.eager) && (bestShared === null || bestShared === void 0 ? void 0 : bestShared.name) === config.name) {
@@ -141,7 +151,7 @@ const registerChildAppRenderSlots = ({ logger, diManager, resolveFullConfig, pre
141
151
  });
142
152
  }
143
153
  });
144
- return result;
154
+ result.map((item) => resourcesRegistry.register(item));
145
155
  };
146
156
 
147
157
  exports.registerChildAppRenderSlots = registerChildAppRenderSlots;
@@ -0,0 +1,3 @@
1
+ const extractorProviders = () => [];
2
+
3
+ export { extractorProviders };
@@ -0,0 +1,2 @@
1
+ export declare const extractorProviders: () => never[];
2
+ //# sourceMappingURL=extractorProviders.browser.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { ChunkExtractor } from '@loadable/server';
2
+ import type { LoadableStats } from '../webpack/moduleFederation';
3
+ export declare const extractorProviders: (loadableStats?: LoadableStats) => import("@tramvai/core").Provider<unknown, ChunkExtractor & {
4
+ __type?: "base token" | undefined;
5
+ }>[];
6
+ //# sourceMappingURL=extractorProviders.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { provide } from '@tramvai/core';
2
+ import { CHILD_APP_INTERNAL_CHUNK_EXTRACTOR } from '@tramvai/tokens-child-app';
3
+ import { ChunkExtractor } from '@loadable/server';
4
+
5
+ const extractorProviders = (loadableStats) => [
6
+ provide({
7
+ provide: CHILD_APP_INTERNAL_CHUNK_EXTRACTOR,
8
+ useFactory: () => {
9
+ return new ChunkExtractor({ stats: loadableStats !== null && loadableStats !== void 0 ? loadableStats : {}, entrypoints: [] });
10
+ },
11
+ }),
12
+ ];
13
+
14
+ export { extractorProviders };
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var core = require('@tramvai/core');
6
+ var tokensChildApp = require('@tramvai/tokens-child-app');
7
+ var server = require('@loadable/server');
8
+
9
+ const extractorProviders = (loadableStats) => [
10
+ core.provide({
11
+ provide: tokensChildApp.CHILD_APP_INTERNAL_CHUNK_EXTRACTOR,
12
+ useFactory: () => {
13
+ return new server.ChunkExtractor({ stats: loadableStats !== null && loadableStats !== void 0 ? loadableStats : {}, entrypoints: [] });
14
+ },
15
+ }),
16
+ ];
17
+
18
+ exports.extractorProviders = extractorProviders;
@@ -3,10 +3,12 @@ import { provide } from '@tramvai/core';
3
3
  import { ChildDispatcherContext } from '@tramvai/state';
4
4
  import { CHILD_APP_INTERNAL_ROOT_STATE_ALLOWED_STORE_TOKEN } from '@tramvai/tokens-child-app';
5
5
  import { DISPATCHER_CONTEXT_TOKEN, DISPATCHER_TOKEN, STORE_MIDDLEWARE, INITIAL_APP_STATE_TOKEN } from '@tramvai/tokens-common';
6
+ import { extractorProviders } from './extractorProviders.browser.browser.js';
6
7
 
7
- const getChildProviders = (appDi) => {
8
+ const getChildProviders = (appDi, loadableStats) => {
8
9
  const parentDispatcherContext = appDi.get(DISPATCHER_CONTEXT_TOKEN);
9
10
  return [
11
+ ...extractorProviders(),
10
12
  provide({
11
13
  provide: DISPATCHER_CONTEXT_TOKEN,
12
14
  useFactory: ({ dispatcher, middlewares, initialState, parentAllowedStores }) => {
@@ -1,4 +1,5 @@
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
+ import type { LoadableStats } from '../webpack/moduleFederation';
4
+ export declare const getChildProviders: (appDi: Container, loadableStats?: LoadableStats) => Provider[];
4
5
  //# sourceMappingURL=providers.d.ts.map
@@ -3,10 +3,12 @@ import { provide } from '@tramvai/core';
3
3
  import { ChildDispatcherContext } from '@tramvai/state';
4
4
  import { CHILD_APP_INTERNAL_ROOT_STATE_ALLOWED_STORE_TOKEN } from '@tramvai/tokens-child-app';
5
5
  import { DISPATCHER_CONTEXT_TOKEN, DISPATCHER_TOKEN, STORE_MIDDLEWARE, INITIAL_APP_STATE_TOKEN } from '@tramvai/tokens-common';
6
+ import { extractorProviders } from './extractorProviders.es.js';
6
7
 
7
- const getChildProviders = (appDi) => {
8
+ const getChildProviders = (appDi, loadableStats) => {
8
9
  const parentDispatcherContext = appDi.get(DISPATCHER_CONTEXT_TOKEN);
9
10
  return [
11
+ ...extractorProviders(loadableStats),
10
12
  provide({
11
13
  provide: DISPATCHER_CONTEXT_TOKEN,
12
14
  useFactory: ({ dispatcher, middlewares, initialState, parentAllowedStores }) => {
@@ -7,14 +7,16 @@ var core = require('@tramvai/core');
7
7
  var state = require('@tramvai/state');
8
8
  var tokensChildApp = require('@tramvai/tokens-child-app');
9
9
  var tokensCommon = require('@tramvai/tokens-common');
10
+ var extractorProviders = require('./extractorProviders.js');
10
11
 
11
12
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
12
13
 
13
14
  var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
14
15
 
15
- const getChildProviders = (appDi) => {
16
+ const getChildProviders = (appDi, loadableStats) => {
16
17
  const parentDispatcherContext = appDi.get(tokensCommon.DISPATCHER_CONTEXT_TOKEN);
17
18
  return [
19
+ ...extractorProviders.extractorProviders(loadableStats),
18
20
  core.provide({
19
21
  provide: tokensCommon.DISPATCHER_CONTEXT_TOKEN,
20
22
  useFactory: ({ dispatcher, middlewares, initialState, parentAllowedStores }) => {
@@ -32,6 +32,7 @@ class DiManager {
32
32
  return;
33
33
  }
34
34
  const di = new ChildContainer(singletonDi, this.appDi);
35
+ 'getLoadableStats' in this.loader ? this.loader.getLoadableStats(config) : undefined;
35
36
  // add providers on the Request Level to make it possible to reuse providers from the root-app ChildContainer
36
37
  const childProviders = getChildProviders(this.appDi);
37
38
  childProviders.forEach((provider) => {
@@ -32,8 +32,9 @@ class DiManager {
32
32
  return;
33
33
  }
34
34
  const di = new ChildContainer(singletonDi, this.appDi);
35
+ const statsLoadable = 'getLoadableStats' in this.loader ? this.loader.getLoadableStats(config) : undefined;
35
36
  // add providers on the Request Level to make it possible to reuse providers from the root-app ChildContainer
36
- const childProviders = getChildProviders(this.appDi);
37
+ const childProviders = getChildProviders(this.appDi, statsLoadable);
37
38
  childProviders.forEach((provider) => {
38
39
  di.register(provider);
39
40
  });
package/lib/shared/di.js CHANGED
@@ -36,8 +36,9 @@ class DiManager {
36
36
  return;
37
37
  }
38
38
  const di = new dippy.ChildContainer(singletonDi, this.appDi);
39
+ const statsLoadable = 'getLoadableStats' in this.loader ? this.loader.getLoadableStats(config) : undefined;
39
40
  // add providers on the Request Level to make it possible to reuse providers from the root-app ChildContainer
40
- const childProviders = providers.getChildProviders(this.appDi);
41
+ const childProviders = providers.getChildProviders(this.appDi, statsLoadable);
41
42
  childProviders.forEach((provider) => {
42
43
  di.register(provider);
43
44
  });
@@ -81,6 +81,7 @@ const sharedProviders = [
81
81
  baseUrl: `${baseUrl}${name}/`,
82
82
  entry: `${baseUrl}${name}/${name}_client@${version}.js`,
83
83
  stats: `${baseUrl}${name}/${name}_stats@${version}.json`,
84
+ statsLoadable: `${baseUrl}${name}/${name}_stats_loadable@${version}.json`,
84
85
  ...client,
85
86
  },
86
87
  css: withoutCss
@@ -81,6 +81,7 @@ const sharedProviders = [
81
81
  baseUrl: `${baseUrl}${name}/`,
82
82
  entry: `${baseUrl}${name}/${name}_client@${version}.js`,
83
83
  stats: `${baseUrl}${name}/${name}_stats@${version}.json`,
84
+ statsLoadable: `${baseUrl}${name}/${name}_stats_loadable@${version}.json`,
84
85
  ...client,
85
86
  },
86
87
  css: withoutCss
@@ -85,6 +85,7 @@ const sharedProviders = [
85
85
  baseUrl: `${baseUrl}${name}/`,
86
86
  entry: `${baseUrl}${name}/${name}_client@${version}.js`,
87
87
  stats: `${baseUrl}${name}/${name}_stats@${version}.json`,
88
+ statsLoadable: `${baseUrl}${name}/${name}_stats_loadable@${version}.json`,
88
89
  ...client,
89
90
  },
90
91
  css: withoutCss
@@ -5,6 +5,7 @@ import { CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
5
5
  import { LOGGER_TOKEN } from '@tramvai/tokens-common';
6
6
  import { UniversalErrorBoundary, useDi } from '@tramvai/react';
7
7
  import { RenderContext } from './render-context.browser.js';
8
+ import { Extractor } from './extractor.browser.browser.js';
8
9
 
9
10
  const FailedChildAppFallback = ({ config: { name, version, tag, fallback: Fallback }, }) => {
10
11
  const logger = useDi(LOGGER_TOKEN);
@@ -28,6 +29,7 @@ const FailedChildAppFallback = ({ config: { name, version, tag, fallback: Fallba
28
29
  }
29
30
  return Fallback ? jsx(Fallback, {}) : null;
30
31
  };
32
+ // eslint-disable-next-line max-statements
31
33
  const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
32
34
  const renderManager = useContext(RenderContext);
33
35
  const logger = useDi(LOGGER_TOKEN);
@@ -76,7 +78,7 @@ const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) =>
76
78
  });
77
79
  return null;
78
80
  }
79
- return jsx(Cmp, { di: di, props: props });
81
+ return (jsx(Extractor, { di: di, children: jsx(Cmp, { di: di, props: props }) }));
80
82
  }
81
83
  catch (error) {
82
84
  log.error({
@@ -5,6 +5,7 @@ import { CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
5
5
  import { LOGGER_TOKEN } from '@tramvai/tokens-common';
6
6
  import { UniversalErrorBoundary, useDi } from '@tramvai/react';
7
7
  import { RenderContext } from './render-context.es.js';
8
+ import { Extractor } from './extractor.es.js';
8
9
 
9
10
  const FailedChildAppFallback = ({ config: { name, version, tag, fallback: Fallback }, }) => {
10
11
  const logger = useDi(LOGGER_TOKEN);
@@ -28,6 +29,7 @@ const FailedChildAppFallback = ({ config: { name, version, tag, fallback: Fallba
28
29
  }
29
30
  return Fallback ? jsx(Fallback, {}) : null;
30
31
  };
32
+ // eslint-disable-next-line max-statements
31
33
  const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
32
34
  const renderManager = useContext(RenderContext);
33
35
  const logger = useDi(LOGGER_TOKEN);
@@ -76,7 +78,7 @@ const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) =>
76
78
  });
77
79
  return null;
78
80
  }
79
- return jsx(Cmp, { di: di, props: props });
81
+ return (jsx(Extractor, { di: di, children: jsx(Cmp, { di: di, props: props }) }));
80
82
  }
81
83
  catch (error) {
82
84
  log.error({
@@ -9,6 +9,7 @@ var tokensChildApp = require('@tramvai/tokens-child-app');
9
9
  var tokensCommon = require('@tramvai/tokens-common');
10
10
  var react$1 = require('@tramvai/react');
11
11
  var renderContext = require('./render-context.js');
12
+ var extractor = require('./extractor.js');
12
13
 
13
14
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
15
 
@@ -36,6 +37,7 @@ const FailedChildAppFallback = ({ config: { name, version, tag, fallback: Fallba
36
37
  }
37
38
  return Fallback ? jsxRuntime.jsx(Fallback, {}) : null;
38
39
  };
40
+ // eslint-disable-next-line max-statements
39
41
  const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) => {
40
42
  const renderManager = react.useContext(renderContext.RenderContext);
41
43
  const logger = react$1.useDi(tokensCommon.LOGGER_TOKEN);
@@ -84,7 +86,7 @@ const ChildAppWrapper = ({ name, version, tag, props, fallback: Fallback, }) =>
84
86
  });
85
87
  return null;
86
88
  }
87
- return jsxRuntime.jsx(Cmp, { di: di, props: props });
89
+ return (jsxRuntime.jsx(extractor.Extractor, { di: di, children: jsxRuntime.jsx(Cmp, { di: di, props: props }) }));
88
90
  }
89
91
  catch (error) {
90
92
  log.error({
@@ -0,0 +1,5 @@
1
+ const Extractor = ({ children }) => {
2
+ return children;
3
+ };
4
+
5
+ export { Extractor };
@@ -0,0 +1,3 @@
1
+ import type { PropsWithChildren } from 'react';
2
+ export declare const Extractor: ({ children }: PropsWithChildren<{}>) => import("react").ReactNode;
3
+ //# sourceMappingURL=extractor.browser.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { type Container } from '@tinkoff/dippy';
2
+ import type { ComponentType, PropsWithChildren } from 'react';
3
+ export declare const Extractor: ComponentType<PropsWithChildren<{
4
+ di: Container;
5
+ }>>;
6
+ //# sourceMappingURL=extractor.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { ChunkExtractorManager } from '@loadable/server';
2
+ import { optional } from '@tinkoff/dippy';
3
+ import { CHILD_APP_INTERNAL_CHUNK_EXTRACTOR } from '@tramvai/tokens-child-app';
4
+ import { createElement } from 'react';
5
+
6
+ // Use `.ts` file, not `.tsx` because `@tramvai/build` expect only `.ts` source files extension if file is used in package.json `browser` field
7
+ const Extractor = ({ children, di, }) => {
8
+ const extractor = di.get(optional(CHILD_APP_INTERNAL_CHUNK_EXTRACTOR));
9
+ if (!extractor) {
10
+ return children;
11
+ }
12
+ return createElement(ChunkExtractorManager, { extractor }, children);
13
+ };
14
+
15
+ export { Extractor };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var server = require('@loadable/server');
6
+ var dippy = require('@tinkoff/dippy');
7
+ var tokensChildApp = require('@tramvai/tokens-child-app');
8
+ var react = require('react');
9
+
10
+ // Use `.ts` file, not `.tsx` because `@tramvai/build` expect only `.ts` source files extension if file is used in package.json `browser` field
11
+ const Extractor = ({ children, di, }) => {
12
+ const extractor = di.get(dippy.optional(tokensChildApp.CHILD_APP_INTERNAL_CHUNK_EXTRACTOR));
13
+ if (!extractor) {
14
+ return children;
15
+ }
16
+ return react.createElement(server.ChunkExtractorManager, { extractor }, children);
17
+ };
18
+
19
+ exports.Extractor = Extractor;
@@ -42,6 +42,9 @@ export interface ModuleFederationStats {
42
42
  exposes: Record<string, Array<Record<string, string[]>>>;
43
43
  }>;
44
44
  }
45
+ export interface LoadableStats {
46
+ [key: string]: any;
47
+ }
45
48
  export declare const getSharedScope: (scope?: string) => ModuleFederationSharedScope;
46
49
  export declare const initModuleFederation: (container?: ModuleFederationContainer, scope?: string) => Promise<void>;
47
50
  export declare const getModuleFederation: (container: ModuleFederationContainer, name?: string) => Promise<unknown>;
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@tramvai/module-child-app",
3
- "version": "3.27.5",
3
+ "version": "3.31.0",
4
4
  "description": "Module for child apps",
5
5
  "browser": {
6
6
  "./lib/server.js": "./lib/browser.js",
7
7
  "./lib/server/child/singletonProviders.js": "./lib/browser/child/singletonProviders.js",
8
8
  "./lib/server/child/providers.js": "./lib/browser/child/providers.js",
9
+ "./lib/shared/react/extractor.js": "./lib/shared/react/extractor.browser.js",
10
+ "./lib/shared/child/extractorProviders.js": "./lib/shared/child/extractorProviders.browser.js",
9
11
  "./lib/server.es.js": "./lib/browser.js"
10
12
  },
11
13
  "main": "lib/server.js",
@@ -27,25 +29,26 @@
27
29
  "registry": "https://registry.npmjs.org/"
28
30
  },
29
31
  "dependencies": {
32
+ "@loadable/server": "^5.15.0",
30
33
  "@tinkoff/env-validators": "0.2.1",
31
34
  "@tinkoff/module-loader-client": "0.5.1",
32
- "@tinkoff/module-loader-server": "0.6.2",
35
+ "@tinkoff/module-loader-server": "0.6.3",
33
36
  "@tinkoff/url": "0.9.2",
34
- "@tramvai/child-app-core": "3.27.5",
37
+ "@tramvai/child-app-core": "3.31.0",
35
38
  "@tramvai/safe-strings": "0.6.2",
36
- "@tramvai/tokens-child-app": "3.27.5"
39
+ "@tramvai/tokens-child-app": "3.31.0"
37
40
  },
38
41
  "devDependencies": {},
39
42
  "peerDependencies": {
40
43
  "@tinkoff/dippy": "0.9.2",
41
- "@tinkoff/router": "0.3.52",
44
+ "@tinkoff/router": "0.3.57",
42
45
  "@tinkoff/utils": "^2.1.2",
43
- "@tramvai/core": "3.27.5",
44
- "@tramvai/state": "3.27.5",
45
- "@tramvai/react": "3.27.5",
46
- "@tramvai/tokens-common": "3.27.5",
47
- "@tramvai/tokens-render": "3.27.5",
48
- "@tramvai/tokens-router": "3.27.5",
46
+ "@tramvai/core": "3.31.0",
47
+ "@tramvai/state": "3.31.0",
48
+ "@tramvai/react": "3.31.0",
49
+ "@tramvai/tokens-common": "3.31.0",
50
+ "@tramvai/tokens-render": "3.31.0",
51
+ "@tramvai/tokens-router": "3.31.0",
49
52
  "react": ">=16.14.0",
50
53
  "react-dom": ">=16.14.0",
51
54
  "object-assign": "^4.1.1",