@tramvai/module-child-app 1.66.0 → 1.68.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -129,14 +129,70 @@ State for child-apps will be dehydrated on server as separate variable in the re
129
129
 
130
130
  Usually child-app cannot read data from root-app stores, but the dangerous workaround that allows to subscribe on any root-app store exists.
131
131
 
132
- It may be done using `CHILD_APP_ROOT_STATE_SUBSCRIPTION_TOKEN` token.
132
+ It may be done using `CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN` token.
133
133
 
134
- This token is considered dangerous as it leads to high coupling with stores from root-app and this way stores in root-app might not change their public interface. But, in most cases, changes in stores ignore breaking change tracking and often breaks backward-compatibility. So **do not use this token if you can**, and if you should - use as little as possible from root-app and provide some fallback in case of wrong data.
134
+ This token is considered dangerous as it leads to high coupling with stores from root-app and this way stores in root-app might not change their public interface. But, in most cases, changes in stores ignore breaking change tracking and often breaks backward-compatibility. So **do not use this token if you can**, and if you should - use as little as possible from root-app and provide some fallback in case of wrong data.
135
+
136
+ [See how to do it](#child_app_internal_root_state_subscription_token)
135
137
 
136
138
  :::
137
139
 
138
140
  ## API
139
141
 
142
+ ### CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN
143
+
144
+ Allows to subscribe to any store from the root app and execute actions based on its state, e.g. to fill internal child-app state.
145
+
146
+ 1. Create a new store and a new event within child-app. This store might be used inside child-app as usual store.
147
+
148
+ ```ts
149
+ import { createReducer, createEvent } from '@tramvai/state';
150
+
151
+ interface State {
152
+ value: string;
153
+ }
154
+ export const setRootState = createEvent<string>('child-root set state');
155
+
156
+ export const rootStore = createReducer('child-root', { value: 'child' } as State).on(
157
+ setRootState,
158
+ (state, value) => {
159
+ return { value };
160
+ }
161
+ );
162
+ ```
163
+
164
+ 2. Add provider for the `CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN` in order to subscribe to store. In subscription you can dispatch internal event from the child-app
165
+
166
+ ```ts
167
+ provide({
168
+ provide: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN,
169
+ multi: true,
170
+ useFactory: ({ context }) => {
171
+ return {
172
+ stores: ['root'],
173
+ listener: (state: Record<string, any>) => {
174
+ return context.dispatch(setRootState(`root ${state.root.value}`));
175
+ },
176
+ };
177
+ },
178
+ deps: {
179
+ context: CONTEXT_TOKEN,
180
+ },
181
+ });
182
+ ```
183
+
184
+ 3. Use internal child-app store anywhere in the child-app
185
+
186
+ ```tsx
187
+ export const StateCmp = () => {
188
+ const value = useSelector([rootStore], (state) => {
189
+ return state['child-root'].value;
190
+ });
191
+
192
+ return <div id="child-state">Current Value from Root Store: {value}</div>;
193
+ };
194
+ ```
195
+
140
196
  ## How to
141
197
 
142
198
  ### Connect a child app
@@ -1,3 +1,3 @@
1
1
  import type { Container } from '@tinkoff/dippy';
2
2
  import type { Provider } from '@tramvai/core';
3
- export declare const getChildProviders: (appDi: Container) => Provider[];
3
+ export declare const getChildProviders: (_: Container) => Provider[];
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
@@ -2,8 +2,9 @@ import type { CUSTOM_RENDER } from '@tramvai/tokens-render';
2
2
  import type { Container } from '@tinkoff/dippy';
3
3
  import type { ChildAppDiManager, ChildAppPreloadManager, ChildAppRenderManager, ChildAppRequestConfig, CHILD_APP_RESOLVE_CONFIG_TOKEN } from '@tramvai/tokens-child-app';
4
4
  import type { LOGGER_TOKEN } from '@tramvai/tokens-common';
5
- export declare const customRender: ({ renderManager, }: {
5
+ export declare const customRender: ({ renderManager, diManager, }: {
6
6
  renderManager: ChildAppRenderManager;
7
+ diManager: ChildAppDiManager;
7
8
  }) => typeof CUSTOM_RENDER;
8
9
  export declare class RenderManager implements ChildAppRenderManager {
9
10
  private readonly preloadManager;
@@ -14,7 +14,7 @@ import { loadModule } from '@tinkoff/module-loader-client';
14
14
  import noop from '@tinkoff/utils/function/noop';
15
15
  import { useDi } from '@tramvai/react';
16
16
 
17
- const getChildProviders$1 = (appDi) => {
17
+ const getChildProviders$3 = (appDi) => {
18
18
  const context = appDi.get(CONTEXT_TOKEN);
19
19
  return [
20
20
  {
@@ -56,7 +56,7 @@ const getChildProviders$1 = (appDi) => {
56
56
  ];
57
57
  };
58
58
 
59
- const getChildProviders = (appDi) => {
59
+ const getChildProviders$2 = (appDi) => {
60
60
  const logger = appDi.get(LOGGER_TOKEN);
61
61
  return [
62
62
  provide({
@@ -70,7 +70,7 @@ const getChildProviders = (appDi) => {
70
70
  multi: true,
71
71
  useValue: [],
72
72
  }),
73
- ...getChildProviders$1(appDi),
73
+ ...getChildProviders$3(appDi),
74
74
  ];
75
75
  };
76
76
 
@@ -137,7 +137,7 @@ class SingletonDiManager {
137
137
  },
138
138
  ], this.appDi);
139
139
  const { modules = [], providers = [], actions = [] } = children;
140
- const childProviders = getChildProviders(this.appDi);
140
+ const childProviders = getChildProviders$2(this.appDi);
141
141
  childProviders.forEach((provider) => {
142
142
  di.register(provider);
143
143
  });
@@ -171,6 +171,14 @@ class SingletonDiManager {
171
171
  }
172
172
  }
173
173
 
174
+ const getChildProviders$1 = (_) => {
175
+ return [];
176
+ };
177
+
178
+ const getChildProviders = (appDi) => {
179
+ return getChildProviders$1();
180
+ };
181
+
174
182
  class DiManager {
175
183
  constructor({ appDi, loader, singletonDiManager, }) {
176
184
  this.cache = new Map();
@@ -201,7 +209,12 @@ class DiManager {
201
209
  if (!singletonDi) {
202
210
  return;
203
211
  }
204
- return new ChildContainer(singletonDi, this.appDi);
212
+ const di = new ChildContainer(singletonDi, this.appDi);
213
+ const childProviders = getChildProviders(this.appDi);
214
+ childProviders.forEach((provider) => {
215
+ di.register(provider);
216
+ });
217
+ return di;
205
218
  }
206
219
  }
207
220
 
package/lib/server.es.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import { provide, COMMAND_LINE_RUNNER_TOKEN, walkOfModules, getModuleParameters, commandLineListTokens as commandLineListTokens$1, Module } from '@tramvai/core';
3
3
  import { Container, ChildContainer, Scope, DI_TOKEN } from '@tinkoff/dippy';
4
- import { commandLineListTokens, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
4
+ import { commandLineListTokens, CHILD_APP_INTERNAL_ACTION_TOKEN, CHILD_APP_INTERNAL_CONFIG_TOKEN, IS_CHILD_APP_DI_TOKEN, CHILD_APP_INTERNAL_ROOT_DI_BORROW_TOKEN, CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN, CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, CHILD_APP_RESOLUTION_CONFIG_MANAGER_TOKEN, CHILD_APP_RESOLUTION_CONFIGS_TOKEN, CHILD_APP_RESOLVE_CONFIG_TOKEN, CHILD_APP_RESOLVE_BASE_URL_TOKEN, CHILD_APP_SINGLETON_DI_MANAGER_TOKEN, CHILD_APP_LOADER_TOKEN, CHILD_APP_DI_MANAGER_TOKEN, CHILD_APP_COMMAND_LINE_RUNNER_TOKEN, CHILD_APP_PRELOAD_MANAGER_TOKEN, CHILD_APP_RENDER_MANAGER_TOKEN, CHILD_APP_STATE_MANAGER_TOKEN, CHILD_APP_INTERNAL_RENDER_TOKEN } from '@tramvai/tokens-child-app';
5
5
  export * from '@tramvai/tokens-child-app';
6
- import { ACTION_PAGE_RUNNER_TOKEN, CONTEXT_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
6
+ import { ACTION_PAGE_RUNNER_TOKEN, LOGGER_TOKEN, DISPATCHER_TOKEN, STORE_TOKEN, CONTEXT_TOKEN, COMBINE_REDUCERS, ENV_MANAGER_TOKEN, REGISTER_CLEAR_CACHE_TOKEN, CLEAR_CACHE_TOKEN, ENV_USED_TOKEN, CREATE_CACHE_TOKEN } from '@tramvai/tokens-common';
7
7
  import { RENDER_SLOTS, EXTEND_RENDER, ResourceType, ResourceSlot, RESOURCES_REGISTRY, CUSTOM_RENDER } from '@tramvai/tokens-render';
8
8
  import { PAGE_SERVICE_TOKEN } from '@tramvai/tokens-router';
9
9
  import flatten from '@tinkoff/utils/array/flatten';
@@ -17,27 +17,8 @@ import noop from '@tinkoff/utils/function/noop';
17
17
  import { renderToString } from 'react-dom/server';
18
18
  import { useDi } from '@tramvai/react';
19
19
 
20
- const getChildProviders$1 = (appDi) => {
21
- const context = appDi.get(CONTEXT_TOKEN);
20
+ const getChildProviders$3 = (appDi) => {
22
21
  return [
23
- {
24
- provide: commandLineListTokens.customerStart,
25
- multi: true,
26
- useFactory: ({ subscriptions, }) => {
27
- return function resolveRootStateForChild() {
28
- if (!subscriptions) {
29
- return;
30
- }
31
- const state = context.getState();
32
- return Promise.all(subscriptions.map((sub) => {
33
- return sub.listener(state);
34
- }));
35
- };
36
- },
37
- deps: {
38
- subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
39
- },
40
- },
41
22
  provide({
42
23
  provide: commandLineListTokens.resolvePageDeps,
43
24
  multi: true,
@@ -54,7 +35,7 @@ const getChildProviders$1 = (appDi) => {
54
35
  ];
55
36
  };
56
37
 
57
- const getChildProviders = (appDi) => {
38
+ const getChildProviders$2 = (appDi) => {
58
39
  const logger = appDi.get(LOGGER_TOKEN);
59
40
  return [
60
41
  provide({
@@ -68,7 +49,7 @@ const getChildProviders = (appDi) => {
68
49
  multi: true,
69
50
  useValue: [],
70
51
  }),
71
- ...getChildProviders$1(appDi),
52
+ ...getChildProviders$3(),
72
53
  ];
73
54
  };
74
55
 
@@ -135,7 +116,7 @@ class SingletonDiManager {
135
116
  },
136
117
  ], this.appDi);
137
118
  const { modules = [], providers = [], actions = [] } = children;
138
- const childProviders = getChildProviders(this.appDi);
119
+ const childProviders = getChildProviders$2(this.appDi);
139
120
  childProviders.forEach((provider) => {
140
121
  di.register(provider);
141
122
  });
@@ -169,6 +150,34 @@ class SingletonDiManager {
169
150
  }
170
151
  }
171
152
 
153
+ const getChildProviders$1 = (appDi) => {
154
+ const store = appDi.get(STORE_TOKEN);
155
+ return [
156
+ {
157
+ provide: CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN,
158
+ multi: true,
159
+ useFactory: ({ subscriptions, }) => {
160
+ return function resolveRootStateForChild() {
161
+ if (!subscriptions) {
162
+ return;
163
+ }
164
+ const state = store.getState();
165
+ return Promise.all(subscriptions.map((sub) => {
166
+ return sub.listener(state);
167
+ }));
168
+ };
169
+ },
170
+ deps: {
171
+ subscriptions: { token: CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
172
+ },
173
+ },
174
+ ];
175
+ };
176
+
177
+ const getChildProviders = (appDi) => {
178
+ return getChildProviders$1(appDi);
179
+ };
180
+
172
181
  class DiManager {
173
182
  constructor({ appDi, loader, singletonDiManager, }) {
174
183
  this.cache = new Map();
@@ -199,7 +208,12 @@ class DiManager {
199
208
  if (!singletonDi) {
200
209
  return;
201
210
  }
202
- return new ChildContainer(singletonDi, this.appDi);
211
+ const di = new ChildContainer(singletonDi, this.appDi);
212
+ const childProviders = getChildProviders(this.appDi);
213
+ childProviders.forEach((provider) => {
214
+ di.register(provider);
215
+ });
216
+ return di;
203
217
  }
204
218
  }
205
219
 
@@ -690,8 +704,16 @@ class StateManager {
690
704
  }
691
705
 
692
706
  const LOAD_TIMEOUT = 500;
693
- const customRender = ({ renderManager, }) => {
707
+ const customRender = ({ renderManager, diManager, }) => {
694
708
  return async (content) => {
709
+ const promises = [];
710
+ diManager.forEachChildDi((di) => {
711
+ const beforeAppRender = di.get(CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN);
712
+ if (beforeAppRender) {
713
+ promises.push(Promise.all(beforeAppRender.map((fn) => fn())));
714
+ }
715
+ });
716
+ await Promise.all(promises);
695
717
  let render = renderToString(content);
696
718
  let timeouted = false;
697
719
  await Promise.race([
@@ -876,6 +898,7 @@ const serverProviders = [
876
898
  useFactory: customRender,
877
899
  deps: {
878
900
  renderManager: CHILD_APP_RENDER_MANAGER_TOKEN,
901
+ diManager: CHILD_APP_DI_MANAGER_TOKEN,
879
902
  },
880
903
  }),
881
904
  provide({
package/lib/server.js CHANGED
@@ -27,27 +27,8 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
27
27
  var applyOrReturn__default = /*#__PURE__*/_interopDefaultLegacy(applyOrReturn);
28
28
  var noop__default = /*#__PURE__*/_interopDefaultLegacy(noop);
29
29
 
30
- const getChildProviders$1 = (appDi) => {
31
- const context = appDi.get(tokensCommon.CONTEXT_TOKEN);
30
+ const getChildProviders$3 = (appDi) => {
32
31
  return [
33
- {
34
- provide: tokensChildApp.commandLineListTokens.customerStart,
35
- multi: true,
36
- useFactory: ({ subscriptions, }) => {
37
- return function resolveRootStateForChild() {
38
- if (!subscriptions) {
39
- return;
40
- }
41
- const state = context.getState();
42
- return Promise.all(subscriptions.map((sub) => {
43
- return sub.listener(state);
44
- }));
45
- };
46
- },
47
- deps: {
48
- subscriptions: { token: tokensChildApp.CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
49
- },
50
- },
51
32
  core.provide({
52
33
  provide: tokensChildApp.commandLineListTokens.resolvePageDeps,
53
34
  multi: true,
@@ -64,7 +45,7 @@ const getChildProviders$1 = (appDi) => {
64
45
  ];
65
46
  };
66
47
 
67
- const getChildProviders = (appDi) => {
48
+ const getChildProviders$2 = (appDi) => {
68
49
  const logger = appDi.get(tokensCommon.LOGGER_TOKEN);
69
50
  return [
70
51
  core.provide({
@@ -78,7 +59,7 @@ const getChildProviders = (appDi) => {
78
59
  multi: true,
79
60
  useValue: [],
80
61
  }),
81
- ...getChildProviders$1(appDi),
62
+ ...getChildProviders$3(),
82
63
  ];
83
64
  };
84
65
 
@@ -145,7 +126,7 @@ class SingletonDiManager {
145
126
  },
146
127
  ], this.appDi);
147
128
  const { modules = [], providers = [], actions = [] } = children;
148
- const childProviders = getChildProviders(this.appDi);
129
+ const childProviders = getChildProviders$2(this.appDi);
149
130
  childProviders.forEach((provider) => {
150
131
  di.register(provider);
151
132
  });
@@ -179,6 +160,34 @@ class SingletonDiManager {
179
160
  }
180
161
  }
181
162
 
163
+ const getChildProviders$1 = (appDi) => {
164
+ const store = appDi.get(tokensCommon.STORE_TOKEN);
165
+ return [
166
+ {
167
+ provide: tokensChildApp.CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN,
168
+ multi: true,
169
+ useFactory: ({ subscriptions, }) => {
170
+ return function resolveRootStateForChild() {
171
+ if (!subscriptions) {
172
+ return;
173
+ }
174
+ const state = store.getState();
175
+ return Promise.all(subscriptions.map((sub) => {
176
+ return sub.listener(state);
177
+ }));
178
+ };
179
+ },
180
+ deps: {
181
+ subscriptions: { token: tokensChildApp.CHILD_APP_INTERNAL_ROOT_STATE_SUBSCRIPTION_TOKEN, optional: true },
182
+ },
183
+ },
184
+ ];
185
+ };
186
+
187
+ const getChildProviders = (appDi) => {
188
+ return getChildProviders$1(appDi);
189
+ };
190
+
182
191
  class DiManager {
183
192
  constructor({ appDi, loader, singletonDiManager, }) {
184
193
  this.cache = new Map();
@@ -209,7 +218,12 @@ class DiManager {
209
218
  if (!singletonDi) {
210
219
  return;
211
220
  }
212
- return new dippy.ChildContainer(singletonDi, this.appDi);
221
+ const di = new dippy.ChildContainer(singletonDi, this.appDi);
222
+ const childProviders = getChildProviders(this.appDi);
223
+ childProviders.forEach((provider) => {
224
+ di.register(provider);
225
+ });
226
+ return di;
213
227
  }
214
228
  }
215
229
 
@@ -700,8 +714,16 @@ class StateManager {
700
714
  }
701
715
 
702
716
  const LOAD_TIMEOUT = 500;
703
- const customRender = ({ renderManager, }) => {
717
+ const customRender = ({ renderManager, diManager, }) => {
704
718
  return async (content) => {
719
+ const promises = [];
720
+ diManager.forEachChildDi((di) => {
721
+ const beforeAppRender = di.get(tokensChildApp.CHILD_APP_INTERNAL_BEFORE_RENDER_TOKEN);
722
+ if (beforeAppRender) {
723
+ promises.push(Promise.all(beforeAppRender.map((fn) => fn())));
724
+ }
725
+ });
726
+ await Promise.all(promises);
705
727
  let render = server.renderToString(content);
706
728
  let timeouted = false;
707
729
  await Promise.race([
@@ -886,6 +908,7 @@ const serverProviders = [
886
908
  useFactory: customRender,
887
909
  deps: {
888
910
  renderManager: tokensChildApp.CHILD_APP_RENDER_MANAGER_TOKEN,
911
+ diManager: tokensChildApp.CHILD_APP_DI_MANAGER_TOKEN,
889
912
  },
890
913
  }),
891
914
  core.provide({
@@ -0,0 +1,3 @@
1
+ import type { Container } from '@tinkoff/dippy';
2
+ import type { Provider } from '@tramvai/core';
3
+ export declare const getChildProviders: (appDi: Container) => Provider[];
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@tramvai/module-child-app",
3
- "version": "1.66.0",
3
+ "version": "1.68.1",
4
4
  "description": "Module for child apps",
5
5
  "browser": {
6
6
  "./lib/server.js": "./lib/browser.js",
7
+ "./lib/server/child/singletonProviders.js": "./lib/browser/child/singletonProviders.js",
7
8
  "./lib/server/child/providers.js": "./lib/browser/child/providers.js",
8
9
  "./lib/server.es.js": "./lib/server.browser.js"
9
10
  },
@@ -30,20 +31,20 @@
30
31
  "@tinkoff/env-validators": "0.0.3",
31
32
  "@tinkoff/module-loader-client": "0.3.25",
32
33
  "@tinkoff/module-loader-server": "0.4.41",
33
- "@tramvai/child-app-core": "1.66.0",
34
+ "@tramvai/child-app-core": "1.68.1",
34
35
  "@tramvai/safe-strings": "0.4.3",
35
- "@tramvai/tokens-child-app": "1.66.0"
36
+ "@tramvai/tokens-child-app": "1.68.1"
36
37
  },
37
38
  "devDependencies": {},
38
39
  "peerDependencies": {
39
40
  "@tinkoff/dippy": "0.7.38",
40
41
  "@tinkoff/utils": "^2.1.2",
41
- "@tramvai/core": "1.66.0",
42
- "@tramvai/state": "1.66.0",
43
- "@tramvai/react": "1.66.0",
44
- "@tramvai/tokens-common": "1.66.0",
45
- "@tramvai/tokens-render": "1.66.0",
46
- "@tramvai/tokens-router": "1.66.0",
42
+ "@tramvai/core": "1.68.1",
43
+ "@tramvai/state": "1.68.1",
44
+ "@tramvai/react": "1.68.1",
45
+ "@tramvai/tokens-common": "1.68.1",
46
+ "@tramvai/tokens-render": "1.68.1",
47
+ "@tramvai/tokens-router": "1.68.1",
47
48
  "react": ">=16.8.0",
48
49
  "react-dom": ">=16.8.0",
49
50
  "object-assign": "^4.1.1",