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/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` модули. Это модули, которые подключаются с помощью [webpack module federation](https://webpack.js.org/concepts/module-federation/).
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
- ```tsx
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
- const unmountModule: ModuleUnmountFunction = (targetNode) => {
140
- // здесь мы можем отключить наш модуль от targetNode
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
- // ClientModuleEmbedded - имя модуля, которое мы указали в настройках arui-scripts
147
- (window as WindowWithMountableModule).ClientModuleEmbedded = {
148
- mount: mountModule,
149
- unmount: unmountModule,
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
- Если у вас возникает вопрос "фу, разве не плохо писать в window?". Ответ: да, плохо. Но вы думаете что ModuleFederation
154
- работает как то иначе? По сути мы просто воспроизводим то же самое поведение, только в более ручном режиме.
150
+ <details>
151
+ <summary>Писать в window? Вы что, с дуба рухнулись?</summary>
152
+ Да, конечно, это может создать определенные проблемы (конфликты имен модулей, определенные ограничения на используемые названия),
153
+ но по сути это единственный способ передать код модуля в хост-приложение.
155
154
 
156
- `mf` модули не должны ничего писать в window (на самом деле за них то же самое делает webpack). Они должны просто
157
- экспортировать функции `mount` и `unmount`:
155
+ Webpack module federation делает абсолютно то же самое, просто прячет работу с глобальными переменными за собой.
156
+ </details>
158
157
 
159
- ```tsx
160
- import type { ModuleMountFunction, ModuleUnmountFunction } from '@alfalab/scripts-modules';
158
+ #### MF модуль
159
+ Входная точка MF модуля должна экспортировать все поля модуля через `export`.
161
160
 
162
- export const mount: ModuleMountFunction = (moduleId, params, targetNode) => {
163
- // здесь мы можем отрендерить наш модуль в targetNode
164
- // например:
165
- ReactDOM.render(<App />, targetNode);
166
- };
161
+ ```ts
162
+ // src/modules/client-module-mf/index.ts
167
163
 
168
- export const unmount: ModuleUnmountFunction = (targetNode) => {
169
- // здесь мы можем отключить наш модуль от targetNode
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
- // данные, которые вернет эта функция будут переданы в mount функцию модуля
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
- TODO
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 { PackageSettings } from 'arui-scripts';
312
+ import { createModuleLoader, createClientResourcesFetcher } from '@alfalab/scripts-modules';
285
313
 
286
- const aruiScriptsConfig: PackageSettings = {
287
- embeddedModules: {
288
- shared: {
289
- 'react': 'reactDOM',
290
- 'react-dom': 'reactDOM',
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
- ```tsx
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
- export const ServerModuleMounter = () => {
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
- return (
355
- <div>
356
- { loadingState === 'pending' && <div>Loading...</div> }
357
- { loadingState === 'rejected' && <div>Failed to load module</div> }
342
+ ## Использование загрузчика
343
+ После того как вы создали `loader` - вы легко можете получить доступ к модулю:
358
344
 
359
- <div ref={ targetElementRef } />
360
- </div>
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
- При подключении же клиентских модулей необходимо использовать функцию `createClientLoader` вместо `createLoader`:
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 React from 'react';
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 = createClientLoader({
374
- baseUrl: 'http://localhost:8081/', // базовый адрес приложения с подключаемым модулем
382
+ const loader = createModuleLoader({
383
+ moduleId: 'test',
384
+ getModuleResources: createClientResourcesFetcher({
385
+ baseUrl: 'http://localhost:8081',
386
+ mountMode: 'mf',
387
+ }),
375
388
  });
376
389
 
377
- export const EmbeddedModuleMounter = () => {
378
- const { loadingState, targetElementRef } = useModuleLoader(
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
- { loadingState === 'pending' && <Spinner size='m' /> }
386
- { loadingState === 'rejected' && <div>Failed to load module</div> }
387
-
388
- <div ref={ targetElementRef } />
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
- ## Embedded модули
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
- `mfModules` - объект, управляющий конфигурацией Module Federation модулей.
416
+ const loader = createModuleLoader({
417
+ moduleId: 'test',
418
+ getModuleResources: createClientResourcesFetcher({
419
+ baseUrl: 'http://localhost:8081',
420
+ mountMode: 'embedded',
421
+ }),
422
+ });
414
423
 
415
- - `mfModules.name` - опциональное имя модуля. Это имя будет использовано как название контейнера модуля. Если не указано, то
416
- будет использовано имя пакета, в котором все `-` будут заменены на `_`. Должно быть уникальным в рамках хост-приложения,
417
- и быть валидным именем для js переменной.
418
- - `mfModules.shared` - объект, описывающий библиотеки, которые приложение будет предоставлять модулям, и библиотеки, которые модуль будет пытаться получить от хост-приложения.
419
- Подробнее про варианты описания можно почитать в [документации](https://webpack.js.org/plugins/module-federation-plugin/#specify-package-versions).
420
- - `exposes` - объект, описывающий какие модули должны быть предоставлены хост-приложению. Ключ объекта - название модуля,
421
- значение - точка входа модуля.
424
+ const MyComponent = () => {
425
+ const { loadingState, targetElementRef } = useModuleMounter({
426
+ loader,
427
+ loaderParams: {}, // параметры, которые будут переданы в getModuleResources, опционально
428
+ runParams: {}, // параметры, которые будут переданы в mount функцию модуля, опционально
429
+ });
422
430
 
423
- # API библиотек
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
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arui-scripts",
3
- "version": "14.5.0-feat-modules.2",
3
+ "version": "14.5.0-feat-modules.3",
4
4
  "main": "./build/index.js",
5
5
  "typings": "./build/index.d.ts",
6
6
  "license": "MPL-2.0",