arui-scripts 14.5.0-feat-modules.2 → 14.5.0-feat-modules.3
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/CHANGELOG.md +9 -0
- package/README.md +2 -0
- package/build/configs/app-configs/calculate-dependent-config.d.ts +2 -1
- package/build/configs/app-configs/get-defaults.js +2 -1
- package/build/configs/app-configs/types.d.ts +2 -1
- package/build/configs/dev-server.d.ts +2 -15
- package/build/configs/dev-server.js +11 -4
- package/build/configs/postcss.config.d.ts +1 -1
- package/build/tsconfig-local.tsbuildinfo +1 -1
- package/docs/modules.md +217 -201
- package/package.json +1 -1
package/docs/modules.md
CHANGED
|
@@ -1,58 +1,29 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## Мотивация
|
|
1
|
+
# Что такое модули
|
|
4
2
|
Модули приложений предназначены для решения простой проблемы - переиспользование фронтового кода между приложениями.
|
|
5
3
|
|
|
6
4
|
В целом, для того чтобы переиспользовать код у нас есть много разных способов, например:
|
|
7
5
|
- копировать код из одного приложения в другое. Быстро, но неудобно и неэффективно.
|
|
8
6
|
- выносить код в отдельный пакет и подключать его через npm. Понятный и достаточно удобный вариант,
|
|
9
|
-
но ограничивает нас в скорости изменений. Если мы хотим заменить обновить код в пакете, процесс
|
|
10
|
-
раскатки этого обновления на все приложения может занять много времени.
|
|
7
|
+
но ограничивает нас в скорости изменений. Если мы хотим заменить обновить код в пакете, процесс
|
|
8
|
+
раскатки этого обновления на все приложения может занять много времени.
|
|
11
9
|
- Сделать так, чтобы мы могли подключать код из других приложений в свое. При этом мы получаем
|
|
12
|
-
возможность быстро изменить общий код только в одном месте, а все приложения автоматически получат
|
|
13
|
-
обновления.
|
|
10
|
+
возможность быстро изменить общий код только в одном месте, а все приложения автоматически получат
|
|
11
|
+
обновления.
|
|
14
12
|
|
|
15
13
|
Модули позволяют реализовать именно последний вариант. Если вы знакомы с концепцией [module federation](https://webpack.js.org/concepts/module-federation/),
|
|
16
14
|
то модули приложений - это его реализация в рамках arui-scripts, с дополнительным уровнем абстракции, который, в том числе,
|
|
17
15
|
позволяет использовать модули без самого module-federation.
|
|
18
16
|
|
|
17
|
+
## Общие принципы работы модулей
|
|
18
|
+
С точки зрения кода модуль представляет собой простой js-объект, который может быть _каким то образом_ подключен в другое приложение.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
Модуль - это некоторая совокупность js и css файлов, которые можно подключить в приложение. У модуля есть
|
|
22
|
-
входная точка - js файл, код которого будет являться его публичным api.
|
|
23
|
-
|
|
24
|
-
Для подключения модулей в приложение предоставляется набор библиотек, которые позволяют указать, какой модуль
|
|
25
|
-
и куда надо подключить.
|
|
26
|
-
|
|
27
|
-
## Типы модулей
|
|
28
|
-
Несмотря на кажущуюся простоту концепции, можно представить разные сценарии использования модулей. В ряде случаев
|
|
29
|
-
мы хотим просто предоставить доступ к коду из другого приложения, в других - мы хотим иметь возможность
|
|
30
|
-
настраивать поведение модуля в зависимости от приложения, в котором он используется. Или мы хотим сделать так, чтобы
|
|
31
|
-
наш модуль мог сразу же получить какие-то данные с сервера, потому что его поведение зависит от этих данных.
|
|
32
|
-
|
|
33
|
-
Из-за того, что эти сценарии различаются, мы выделили два типа модулей:
|
|
34
|
-
|
|
35
|
-
- Клиентские модули. Это модули, которые имеют только клиентскую часть.
|
|
36
|
-
- Модули с серверной частью. Это модули, которые имеют как клиентскую, так и серверную часть. Серверная часть может
|
|
37
|
-
реализовывать какую-то логику, которая не может быть реализована на клиенте, например отдавать разные модули в зависимости
|
|
38
|
-
от пользователя, получать предподготовленные данные с сервера и т.д.
|
|
39
|
-
|
|
40
|
-
### Сравнение
|
|
41
|
-
|
|
42
|
-
Клиентские модули:
|
|
43
|
-
- Можно реализовать в любом приложении, даже если у него нет серверной части.
|
|
44
|
-
- Меньше кода, меньше проблем с поддержкой.
|
|
45
|
-
- Немного проще подключение модуля в приложение-хост.
|
|
46
|
-
|
|
47
|
-
Модули с серверной частью:
|
|
48
|
-
- Можно реализовать дополнительную логику, которая не может быть реализована на клиенте.
|
|
49
|
-
- Возможность изменить режим подключения модуля без изменений на приложениях-хостах.
|
|
20
|
+
`arui-scripts` предоставляет решение для сборки таких модулей, а также отдельную библиотеку для упрощения их подключения в другие приложения.
|
|
50
21
|
|
|
51
22
|
## Режимы подключения модулей
|
|
52
23
|
|
|
53
|
-
|
|
54
|
-
- `mf`
|
|
55
|
-
- `embedded`
|
|
24
|
+
В `arui-scripts` есть два способа сборки модулей:
|
|
25
|
+
- `mf` - Это модули, которые подключаются с помощью [webpack module federation](https://webpack.js.org/concepts/module-federation/).
|
|
26
|
+
- `embedded` - Это модули, которые подключаются просто добавлением нужных скриптов на страницу.
|
|
56
27
|
|
|
57
28
|
Основная проблема, которую решает ModuleFederation - это возможность не загружать на хост-приложение код библиотек уже подключенных в него.
|
|
58
29
|
Например, хост-приложение уже использует `react`, модуль так же написан на `react`. ModuleFederation дает нам легко "переиспользовать"
|
|
@@ -74,6 +45,43 @@
|
|
|
74
45
|
- **+++** Встроенная изоляция стилей. Стили модуля не будут применены к хост-приложению, если только вы не захотите этого.
|
|
75
46
|
- **---** Нет возможности использовать разные версии общих библиотек в разных модулях/хостах, если вы хотите их шарить.
|
|
76
47
|
|
|
48
|
+
## Возможность управления модулями с сервера
|
|
49
|
+
Сами модули используются только на клиентской части приложения. Но, в некоторых случаях, может быть полезно иметь возможность
|
|
50
|
+
управлять тем, какой модуль должен быть подключен на странице с сервера, или же иметь модуль, который будет при загрузке
|
|
51
|
+
иметь доступ к данным, доступным только на сервере (аналогично тому, как мы передаем серверный стейт в приложения при SSR).
|
|
52
|
+
|
|
53
|
+
Поэтому `arui-scripts` предоставляет возможность создать специальный эндпоинт на вашем сервере, из которого вы сможете управлять
|
|
54
|
+
состоянием модуля.
|
|
55
|
+
|
|
56
|
+
Модули с такой возможностью мы называем _серверными модулями_ (обычные модули мы называем _клиентскими_).
|
|
57
|
+
|
|
58
|
+
## Особые типы модулей
|
|
59
|
+
Несмотря на то, что сами по себе модули представляют собой простой js-объект, мы определяем один особый тип модулей - _монтируемые модули_.
|
|
60
|
+
|
|
61
|
+
### Монтируемые модули
|
|
62
|
+
Монтируемые модули - это модули, основное предназначение которых - отрендерить какой-то компонент внутри хост-приложения.
|
|
63
|
+
Монтируемые модули могут быть как клиентскими, так и серверными.
|
|
64
|
+
|
|
65
|
+
Такие модули должны экспортировать две функции:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
export function mount(targetNode, runParams, serverState): void {
|
|
69
|
+
// здесь происходит монтирование модуля в хост-приложение
|
|
70
|
+
// targetNode - это DOM-нода, в которую нужно отрендерить модуль
|
|
71
|
+
// runParams - это параметры, которые были переданы при запуске модуля
|
|
72
|
+
// serverState - это состояние, которое было передано с сервера
|
|
73
|
+
|
|
74
|
+
// Скорее всего это будет что-то вроде:
|
|
75
|
+
ReactDOM.render(<App preparedState={serverState} runParams={runParams} />, targetNode);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function unmount(targetNode): void {
|
|
79
|
+
// здесь происходит демонтирование модуля из хост-приложения
|
|
80
|
+
// Скорее всего это будет что-то вроде:
|
|
81
|
+
ReactDOM.unmountComponentAtNode(targetNode);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
77
85
|
## Как создать модуль
|
|
78
86
|
|
|
79
87
|
### Описать модуль в настройках arui-scripts
|
|
@@ -119,57 +127,54 @@ export default aruiScriptsConfig;
|
|
|
119
127
|
Все параметры конфигурации описаны [ниже](#Конфигурация-модулей).
|
|
120
128
|
|
|
121
129
|
### Создать модуль
|
|
122
|
-
Модуль является простым js/ts
|
|
123
|
-
|
|
124
|
-
`embedded` модули должны писать в window свой объект, который содержит функции для монтирования и демонтирования модуля.
|
|
130
|
+
Модуль является простым js/ts файлом. Он может использовать любой код вашего проекта, и любые библиотеки из node_modules.
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
import type { // Обратите внимание на `import type` - наш в модель никак не использует код библиотеки, нам нужны только типы
|
|
128
|
-
ModuleMountFunction,
|
|
129
|
-
ModuleUnmountFunction,
|
|
130
|
-
WindowWithMountableModule
|
|
131
|
-
} from '@alfalab/scripts-modules';
|
|
132
|
-
|
|
133
|
-
const mountModule: ModuleMountFunction = (moduleId, params, targetNode) => {
|
|
134
|
-
// здесь мы можем отрендерить наш модуль в targetNode
|
|
135
|
-
// например:
|
|
136
|
-
ReactDOM.render(<App />, targetNode);
|
|
137
|
-
};
|
|
132
|
+
В зависимости от режима подключения модуля, входная точка будет выглядеть по разному.
|
|
138
133
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
ReactDOM.unmountComponentAtNode(targetNode);
|
|
143
|
-
};
|
|
134
|
+
#### Embedded модуль
|
|
135
|
+
Входная точка embedded модуля должна писать в глобальную переменную `window` объект с ключом `{НазваниеМодуля}`.
|
|
136
|
+
Все поля этого объекта по сути и будут являться модулем, ваши потребители смогут использовать их.
|
|
144
137
|
|
|
138
|
+
```ts
|
|
139
|
+
// src/modules/client-module-embedded/index.ts
|
|
145
140
|
|
|
146
|
-
|
|
147
|
-
(
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
window.ClientModuleEmbedded = {
|
|
142
|
+
doSomething: () => {
|
|
143
|
+
console.log('Hello from embedded module!');
|
|
144
|
+
},
|
|
145
|
+
publicConstant: 3.14,
|
|
146
|
+
// ...
|
|
150
147
|
};
|
|
151
148
|
```
|
|
152
149
|
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
<details>
|
|
151
|
+
<summary>Писать в window? Вы что, с дуба рухнулись?</summary>
|
|
152
|
+
Да, конечно, это может создать определенные проблемы (конфликты имен модулей, определенные ограничения на используемые названия),
|
|
153
|
+
но по сути это единственный способ передать код модуля в хост-приложение.
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
|
|
155
|
+
Webpack module federation делает абсолютно то же самое, просто прячет работу с глобальными переменными за собой.
|
|
156
|
+
</details>
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
|
|
158
|
+
#### MF модуль
|
|
159
|
+
Входная точка MF модуля должна экспортировать все поля модуля через `export`.
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// например:
|
|
165
|
-
ReactDOM.render(<App />, targetNode);
|
|
166
|
-
};
|
|
161
|
+
```ts
|
|
162
|
+
// src/modules/client-module-mf/index.ts
|
|
167
163
|
|
|
168
|
-
export const
|
|
169
|
-
|
|
170
|
-
// например:
|
|
171
|
-
ReactDOM.unmountComponentAtNode(targetNode);
|
|
164
|
+
export const doSomething = () => {
|
|
165
|
+
console.log('Hello from mf module!');
|
|
172
166
|
};
|
|
167
|
+
|
|
168
|
+
export const publicConstant = 3.14;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Создание модулей предопределенного типа
|
|
172
|
+
|
|
173
|
+
**Монтируемый модуль, mf**
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
// src/modules/client-module-mf/index.ts
|
|
177
|
+
|
|
173
178
|
```
|
|
174
179
|
|
|
175
180
|
### (Опционально) Определить серверный эндпоинт для модуля
|
|
@@ -185,7 +190,8 @@ const modules: ModulesConfig = {
|
|
|
185
190
|
version: '1.0.0',
|
|
186
191
|
getRunParams: async (getResourcesRequest) => ({
|
|
187
192
|
// getResouresRequest - это объект, который будет передан из хост-приложения
|
|
188
|
-
|
|
193
|
+
|
|
194
|
+
// данные, которые вернет эта будут доступны при инициализации модуля
|
|
189
195
|
paramFromServer: 'This can be any data from server',
|
|
190
196
|
asyncData: 'It can be constructed from async data, so you may perform some service calls here',
|
|
191
197
|
contextRoot: 'http://localhost:8081',
|
|
@@ -203,6 +209,8 @@ const modules: ModulesConfig = {
|
|
|
203
209
|
};
|
|
204
210
|
```
|
|
205
211
|
|
|
212
|
+
Подробнее о `getResourcesRequest` и `getRunParams` рассказано в разделе [Подключение модулей](#Подключение-модулей).
|
|
213
|
+
|
|
206
214
|
Далее, в зависимости от того, какой серверный фреймворк вы используете, вам нужно будет подключить ваши модули в
|
|
207
215
|
соответствующий хендлер. Например, для express это будет выглядеть так:
|
|
208
216
|
|
|
@@ -214,7 +222,7 @@ const modulesRouter = createGetModulesExpress(modules);
|
|
|
214
222
|
app.use(modulesRouter);
|
|
215
223
|
```
|
|
216
224
|
|
|
217
|
-
Для hapi@16
|
|
225
|
+
Для `hapi@16`:
|
|
218
226
|
|
|
219
227
|
```ts
|
|
220
228
|
import { createGetModulesHapi16Plugin } from '@alfalab/scripts-server/build/hapi16';
|
|
@@ -224,7 +232,7 @@ const modulesPlugin = createGetModulesHapi16Plugin(modules);
|
|
|
224
232
|
server.register(modulesPlugin);
|
|
225
233
|
```
|
|
226
234
|
|
|
227
|
-
Для hapi@20
|
|
235
|
+
Для `hapi@20`:
|
|
228
236
|
|
|
229
237
|
```ts
|
|
230
238
|
import { createGetModulesHapi20Plugin } from '@alfalab/scripts-server/build/hapi20';
|
|
@@ -269,155 +277,163 @@ type ModulesMethod = {
|
|
|
269
277
|
Никакого встроенного механизма изоляции стилей для MF модулей нет. Если хост-приложение и модуль используют css-modules,
|
|
270
278
|
то конфликтов возникнуть не должно. Если же это не так - вы можете попробовать решить эту проблему используя shadow-dom.
|
|
271
279
|
|
|
272
|
-
###
|
|
280
|
+
### TODO: тестирование модулей
|
|
273
281
|
|
|
274
|
-
|
|
282
|
+
# Подключение модулей
|
|
275
283
|
|
|
284
|
+
## Создание загрузчика
|
|
285
|
+
Базовый способ подключение модулей - это использование `createModuleLoader` из `@alfalab/scripts-modules`. Этот метод
|
|
286
|
+
вернет вам функцию, которая позволит подключить модуль в ваше приложение.
|
|
276
287
|
|
|
277
|
-
|
|
288
|
+
```ts
|
|
289
|
+
import { createModuleLoader } from '@alfalab/scripts-modules';
|
|
290
|
+
|
|
291
|
+
const loader = createModuleLoader({
|
|
292
|
+
moduleId: 'test', // id модуля, который вы хотите подключить
|
|
293
|
+
// функция, которая должна вернуть описание модуля.
|
|
294
|
+
getModuleResources: async ({ moduleId, hostAppId, params }) => ({
|
|
295
|
+
scripts: ['http://localhost:8081/static/js/main.js'], // скрипты модуля
|
|
296
|
+
styles: ['http://localhost:8081/static/css/main.css'], // стили модуля
|
|
297
|
+
moduleVersion: '1.0.0', // версия модуля
|
|
298
|
+
appName: 'moduleSourceAppName', // имя приложения, которое является источником модуля
|
|
299
|
+
mountMode: 'embedded', // режим монтирования модуля
|
|
300
|
+
moduleRunParams: { // параметры, которые будут доступны при инициализации модуля
|
|
301
|
+
baseUrl: 'http://localhost:8081',
|
|
302
|
+
},
|
|
303
|
+
}),
|
|
304
|
+
});
|
|
305
|
+
```
|
|
278
306
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
определить параметры для этих библиотек в `arui-scripts.config.ts`.
|
|
307
|
+
Вам вовсе не обязательно руками описывать функцию `getModuleResources`. В зависимости от типа модуля, вы можете
|
|
308
|
+
использовать один из готовых хелперов:
|
|
282
309
|
|
|
310
|
+
Для клиентских модулей:
|
|
283
311
|
```ts
|
|
284
|
-
import {
|
|
312
|
+
import { createModuleLoader, createClientResourcesFetcher } from '@alfalab/scripts-modules';
|
|
285
313
|
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
mfModules: {
|
|
294
|
-
shared: {
|
|
295
|
-
'react': {
|
|
296
|
-
eager: true,
|
|
297
|
-
singleton: true,
|
|
298
|
-
requiredVersion: '^17.0.0',
|
|
299
|
-
},
|
|
300
|
-
'react-dom': {
|
|
301
|
-
eager: true,
|
|
302
|
-
singleton: true,
|
|
303
|
-
requiredVersion: '^17.0.0',
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
}
|
|
314
|
+
const loader = createModuleLoader({
|
|
315
|
+
moduleId: 'test',
|
|
316
|
+
getModuleResources: createClientResourcesFetcher({
|
|
317
|
+
baseUrl: 'http://localhost:8081',
|
|
318
|
+
mountMode: 'mf',
|
|
319
|
+
}),
|
|
320
|
+
});
|
|
308
321
|
```
|
|
309
322
|
|
|
310
|
-
|
|
311
|
-
Клиентские и серверные модули подключаются на страницу немного по-разному.
|
|
323
|
+
`createClientResourcesFetcher` сам сделает запрос за манифестом приложения, и правильным образом сформирует описание модуля.
|
|
312
324
|
|
|
313
|
-
|
|
325
|
+
Для серверных модулей:
|
|
326
|
+
```ts
|
|
327
|
+
import { createModuleLoader, createServerResourcesFetcher } from '@alfalab/scripts-modules';
|
|
328
|
+
|
|
329
|
+
const loader = createModuleLoader({
|
|
330
|
+
moduleId: 'test',
|
|
331
|
+
getModuleResources: createServerResourcesFetcher({
|
|
332
|
+
baseUrl: 'http://localhost:8081',
|
|
333
|
+
headers: { 'X-Auth': 'bla-bla' } // опционально вы можете передать дополнительные заголовки для запроса
|
|
334
|
+
}),
|
|
335
|
+
});
|
|
336
|
+
```
|
|
314
337
|
|
|
315
|
-
|
|
316
|
-
import React, { useMemo } from 'react';
|
|
317
|
-
import { createLoader, useModuleLoader, getModuleResourcesPath } from '@alfalab/scripts-modules';
|
|
318
|
-
|
|
319
|
-
// Это просто функция, которая должна обратиться к серверу модуля.
|
|
320
|
-
// Скорее всего у вас уже есть хелпер, который создает подобные функции
|
|
321
|
-
// и насыщает запрос дополнительными данными, например, токеном авторизации, traceId и т.д.
|
|
322
|
-
const customFetch = (loaderParams) => {
|
|
323
|
-
// arui-scripts не знает заранее ни дополнительных параметров (авторизация, заголовки), которые вы хотите передать в запрос,
|
|
324
|
-
// ни того, на какой адрес нужно делать запрос. Поэтому вам нужно самим реализовать эту функцию.
|
|
325
|
-
return fetch(`http://localhost:8081/${getModuleResourcesPath}`, {
|
|
326
|
-
method: 'POST',
|
|
327
|
-
body: JSON.stringify(loaderParams),
|
|
328
|
-
headers: {
|
|
329
|
-
'Content-Type': 'application/json',
|
|
330
|
-
},
|
|
331
|
-
}).then((response) => response.json());
|
|
332
|
-
}
|
|
338
|
+
`createServerResourcesFetcher` сам сделает запрос к ручке, которая отдает описание модуля.
|
|
333
339
|
|
|
334
|
-
|
|
335
|
-
// Загрузчик - это функция, которая прячет в себе запрос к серверу, подключение ресурсов на страницу и т.д.
|
|
336
|
-
const loader = useMemo(() => createLoader({
|
|
337
|
-
hostAppId: 'example', // id вашего хост-приложения
|
|
338
|
-
fetchFunction: customFetch,
|
|
339
|
-
// С помощью этой функции вы можете передать дополнительные параметры в запрос к серверу модуля.
|
|
340
|
-
getModuleRequestParams: async () => ({
|
|
341
|
-
paramName: 'some param that will be passed to module',
|
|
342
|
-
}),
|
|
343
|
-
}), []);
|
|
344
|
-
|
|
345
|
-
// useModuleLoader - это простой хук, который с помощью переданного загрузчика подключает модуль на страницу.
|
|
346
|
-
const {
|
|
347
|
-
loadingState, // состояние загрузки модуля. 'pending' - модуль еще не загружен, 'resolved' - модуль загружен, 'rejected' - произошла ошибка при загрузке модуля
|
|
348
|
-
targetElementRef, // ссылка на элемент, в который будет подключен модуль
|
|
349
|
-
} = useModuleLoader(
|
|
350
|
-
"ServerModuleEmbedded", // id модуля, который был указан в arui-scripts.config.ts
|
|
351
|
-
loader,
|
|
352
|
-
);
|
|
340
|
+
В случае же совсем кастомных требований, вы можете реализовать функцию `getModuleResources` самостоятельно.
|
|
353
341
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
{ loadingState === 'pending' && <div>Loading...</div> }
|
|
357
|
-
{ loadingState === 'rejected' && <div>Failed to load module</div> }
|
|
342
|
+
## Использование загрузчика
|
|
343
|
+
После того как вы создали `loader` - вы легко можете получить доступ к модулю:
|
|
358
344
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
};
|
|
345
|
+
```ts
|
|
346
|
+
const { module, unmount, moduleResources } = await loader({
|
|
347
|
+
getResourcesParams: {}, // параметры, которые будут переданы в getModuleResources
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
console.log(module); // модуль, который вы загрузили. Тут будут доступны всё, что было экспортировано из модуля
|
|
351
|
+
console.log(moduleResources); // полный ответ от getModuleResources
|
|
352
|
+
|
|
353
|
+
// вызов этой функции отмонтирует модуль из вашего приложения - удалит скрипты и стили модуля, а так же удалит
|
|
354
|
+
// все глобальные переменные, которые были определены в модуле.
|
|
355
|
+
unmount();
|
|
363
356
|
```
|
|
364
357
|
|
|
365
|
-
При
|
|
358
|
+
При вызове `loader` вы можете передать параметры, которые попадут в функцию `getModuleResources`. Это может быть полезно,
|
|
359
|
+
если вы хотите передать какие-то параметры на сервер модуля.
|
|
360
|
+
|
|
361
|
+
`getModuleResources` будет вызвана со следующими параметрами:
|
|
362
|
+
```ts
|
|
363
|
+
const getModuleResourcesParams = {
|
|
364
|
+
moduleId: 'test', // id модуля, который вы хотите подключить
|
|
365
|
+
hostAppId: 'hostAppId', // id вашего приложения
|
|
366
|
+
params: {}, // параметры, которые вы передали в loader как `getResourcesParams`
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
На сервер будут отправлены именно эти параметры, они будут доступны как параметр в `getRunParams` в описании вашего модуля.
|
|
371
|
+
|
|
372
|
+
При использовании клиентских модулей, вам не нужно беспокоиться о том, какие параметры вы передаете в `getModuleResources` - они
|
|
373
|
+
никак не используются в клиентских модулях.
|
|
374
|
+
|
|
375
|
+
## Использования загрузчика в реакт-приложении
|
|
376
|
+
|
|
377
|
+
Для того чтобы упростить работу с загрузчиком в реакт-приложении, мы предоставляем хук `useModuleLoader`:
|
|
366
378
|
|
|
367
379
|
```tsx
|
|
368
|
-
import
|
|
369
|
-
import { createClientLoader, useModuleLoader } from '@alfalab/scripts-modules';
|
|
370
|
-
import { Underlay } from '@alfalab/core-components/underlay';
|
|
371
|
-
import { Spinner } from '@alfalab/core-components/spinner';
|
|
380
|
+
import { createModuleLoader, useModuleLoader } from '@alfalab/scripts-modules';
|
|
372
381
|
|
|
373
|
-
const loader =
|
|
374
|
-
|
|
382
|
+
const loader = createModuleLoader({
|
|
383
|
+
moduleId: 'test',
|
|
384
|
+
getModuleResources: createClientResourcesFetcher({
|
|
385
|
+
baseUrl: 'http://localhost:8081',
|
|
386
|
+
mountMode: 'mf',
|
|
387
|
+
}),
|
|
375
388
|
});
|
|
376
389
|
|
|
377
|
-
|
|
378
|
-
const { loadingState,
|
|
379
|
-
"ClientModuleEmbedded", // id модуля, который был указан в arui-scripts.config.ts
|
|
380
|
-
loader
|
|
381
|
-
);
|
|
390
|
+
const MyComponent = () => {
|
|
391
|
+
const { loadingState, module, resources } = useModuleLoader(loader); // вторым параметром можно передать параметры, которые будут переданы в getModuleResources
|
|
382
392
|
|
|
383
393
|
return (
|
|
384
394
|
<div>
|
|
385
|
-
{
|
|
386
|
-
{
|
|
387
|
-
|
|
388
|
-
|
|
395
|
+
{loadingState === 'loading' && <div>Loading...</div>}
|
|
396
|
+
{loadingState === 'error' && <div>Error</div>}
|
|
397
|
+
{loadingState === 'success' && (
|
|
398
|
+
<div>
|
|
399
|
+
<div>Module loaded</div>
|
|
400
|
+
<div>{module}</div> {/* модуль, который вы загрузили. Тут будет доступно всё, что было экспортировано из модуля */}
|
|
401
|
+
<div>{resources}</div>
|
|
402
|
+
</div>
|
|
403
|
+
)}
|
|
389
404
|
</div>
|
|
390
405
|
);
|
|
391
|
-
}
|
|
392
|
-
|
|
406
|
+
};
|
|
393
407
|
```
|
|
394
408
|
|
|
409
|
+
### Использование монтируемых модулей
|
|
395
410
|
|
|
396
|
-
|
|
411
|
+
Для работы с монтируемыми модулями так же есть готовый хук `useModuleMounter`:
|
|
397
412
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
`embeddedModules` - объект, управляющий конфигурацией embedded модулей.
|
|
401
|
-
|
|
402
|
-
- `embeddedModules.shared` - объект, описывающий библиотеки, которые приложение будет предоставлять модулям. Ключ объекта - название библиотеки,
|
|
403
|
-
значение - название переменной в window, в которую будет записана библиотека.
|
|
404
|
-
- `embeddedModules.exposes` - объект, описывающий embedded модули. Ключ объекта - id модуля, значение - объект с конфигурацией модуля.
|
|
405
|
-
- `embeddedModules.exposes[id].entry` - путь до точки входа модуля. Должен быть либо абсолютным, либо относительным от корня проекта.
|
|
406
|
-
- `embeddedModules.exposes[id].cssPrefix` - префикс для css классов модуля. По умолчанию все стили модуля будут префиксированы с `.module-{id модуля}`. Вы можете передать сюда
|
|
407
|
-
свой префикс, или `false` чтобы отключить префиксирование.
|
|
408
|
-
- `embeddedModules.exposes[id].embeddedConfig` - объект, описывающий какие библиотеки должны быть помечены для модуля как `external`. Ключ объекта - название библиотеки,
|
|
409
|
-
значение - название переменной в window, в которой модуль будет искать эту библиотеку.
|
|
410
|
-
|
|
411
|
-
## MF модули
|
|
413
|
+
```tsx
|
|
414
|
+
import { createModuleLoader, useModuleMounter } from '@alfalab/scripts-modules';
|
|
412
415
|
|
|
413
|
-
|
|
416
|
+
const loader = createModuleLoader({
|
|
417
|
+
moduleId: 'test',
|
|
418
|
+
getModuleResources: createClientResourcesFetcher({
|
|
419
|
+
baseUrl: 'http://localhost:8081',
|
|
420
|
+
mountMode: 'embedded',
|
|
421
|
+
}),
|
|
422
|
+
});
|
|
414
423
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
значение - точка входа модуля.
|
|
424
|
+
const MyComponent = () => {
|
|
425
|
+
const { loadingState, targetElementRef } = useModuleMounter({
|
|
426
|
+
loader,
|
|
427
|
+
loaderParams: {}, // параметры, которые будут переданы в getModuleResources, опционально
|
|
428
|
+
runParams: {}, // параметры, которые будут переданы в mount функцию модуля, опционально
|
|
429
|
+
});
|
|
422
430
|
|
|
423
|
-
|
|
431
|
+
return (
|
|
432
|
+
<div>
|
|
433
|
+
{loadingState === 'loading' && <div>Loading...</div>}
|
|
434
|
+
{loadingState === 'error' && <div>Error</div>}
|
|
435
|
+
<div ref={targetElementRef} /> {/* сюда будет монтироваться модуль */}
|
|
436
|
+
</div>
|
|
437
|
+
);
|
|
438
|
+
};
|
|
439
|
+
```
|