diff --git a/vuepress/docs/next/tutorials/create/mfe/communication.md b/vuepress/docs/next/tutorials/create/mfe/communication.md index 1106777648..af4ef8dc8d 100644 --- a/vuepress/docs/next/tutorials/create/mfe/communication.md +++ b/vuepress/docs/next/tutorials/create/mfe/communication.md @@ -6,38 +6,21 @@ sidebarDepth: 2 ::: tip Recommended Learning - Tutorial: [Create a React Micro Frontend](react.md) -- Tutorial: [Create an Angular Micro Frontend](angular.md) ::: -Entando supports communication between micro frontends using [Custom Events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent), an established web standard. In this tutorial, we build: +Entando supports communication between micro frontends (MFEs) using [Custom Events](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent), an established web standard. The MFEs can use either the same or different JavaScript frameworks. In this tutorial, we build: -- A React micro frontend that publishes an event -- A React micro frontend that listens to an event -- An Angular micro frontend that publishes an event to a React micro frontend +- A React MFE that publishes an event +- A React MFE that listens to an event +## Prerequisites -## Publisher +- 2 [simple React apps](react.md#create-a-react-app-in-an-entando-bundle): One will be modified to publish an event while the other will be modified to subscribe to an event -Create a simple app to publish an event. +## Modify the Publisher MFE -``` bash -npx create-react-app publisher-widget --use-npm -``` - -Start the app. - -``` bash -cd publisher-widget -``` - -``` bash -npm start -``` +### Create the Custom Event -### Create Custom Event - -Next, add event firing logic. - -Add a new file `publisher-widget/src/PublisherWidgetElement.js`. +1. To add a custom event, create the file `publisher-widget/src/PublisherWidgetElement.js`: ``` js import React from 'react'; @@ -76,22 +59,18 @@ customElements.define('publisher-widget', PublisherWidgetElement); export default PublisherWidgetElement; ``` -- In the `CustomEvent` constructor, `detail` is the specific name to use in the event payload, as per the [DOM specification](https://dom.spec.whatwg.org/#interface-customevent). - -#### Import Custom Element + In the `CustomEvent` constructor, `detail` denotes the specific name to use in the event payload per the [DOM specification](https://dom.spec.whatwg.org/#interface-customevent). -Update `publisher-widget/src/index.js`. +2. To import the custom element, replace the contents of `publisher-widget/src/index.js`: ``` js import './index.css'; import './PublisherWidgetElement'; ``` -#### Test Custom Element +3. To test the MFE, update the `body` section of `publisher-widget/public/index.html`: -Update `publisher-widget/public/index.html`, and view it in the browser. - -``` html +``` js @@ -99,14 +78,16 @@ Update `publisher-widget/public/index.html`, and view it in the browser. ``` -### Update React App to Dispatch Event +4. Confirm the app renders in the browser -Update `publisher-widget/src/App.js`. +### Dispatch the Custom Event + +1. Replace the contents of `publisher-widget/src/App.js`: ``` js import React from 'react'; import './App.css'; - + class App extends React.Component { constructor(props) { super(props); @@ -137,41 +118,25 @@ class App extends React.Component { export default App; ``` -### Test Event Dispatcher - -In the JavaScript console of your browser, enter: +2. In the JavaScript console of your browser, enter the following: ``` js window.addEventListener('greeting', (evt) => console.log('Hello', evt.detail.name)) ``` -Write something in the text field. Click the "Say hello!" button and take a look at the JS console. It will show the event message. +3. To test the event dispatcher, write something in the text field and click the "Say hello!" button + +4. Confirm the event message appears in the JS console ::: tip Congratulations! -You’ve now published a custom event. +You’ve now published a custom event ::: -## Subscriber - -Next, let’s create the subscriber. +## Modify the Subscriber MFE -``` bash -npx create-react-app subscriber-widget --use-npm -``` - -Start the app. - -``` bash -cd subscriber-widget -``` - -``` bash -npm start -``` +### Create the Event Listener -### Add Event Listener - -Add a new file `subscriber-widget/src/SubscriberWidgetElement.js`. +1. To add an event listener, create the file `subscriber-widget/src/SubscriberWidgetElement.js`: ``` js import React from 'react'; @@ -215,30 +180,29 @@ customElements.define('subscriber-widget', SubscriberWidgetElement); export default SubscriberWidgetElement; ``` -#### Import Custom Element - -Update `subscriber-widget/src/index.js`. +2. To import the custom element, replace the contents of `subscriber-widget/src/index.js`: ``` js import './index.css'; import './SubscriberWidgetElement'; ``` -#### Test Micro Frontend -Update `subscriber-widget/public/index.html`, and view it in the browser. +3. To test the MFE, update the `body` section of `subscriber-widget/public/index.html`: -``` html +``` js - + ... ``` -### Display Custom Event +4. Confirm the app renders in the browser -Update `subscriber-widget/src/App.js`. +### Display the Custom Event + +1. Replace the contents of `subscriber-widget/src/App.js`: ``` js import React from 'react'; @@ -252,9 +216,7 @@ function App({ name }) { export default App; ``` -### Test Event Listener - -In the JavaScript console of your browser, enter: +2. To test the event listener, enter the following in the JavaScript console of your browser: ``` js const widgetEvent = new CustomEvent('greeting', { @@ -265,392 +227,51 @@ const widgetEvent = new CustomEvent('greeting', { window.dispatchEvent(widgetEvent); ``` -The custom event should now display in the `subscriber-widget`. +3. Confirm the custom event is displayed in the `subscriber-widget` ::: tip Congratulations! -You’ve now created a micro frontend that listens to custom events. +You’ve now created a micro frontend that listens to custom events ::: ## Add Widgets to App Builder -Now let's add the publisher and subscriber micro frontends in Entando. - -### Create Environment File - -#### Publisher Widget - -1. Create an `.env` file in the project root for the `publisher-widget`. - -2. Open the `.env` file, and enter the `PUBLIC_URL` where the micro frontend will be hosted. - -Example: - -``` -PUBLIC_URL=http://quickstart.192.168.64.34.nip.io/entando-de-app/cmsresources/publisher-widget -``` - -::: tip Notes -- Replace `quickstart.192.168.64.34.nip.io` with the ingress you use to access Entando from your local browser. -- `/entando-de-app/cmsresources/` is your Resource URL. -- `publisher-widget` is the public folder we'll create to host the publisher micro frontend. -::: - -#### Subscriber Widget - -1. Create an `.env` file in the project root for the `subscriber-widget`. - -2. Open the `.env` file, and enter the `PUBLIC_URL` where the micro frontend will be hosted. - -- Use `subscriber-widget` for the name of the public folder we'll create to host the subscriber micro frontend. - -Example: - -``` -PUBLIC_URL=http://quickstart.192.168.64.34.nip.io/entando-de-app/cmsresources/subscriber-widget -``` - -### Run npm build - -#### Publisher Widget - -1. Open a command line, and navigate to the project root of the `publisher-widget`. - -2. Run build. +To add the publisher and subscriber MFEs to Entando, run the following commands from the root folder of each: -``` bash -npm run build ``` - -3. Rename the following generated files in the `build` directory. - -| Example of Generated Build File | Rename to | Function -| :--- | :--- | :--- -| build/static/js/2.f14073bd.chunk.js | `static/js/vendor.js` | Third-party libraries -| build/static/js/runtime-main.8a835b7b.js | `static/js/runtime.js` | Bootstrapping logic -| build/static/js/main.4a514a6d.chunk.js | `static/js/main.js` | App -| build/static/css/main.5f361e03.chunk.css | `static/css/main.css` | Stylesheet - -#### Subscriber Widget - -- Repeat steps 1-3 for the `subscriber-widget`. - -### Create Public Folder - -#### Publisher Widget - -1. Navigate to `Entando App Builder` in your browser. - -2. Go to `Configuration` → `File Browser` → `public` - -3. Click `Create Folder`. - -4. Enter `publisher-widget`. - -5. Click `Save`. - -6. Click `public` → `publisher-widget`. - -7. Create the same folder structure as your generated build directory - -- `publisher-widget/static/css` -- `publisher-widget/static/js` - -8. Upload the files we renamed in the corresponding `js` and `css` folders. - -- `publisher-widget/static/css/main.css` -- `publisher-widget/static/js/main.js` -- `publisher-widget/static/js/runtime.js` -- `publisher-widget/static/js/vendor.js` - -#### Subscriber Widget - -- Repeat steps 1-8 for the `subscriber-widget`. - -### Add Widgets - -#### Publisher Widget - -1. Go to `Entando App Builder` in your browser. - -2. Go to `Components` → `Micro Frontends & Widgets` at the top nav. - -3. Click `Add`. - -4. Enter the following: - -- `Code: publisher_widget` → note: dashes are not allowed -- `Title: Publisher Widget` → for both English and Italian languages -- `Group: Free Access` -- `Custom UI:` - -``` ftl -<#assign wp=JspTaglibs[ "/aps-core"]> - - - - - +ent bundle pack +ent bundle publish +ent bundle deploy +ent bundle install ``` -5. Click `Save`. - -#### Subscriber Widget - -Repeat steps 1-5 for the subscriber widget. - -- `Code: subscriber_widget` → note: dashes are not allowed -- `Title: Subscriber Widget` → for both English and Italian languages -- `Group: Free Access` -- `Custom UI:` - -``` ftl -<#assign wp=JspTaglibs[ "/aps-core"]> - - - - - -``` +Refer to the tutorial on how to [publish a bundle project](../pb/publish-project-bundle.md#create-and-deploy-a-bundle-project) for more detailed instructions. ### View on a Page -You can setup the widgets on an existing page (such as the Home page) or [create your own page](../../compose/page-management.md). The following steps assume you'll use the Home page. -1. Go to `Pages` → `Management` +Place the widgets on an existing page or [create your own page](../../compose/page-management.md). The following steps assume you'll edit the `Home` page. -2. For the `Home` page `(folder icon)`, in the `Actions` column, click the `⋮` icon +1. Go to `Pages` → `Management` -3. Click `Edit`. +2. On the line item for the `Home` page, in the `Actions` column, click the `⋮` icon -4. In the `Settings` section, select a Page Template with more than one frame, e.g. `1-column`: +3. Click `Edit` -- `Page Template: 1 Column` +4. In the `Settings` section, select a Page Template with more than one frame -5. Click `Save and Configure`. +5. Click `Save and Design` -6. In the `WIDGETS` sidebar on the right: +6. From the `Widgets` tab in the right sidebar, drag your publisher and subscriber widgets into `Frame 1` and `Frame 2` -- Drag `Publisher Widget` and `Subscriber Widget` into `Frame 1` and `Frame 2`. +7. Click `Publish` -7. Click `Publish`. +8. To view the `Home` page, scroll up and click `View Published Page` -8. To view the home page, scroll to the top of the page, and click `Go to Homepage`. +9. Enter a name in the input field and click the "Say hello!" button -9. Enter a greeting in the input field. Press the submit button. The subscriber widget will update with the greeting. Done! +10. Confirm that the subscriber widget updates to display the name ::: tip Congratulations! -You can now communicate between micro frontends with `Custom Events`. +You can now communicate between micro frontends using custom events! ::: -## Angular to React - -We can also communicate between micro frontends using different JavaScript frameworks. - -In this next example, we’ll create an Angular micro frontend to publish an event, and we'll use the React micro frontend we created in the previous section to receive the event. - -### Create Angular Publisher - -``` bash -ng new angular-publisher-widget -``` - -Choose the following options: - -``` bash -? Would you like to add Angular routing? No -? Which stylesheet format would you like to use? CSS -``` - -Serve the application. - -``` bash -cd angular-publisher-widget -``` - -``` bash -ng serve -``` - -#### Convert to Custom Element - -Next, let's convert our Angular app into a custom element. We'll use [Angular elements](https://angular.io/guide/elements) to transform components into custom elements. - -``` bash -ng add @angular/elements -``` - -Replace the contents of `angular-publisher-widget/src/app/app.module.ts`. - -- In this file, we bootstrap the custom element using the `ngDoBootstrap` method. - -``` js -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule, Injector } from '@angular/core'; -import { createCustomElement } from '@angular/elements'; -import { AppComponent } from './app.component'; -import { ReactiveFormsModule } from '@angular/forms'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, - ReactiveFormsModule - ], - providers: [], - entryComponents: [AppComponent] -}) -export class AppModule { - constructor(private injector: Injector) {} - - ngDoBootstrap() { - const el = createCustomElement(AppComponent, { injector: this.injector }); - customElements.define('angular-publisher-widget', el); - } -} -``` - -#### Create Custom Event - -Replace the contents of `angular-publisher-widget/src/app/app.component.ts`. - -- Here, we're adding code to dispatch the custom event. - -``` js -import { Component } from '@angular/core'; -import { FormControl, FormGroup } from '@angular/forms'; - -const EVENTS = { - greeting: 'greeting', -}; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] -}) -export class AppComponent { - greetingForm = new FormGroup({ - name: new FormControl(''), - }); - - publishWidgetEvent(eventId, detail) { - const widgetEvent = new CustomEvent(eventId, { detail }); - window.dispatchEvent(widgetEvent); - } - - onSubmit() { - const name = this.greetingForm.get('name').value; - this.publishWidgetEvent(EVENTS.greeting, { name }); - } -} -``` - -#### Add HTML Form - -Replace the contents of `angular-publisher-widget/src/app/app.component.html`. - -- In the app component html, we're adding a simple form to call our component class `app.component.ts`. - -``` html -

