# Communicate Between Micro Frontends

Recommended Learning

Entando supports communication between micro frontends (MFEs) using Custom Events (opens new window), an established web standard. The MFEs can use either the same or different JavaScript frameworks. In this tutorial, we build:

  • A React MFE that publishes an event
  • A React MFE that listens to an event

# Prerequisites

  • 2 simple React apps: One will be modified to publish an event while the other will be modified to subscribe to an event

# Modify the Publisher MFE

# Create the Custom Event

  1. To add a custom event, create the file publisher-widget/src/PublisherWidgetElement.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const EVENTS = {
  greeting: 'greeting',
};

class PublisherWidgetElement extends HTMLElement {

  constructor() {
    super();
    this.onGreet = name => this.publishWidgetEvent(EVENTS.greeting, { name });
  }

  connectedCallback() {
    this.mountPoint = document.createElement('div');
    this.appendChild(this.mountPoint);
    this.render();
  }

  publishWidgetEvent(eventId, detail) {
    const widgetEvent = new CustomEvent(eventId, { detail });
    window.dispatchEvent(widgetEvent);
  }

  render() {
    ReactDOM.render(<App onGreet={this.onGreet} />, this.mountPoint);
  }
}

customElements.define('publisher-widget', PublisherWidgetElement);

export default PublisherWidgetElement;

In the CustomEvent constructor, detail denotes the specific name to use in the event payload per the DOM specification (opens new window).

  1. To import the custom element, replace the contents of publisher-widget/src/index.js:
import './index.css';
import './PublisherWidgetElement';
  1. To test the MFE, update the body section of publisher-widget/public/index.html:
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <publisher-widget />
    ...
  </body>
  1. Confirm the app renders in the browser

# Dispatch the Custom Event

  1. Replace the contents of publisher-widget/src/App.js:
import React from 'react';
import './App.css';
   
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: ''};
  }

  handleNameChange(value) {
    this.setState(prevState => ({
      ...prevState,
      name: value,
    }));
  }

  render() {
    const { name } = this.state;
    const { onGreet } = this.props;
    return (
      <div>
        <h1>Send a greeting</h1>
        <label htmlFor="name">Name</label>
        <input id="name" onChange={e => this.handleNameChange(e.target.value)} value={name} />
        <button onClick={() => onGreet(name)}>Say hello!</button>
      </div>
    );
  }
}

export default App;
  1. In the JavaScript console of your browser, enter the following:
window.addEventListener('greeting', (evt) => console.log('Hello', evt.detail.name))
  1. To test the event dispatcher, write something in the text field and click the "Say hello!" button

  2. Confirm the event message appears in the JS console

Congratulations!

You’ve now published a custom event

# Modify the Subscriber MFE

# Create the Event Listener

  1. To add an event listener, create the file subscriber-widget/src/SubscriberWidgetElement.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const EVENTS = {
  greeting: 'greeting',
};

class SubscriberWidgetElement extends HTMLElement {

  constructor() {
    super();
    this.name = null;
    this.subscribeToWidgetEvent(EVENTS.greeting, (evt) => this.onGreeting(evt.detail.name));
  }

  connectedCallback() {
    this.mountPoint = document.createElement('div');
    this.appendChild(this.mountPoint);
    this.render();
  }

  subscribeToWidgetEvent(eventType, eventHandler) {
    window.addEventListener(eventType, eventHandler);
  }

  onGreeting(name) {
    this.name = name;
    this.render();
  }

  render() {
    ReactDOM.render(<App name={this.name} />, this.mountPoint);
  }
}

customElements.define('subscriber-widget', SubscriberWidgetElement);

export default SubscriberWidgetElement;
  1. To import the custom element, replace the contents of subscriber-widget/src/index.js:
import './index.css';
import './SubscriberWidgetElement';
  1. To test the MFE, update the body section of subscriber-widget/public/index.html:
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <subscriber-widget />
    ...
  </body>
  1. Confirm the app renders in the browser

# Display the Custom Event

  1. Replace the contents of subscriber-widget/src/App.js:
import React from 'react';
import './App.css';

function App({ name }) {
  return name ? (<h2>Just got a greeting from {name}</h2>)
    : (<h2>Waiting for a greeting...</h2>);
}

export default App;
  1. To test the event listener, enter the following in the JavaScript console of your browser:
const widgetEvent = new CustomEvent('greeting', {
  detail: {
    name: 'Pippo'
  },
});
window.dispatchEvent(widgetEvent);
  1. Confirm the custom event is displayed in the subscriber-widget

Congratulations!

You’ve now created a micro frontend that listens to custom events

# Add Widgets to App Builder

To add the publisher and subscriber MFEs to Entando, run the following commands from the root folder of each:

Refer to the tutorial on how to publish a bundle project for more detailed instructions.

# View on a Page

Place the widgets on an existing page or create your own page. The following steps assume you'll edit the Home page.

  1. Go to PagesManagement

  2. On the line item for the Home page, in the Actions column, click the icon

  3. Click Edit

  4. In the Settings section, select a Page Template with more than one frame

  5. Click Save and Design

  6. From the Widgets tab in the right sidebar, drag your publisher and subscriber widgets into Frame 1 and Frame 2

  7. Click Publish

  8. To view the Home page, scroll up and click View Published Page

  9. Enter a name in the input field and click the "Say hello!" button

  10. Confirm that the subscriber widget updates to display the name

Congratulations!

You can now communicate between micro frontends using custom events!