@cxra/routine-assistance
Version:
RA (Routine Assistance).
266 lines (196 loc) • 14.9 kB
Markdown
# /routine-assistance
## Pipes
`isD` checks if the value is defined
`isND` checks if the value is undefined or null
`asSanitizedHtml` is meant to be sanitized to declarative html for use in a template
# /module-federation-navigator
Данная библиотека, предназначена:
* To make it a little easier to work with [Module Federation](https://github.com/angular-architects/module-federation-plugin/blob/main/libs/mf/README.md) in basic cases.
* Автоматизировать не только управление модулями через файл конфигурации, но и управление навигацией к этим модулям и доступностью их для разных контекстов исполнения. _Данная потребность возникала:_
* В продуктовой разработке когда один продукт разворачивается для разных заказчиков с разной конфигурациеи.
* Когда нужно предоставить возможность devops быстро отключать, включать и конфигурировать состав.
* Сохранить возможность ленивой загрузки и при этом дать возможность самим модулям предоставлять компонент который будет использован в качестве навигационного элемента
## Конфигурирование
Основные настройки описываются в конфигурационном файле манифеста модулей `{manifest_name}.json` для изменения конфигурации после развертывания.
* Рекомендуемым местом расположения файла конфигурации для проектов где основное приложение написано на angular является `.\{app-name}\src\assets\{manifest_name}.json` для публикации стандартными средствами
* Так же регулярным вариантом использования является сборка и предоставления манифеста server-side в виде ответа на запрос, так как формат данных манифеста `json`
Recommended point to load the configuration is to implement the standard angular app init loop, by provide `APP_INITIALIZER`
```
providers: [{
provide: APP_INITIALIZER,
useFactory: (manifest: CXraModuleNavigatorManifest<cxra.module.federation.navigation.NavigableRemoteModuleConfig>) =>
(): Promise<void> =>
manifest.load('/assets/modules.manifest.json'),
deps: [CXraModuleNavigatorManifest],
multi: true
}],
```
### Настройка источников модулей
Данная библиотека основана на [angular-architects/module-federation-plugin](https://github.com/angular-architects/module-federation-plugin/blob/main/libs/mf/README.md), по этому основными видами потребляемых модулей являются:
* Модули `angular`. В качестве `type` указывается значение _module_.
```
"module-a": {
"type": "module"
"remoteEntry": "http://localhost:3000/remoteEntry.js"
"remoteName": "example-module-a"
"exposedModule": "./Module"
"elementName": "AppModule"
...
}
```
`elementName` наименование основного класса публикуемого как angular module.
В частности пример приведенный выше, справедлив для внешнего модуль публикованного следующим образом
```
name: "example-module-a"
exposes: {
"./Module": "./examples/example-module-a/src/app/app.module.ts"
"./Component": "./examples/example-module-a/src/app/components/nav/nav.component.ts"
}
```
* Скрипты `js`. В качестве `type` указывается значение _script_.
```
"react-a": {
"type": "script"
"remoteEntry": "https://witty-wave-0a695f710.azurestaticapps.net/remoteEntry.js"
"remoteName": "react"
"exposedModule": "./web-components"
"elementName": "react-element"
}
```
`elementName` наименование component получаемого из публикации в качестве root.
---
Общие настройки вне зависимости от типа:
`remoteEntry` публичный адрес размещения сгенерированного файла декларации интегрируемых модулей.
`remoteName` наименование remote object используемое для публикации.
`exposedModule` наименование секции размещения модуля в экспозиции.
### Настройка навигации модуля
На базовом уровне навигация определяется свойством `navigation`.
* Для модуля может быть определено поведение без навигационного элемента.
Данное решение может быть применимо в случаях когда функциональность remote модуля должна быть доступна только из определенного блока интерфейса или как звено определенного бизнес сценария. Такой подход реализуется по средствам доступа по конкретному маршруту.
`navigation` задается непосредственно строкой описывающей route.
```
"navigation": "module-a/offers/:id/accepted"
```
* Для модуля может быть определена глобальная навигация.
Данное решение предоставляет возможность самому модулю запубликовать навигационный элемент, `component` который будет использован для отображения в меню, инвертировав данную зависимость из основного приложения. Или напрямую в конфигурационном файле определить `template` который будет использоваться в качестве навигационного элемента, что позволяет интегрироваться с remote module не публикующему навигационный элемент, например если он legacy или поставляется сторонним разработчиком.
`navigation` задается объектом содержащим ряд конфигураций.
```
"navigation": {
"route": {
"path": "module-a"
},
"component": {
"type": "ModuleANavComponent",
"remoteEntry": "http://localhost:3000/remoteEntry.js",
"exposedModule": "./Component"
}
}
```
* `route` описание route для lazy load сборки модуля
* `path` обязательная характеристика задающая строкой route
* `params` карта path параметров (_optional_)
* `queries` карта условных параметров (_optional_)
* `component` описание элемента для представления в навигации
* Может быть представлен конфигурацией использующей remote `component` и в данном случае описывается радом свойств.
* `type` название класса компонента из remote модуля который будет использоваться в качестве навигационного элемента
⚠️ Рекомендуется оформлять как __standalone__ компонент
```
({
selector: 'module-a-nav'
standalone: true
...
})
export class ModuleANavComponent {}
```
* `remoteEntry` публичный адрес размещения сгенерированного файла декларации модуля содержащего навигационный элемент.
* `exposedModule` наименование секции размещения навигационного элемента в экспозиции.
```
exposes: {
"./Module": "./examples/example-module-a/src/app/app.module.ts"
"./Component": "./examples/example-module-a/src/app/components/nav/nav.component.ts"
}
```
* Может быть представлен конфигурацией использующей `template`
В данном случае описывается текстовым представлением шаблона напрямую в конфигурационном файле. И предоставляет возможность задания индивидуального значения каждому экземпляру развертывания силами devops.
```
"component": "<span>to <b>reAct-B</b></span>"
```
### Управление доступностью навигации к модулю, в зависимости от контекста или состояния
В конфигурационном файле манифеста модулей `{manifest_name}.json` активность модуля и его навигации, может быть установлена в три состояния 'on' | 'off' | 'promise'.
```
"module-b": {
"state": "on | off | promise"
...
}
...
```
* `on` - модуль активен сразу и будет доступен сразу после загрузки инициированной активацией маршрута
* `off` - навигация к модулю не будет доступна и маршруты для активации модуля не будут опубликованы
* `promise` - навигация к модулю будет разблокировано если будет найдено и выполнено положительно обещание активации, публикуемое по token в DI
```
providers: [{
provide: CXRA_MODULE_OPTIONS,
useFactory: (_http: HttpClient) => ({
['module-a']: {
state: new Promise<boolean>((resolve) => {
_http.get<...>(...).pipe(
map(user => user.permissions.has(...)),
...
takeUntil(...)
).subscribe(() => resolve(true));
})
}
}),
deps: [HttpClient],
multi: true
}, ...],
```
_ cxra.module.federation.navigation.RemoteModuleState_
### Публикация пользовательских событий модуля
Для публикации реализации возможности отображения факта наличия ии самих пользовательских уведомлений remote module в навигационной части приложения в едином стиле, предусмотрена возможность опубликовать источник событий через контракт __CXRA_MODULE_OPTIONS__ как в непосредственном модуле, так и в локализованном приложении потребителе. Тем самым инвертированная устранив зависимость на предоставление модулю интерфейсов для непосредственного размещения элементов в обобщенной части интерфейса приложения.
Для каждого модуля имеющего оповещения в его секции публикуется:
* `events` - представляющий реализацию _Observable<Array<TEvent>>_
```
providers: [{
provide: CXRA_MODULE_OPTIONS,
useFactory: (...) => ({
['module-a']: {
...
events: new BehaviorSubject<unknown>(...)
}
}),
deps: [...],
multi: true
}]
```
## Общие настройки
Для задания общих настроек навигации и менеджмента remote modules определен контракт __CXRA_MODULE_NAVIGATOR_OPTIONS__ обладающий рядом характеристик.
* `undefined.component` предназначена для определения компонента который будет использован в случае перехода к неопределенному элементу маршрутизации, в случае необходимости задания такого поведения централизовано
```
providers: [{
provide: CXRA_MODULE_NAVIGATOR_OPTIONS,
useValue: {
undefined: {
component: UnfoundComponent
}
}
}],
```
## Examples
This repository provides examples of an application using this approach.
Description | Project
--- | ---
Контекст. Пример проекта используемого для публикации и обработки данных используемых между разными модулями. | examples\example-context
Module A. С примером отключения навигации модуля из самого себя. | examples\example-module-a
Module B. С примером инкапсуляции внутренних стилей и данных внешнего контекста. | examples\example-module-b
Directly the application publishes different modules and navigation. | examples\example-app
## First run
* Install packages: ``yarn install``
Please note, you **must** use **yarn** during the beta phase of CLI 11 b/c it allows to override dependencies to force the CLI into webpack 5.
* Build lib`s
Navigator: ``yarn build:module-federation-navigator``
### Usage
* Start all micro-frontend's and app: ``yarn start:example:navigator:all``

## More
More [about Module Federation](https://github.com/angular-architects/module-federation-plugin/blob/main/libs/mf/README.md)