Send a greeting

-
- - -
-``` - -#### View Micro Frontend - -Open `angular-publisher-widget/src/index.html`. - -In the ``, replace `` with your custom element ``. - -``` html - - - -``` - -You can check to see if your micro frontend is working in your browser (e.g., localhost:4200) - -### Add to App Builder - -Now we're ready to host our micro frontend in Entando. - -#### Build It - -From the project root, type: - -``` bash -ng build --prod --outputHashing=none -``` - -This will generate a `dist` directory. - -#### Create Public Folder - -1. Navigate to `Entando App Builder` in your browser. - -2. Click `Configuration` → `File Browser` → `public`. - -3. Create a folder named `angular-publisher-widget`. - -3. Click `Upload Files`. - -4. From your generated `dist` folder, upload: - -- `main-es2015.js` -- `polyfills-es2015.js` -- `runtime-es2015.js` - -#### Add Widget -1. Go to `Components > Micro frontends & Widgets` in the Entando App Builder. - -2. Click `Add` at the lower right. - -3. Enter the following: - -- `Code: angular_publisher_widget` → note: dashes are not allowed -- `Title: Angular Publisher Widget` → for both English and Italian languages -- `Group: Free Access` -- `Custom UI:` - -``` ftl -<#assign wp=JspTaglibs[ "/aps-core"]> - - - - - -``` - -4. Click `Save`. - -#### View on Homepage - -1. Go to `Pages` → `Management` - -2. Next to the `Home` page `(folder icon)`, in the `Actions` column, click the `⋮` icon - -3. In the Search field in right-hand sidebar, enter `Angular Publisher Widget`. - -4. Drag and drop `Angular Publisher Widget` into the `Sample Frame` in the main body of the page. - -> Replace `Publisher Widget`. - -5. Click `Publish`. - -6. In the top navigation, on the right, click `Go to Homepage`. - -7. Enter a greeting in the input field. Press the submit button. The subscriber widget will update with the greeting. Done! - -- Note: If you don't see an input field, refresh the page. - -::: tip Congratulations! -You've now created an Angular micro frontend that can communicate with a React micro frontend. -:::