@ama-mfe/ng-utils 12.1.0-prerelease.80 → 12.1.0-prerelease.81
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 +260 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,3 +1,261 @@
|
|
|
1
|
-
# Ama
|
|
1
|
+
# Ama MFE Angular Utils
|
|
2
|
+
`@ama-mfe/ng-utils` is an Angular library designed to streamline communication within a micro-frontend architecture that
|
|
3
|
+
uses iframes.
|
|
4
|
+
This package is built on the [Amadeus Toolkit for Micro Frontends framework](https://www.npmjs.com/package/@amadeus-it-group/microfrontends-angular)
|
|
5
|
+
and offers a suite of tools - including helpers, wrappers, and services - to facilitate seamless integration and
|
|
6
|
+
interaction between host and embedded applications.
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
Key features include:
|
|
9
|
+
- [Connect](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-mfe/ng-utils/src/connect/): Connect to the communication protocol and send messages to registered applications.
|
|
10
|
+
- [Navigation](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-mfe/ng-utils/src/navigation/): Ensures the host application can update its navigation to reflect the embedded application's URL,
|
|
11
|
+
maintaining consistency even after a page refresh.
|
|
12
|
+
- [Theme](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-mfe/ng-utils/src/theme/): Allows the application of unified CSS variables and styles across embedded modules, ensuring a cohesive
|
|
13
|
+
look and feel.
|
|
14
|
+
- [Resize](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-mfe/ng-utils/src/resize/): Dynamically adjusts the iframe dimensions to fit the content of the embedded application, enhancing the
|
|
15
|
+
user experience.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
To install the package, run:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm exec ng add @ama-mfe/ng-utils
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Consumer and Producer
|
|
25
|
+
In the communication protocol, a message is created by a `Producer` and sent to a `Consumer` which will read the message
|
|
26
|
+
and react according to its content.
|
|
27
|
+
|
|
28
|
+
The `@ama-mfe/ng-utils` package exposes a set of features based on messages exchanged between a host application and its
|
|
29
|
+
embedded module. For each feature, the package provides a `Producer`/`Consumer` pair.
|
|
30
|
+
The former service is in charge of delivering the messages based on triggers (resize event, call to a public function
|
|
31
|
+
etc.) while the latter implements the logic behind the feature (resizing of the iframe, application of a theme, etc.).
|
|
32
|
+
|
|
33
|
+
## How to use
|
|
34
|
+
### Connection to the communication service
|
|
35
|
+
#### Configure your application connection
|
|
36
|
+
Applications first need to provide and configure the `ConnectionService` to use the communication protocol.
|
|
37
|
+
The `provideConnection` method allows an application to register with a unique ID that others will use to
|
|
38
|
+
connect and target the application.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import {provideConnection} from '@ama-mfe/ng-utils';
|
|
42
|
+
|
|
43
|
+
export const appConfig: ApplicationConfig = {
|
|
44
|
+
providers: [
|
|
45
|
+
provideConnection({
|
|
46
|
+
id: 'applicationUniqueID'
|
|
47
|
+
})
|
|
48
|
+
]
|
|
49
|
+
};
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Initiate the communication with the host application
|
|
53
|
+
An application embedded into another one can connect to its host using the [ConnectionService].
|
|
54
|
+
To establish the connection, the embedded application requires the host application id (set via the
|
|
55
|
+
[connection service's provider](#configure-your-application-connection)).
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// main.ts
|
|
59
|
+
import {inject, runInInjectionContext} from '@angular/core';
|
|
60
|
+
import {bootstrapApplication} from '@angular/platform-browser';
|
|
61
|
+
import {ConnectionService, NavigationConsumerService} from '@ama-mfe/ng-utils';
|
|
62
|
+
|
|
63
|
+
bootstrapApplication(AppComponent, appConfig)
|
|
64
|
+
.then((m) => {
|
|
65
|
+
runInInjectionContext(m.injector, () => {
|
|
66
|
+
if (window.top !== window.self) {
|
|
67
|
+
// If embedded in an iframe, connect to the host
|
|
68
|
+
inject(ConnectionService).connect('hostUniqueID');
|
|
69
|
+
}
|
|
70
|
+
// Other injections
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Initiate the connection to your embedded module
|
|
76
|
+
Use the `connect` directive to initiate the communication between your application and the module in the iframe.
|
|
77
|
+
The communication pipe will be closed once the iframe is destroyed.
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<iframe [src]='myModuleUrl'
|
|
81
|
+
[connect]='myModuleUniqueID'>
|
|
82
|
+
</iframe>
|
|
83
|
+
```
|
|
84
|
+
In this example, `myModuleUniqueID` refers to the id provided in the `provideConnection` method.
|
|
85
|
+
|
|
86
|
+
### Enable a message-based feature
|
|
87
|
+
To use a feature based on the message communication protocol, you need first to identify if your application will be a
|
|
88
|
+
user of the message (`Consumer`) or the one sending the message (`Producer`).
|
|
89
|
+
This may depend on the context and the type of message. For instance, an application can be the consumer of navigation
|
|
90
|
+
messages but the producer of theme messages.
|
|
91
|
+
|
|
92
|
+
#### Consumers
|
|
93
|
+
If you are a consumer of the message, call the `start` and `stop` methods to respectively enable and disable the feature.
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import {Component, inject} from '@angular/core';
|
|
97
|
+
import {NavigationConsumerService} from '@ama-mfe/ng-utils';
|
|
98
|
+
import {ThemeConsumerService} from "./theme.consumer.service";
|
|
99
|
+
|
|
100
|
+
@Component({
|
|
101
|
+
selector: 'app-example-module',
|
|
102
|
+
template: './example-module.template.html',
|
|
103
|
+
styleUrl: './example-module.style.scss',
|
|
104
|
+
})
|
|
105
|
+
export class ExampleModuleComponent {
|
|
106
|
+
private readonly navigationConsumerService = inject(NavigationConsumerService);
|
|
107
|
+
|
|
108
|
+
constructor() {
|
|
109
|
+
this.navigationConsumerService.start();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
ngOnDestroy() {
|
|
113
|
+
this.navigationConsumerService.stop()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Depending on your use case, you might need to start the service as soon as your application start running.
|
|
119
|
+
In this case, you may inject it in the `main.ts`:
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// main.ts
|
|
123
|
+
import {inject, runInInjectionContext} from '@angular/core';
|
|
124
|
+
import {bootstrapApplication} from '@angular/platform-browser';
|
|
125
|
+
import {ConnectionService, ThemeConsumerService} from '@ama-mfe/ng-utils';
|
|
126
|
+
|
|
127
|
+
bootstrapApplication(AppComponent, appConfig)
|
|
128
|
+
.then((m) => {
|
|
129
|
+
runInInjectionContext(m.injector, () => {
|
|
130
|
+
if (window.top !== window.self) {
|
|
131
|
+
// If embedded in an iframe, connect to the host
|
|
132
|
+
inject(ConnectionService).connect('hostUniqueID');
|
|
133
|
+
// Start the service to consume messages
|
|
134
|
+
inject(ThemeConsumerService).start();
|
|
135
|
+
}
|
|
136
|
+
// Other injections
|
|
137
|
+
})
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Producers
|
|
142
|
+
If your application is a producer, just inject the message producer service and call the trigger when needed.
|
|
143
|
+
There is no standardization on the name of the methods used to trigger a message. It will be different for each service.
|
|
144
|
+
|
|
145
|
+
#### Services provided in @ama-mfe/ng-utils
|
|
146
|
+
You will find more information for each service in their respective `README.md`:
|
|
147
|
+
- [Navigation](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-mfe/ng-utils/src/navigation/README.md)
|
|
148
|
+
- [Resize](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-mfe/ng-utils/src/resize/README.md)
|
|
149
|
+
- [Theme](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-mfe/ng-utils/src/theme/README.md)
|
|
150
|
+
|
|
151
|
+
### Write your own producer and consumers.
|
|
152
|
+
Use the `ProducerManagerService` and the `ConsumerManagerService` to support your own custom messages.
|
|
153
|
+
|
|
154
|
+
A message should be identified by its type and a version to allow different message versions between the host and the
|
|
155
|
+
embedded applications (and avoid migration issues).
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import type {Message} from '@amadeus-it-group/microfrontends';
|
|
159
|
+
|
|
160
|
+
export interface CustomMessageV1_0 extends Message {
|
|
161
|
+
type: 'custom',
|
|
162
|
+
version: '1.0',
|
|
163
|
+
// Custom properties
|
|
164
|
+
customPayload: any
|
|
165
|
+
}
|
|
166
|
+
// Use union type here to add all the future version
|
|
167
|
+
// For example CustomMessage = CustomMessageV1_0 | CustomMessagev2_0
|
|
168
|
+
export type CustomMessageVersions = CustomMessageV1_0;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Consumer
|
|
172
|
+
A consumer should implement the `MessageConsumer` interface and inject the `ConsumeManagerService` which handles the
|
|
173
|
+
registration to the communication protocol.
|
|
174
|
+
It should list the supported versions and map its callback function in a `supportedVersions` public object.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import type {CustomMessageV1_0, CustomMessageVersions} from '@ama-mfe/messages';
|
|
178
|
+
import type {RoutedMessage} from '@amadeus-it-group/microfrontends';
|
|
179
|
+
import {DestroyRef, inject, Injectable} from '@angular/core';
|
|
180
|
+
import {ConsumerManagerService, type MessageConsumer} from '@ama-mfe/ng-utils';
|
|
181
|
+
|
|
182
|
+
@Injectable({
|
|
183
|
+
providedIn: 'root'
|
|
184
|
+
})
|
|
185
|
+
export class CustomConsumerService implements MessageConsumer<CustomMessageVersions> {
|
|
186
|
+
/**
|
|
187
|
+
* The type of messages this service handles ('custom').
|
|
188
|
+
*/
|
|
189
|
+
public readonly type = 'custom';
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* The supported versions of theme messages and their handlers.
|
|
193
|
+
*/
|
|
194
|
+
public readonly supportedVersions = {
|
|
195
|
+
'1.0': (message: RoutedMessage<CustomMessageV1_0>) => console.log('Do some stuff with this message version', message)
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
private readonly consumerManagerService = inject(ConsumerManagerService);
|
|
199
|
+
|
|
200
|
+
constructor() {
|
|
201
|
+
this.start();
|
|
202
|
+
inject(DestroyRef).onDestroy(() => this.stop());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Starts the theme handler service by registering it into the consumer manager service.
|
|
207
|
+
*/
|
|
208
|
+
public start() {
|
|
209
|
+
this.consumerManagerService.register(this);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Stops the theme handler service by unregistering it from the consumer manager service.
|
|
214
|
+
*/
|
|
215
|
+
public stop() {
|
|
216
|
+
this.consumerManagerService.unregister(this);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
#### Producer
|
|
222
|
+
A producer should implement the `MessageProducer` interface and inject the `ProducerManagerService` which handles the
|
|
223
|
+
registration to the communication protocol.
|
|
224
|
+
Once connected, it is able to send messages via the `MessagePeerService`.
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import type {CustomMessageV1_0, CustomMessageVersions} from '../messages';
|
|
228
|
+
import {MessagePeerService} from '@amadeus-it-group/microfrontends-angular';
|
|
229
|
+
import {DestroyRef, inject, Injectable} from '@angular/core';
|
|
230
|
+
import {type MessageProducer, type ErrorContent, ProducerManagerService} from '@ama-mfe/ng-utils';
|
|
231
|
+
|
|
232
|
+
@Injectable({
|
|
233
|
+
providedIn: 'root'
|
|
234
|
+
})
|
|
235
|
+
export class CustomService implements MessageProducer<CustomMessageVersions> {
|
|
236
|
+
private readonly messageService = inject(MessagePeerService<CustomMessageVersions>);
|
|
237
|
+
|
|
238
|
+
constructor() {
|
|
239
|
+
const producerManagerService = inject(ProducerManagerService);
|
|
240
|
+
producerManagerService.register(this);
|
|
241
|
+
|
|
242
|
+
inject(DestroyRef).onDestroy(() => {
|
|
243
|
+
producerManagerService.unregister(this);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
public handleError(message: ErrorContent<CustomMessage_V1_0>): void {
|
|
248
|
+
// If available, use your own logger
|
|
249
|
+
console.error('Error in custom service message', message);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public postMessageAction(payload: any): void {
|
|
253
|
+
const messageV10 = {
|
|
254
|
+
type: 'custom',
|
|
255
|
+
version: '1.0',
|
|
256
|
+
customPayload: 'test'
|
|
257
|
+
} satisfies CustomMessageV1_0;
|
|
258
|
+
this.messageService.send(messageV10);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ama-mfe/ng-utils",
|
|
3
|
-
"version": "12.1.0-prerelease.
|
|
3
|
+
"version": "12.1.0-prerelease.81",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"peerDependencies": {
|
|
8
|
-
"@ama-mfe/messages": "^12.1.0-prerelease.
|
|
8
|
+
"@ama-mfe/messages": "^12.1.0-prerelease.81",
|
|
9
9
|
"@amadeus-it-group/microfrontends": "0.x.x",
|
|
10
10
|
"@amadeus-it-group/microfrontends-angular": "0.x.x",
|
|
11
11
|
"@angular-devkit/core": "~19.2.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"@angular/core": "^19.0.0",
|
|
15
15
|
"@angular/platform-browser": "~19.2.0",
|
|
16
16
|
"@angular/router": "~19.2.0",
|
|
17
|
-
"@o3r/schematics": "^12.1.0-prerelease.
|
|
17
|
+
"@o3r/schematics": "^12.1.0-prerelease.81",
|
|
18
18
|
"rxjs": "^7.8.1"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|