Skip to content

Microfrontends

Kevin Mas Ruiz edited this page Jul 18, 2019 · 3 revisions

Microfrontends have been quite popular recently because they allow to modularize big applications in small applications that will communicate between each other in different ways.

However, as in microservices, microfrontends came with lots of controversy from the community as they enable the same patterns we've seen in the backend, that are dangerous and can be a blocker for big companies.

morphonent allow developers to implement microfrontends in a simple way, that is cheap, easy to test, and predictive. However, they are several things to take into consideration when implementing microfrontends with morphonent:

  • morphonent is a library, it's not opinionated on how you build your microfrontends.
  • morphonent provides a simple way to communicate microfrontends, but you can use yours.
  • morphonent enables microfrontends, but you don't need microfrontends to take advantage of the library and patterns it provides.

In this small tutorial, we are going to implement a basic ping pong example in two microfrontends.

Building the first application

Microfrontends in morphonent are just normal root components that will handle events from other microfrontends. To use microfrontends you will need to learn two new functions that are part of the library: listeningTo and dispatch.

Let's start building a ping component that will show a button. Right now the button will not do anything.

function ping(times) {
    return element('button', {  }, 'ping ' + times)
}

Now we want the ping component to increase the counter of times that has been pinged when a pong event has been dispatched. Here is where we use the new listeningTo function:

function ping(times) {
    return listeningTo({ pong: () => ping(times + 1) },
        element('button', { }, 'ping ' + times))
}

The listeningTo function allows you to wrap a component in a event listener, and apply a handler for each event that has been dispatched. Event handlers act as any other event handler that you'll find in the DOM: they return a new component.

However, we are not yet dispatching any pong event. Let's create a pong component that will do that:

function pong(times) {
    return element('button', { onclick: () => dispatch('pong') && pong(times) }, 'pong ' + times)
}

The new dispatch function allows to send an event to any listener registered with listeningTo and render the new state of the current component. You can send any information of the event in the second parameter of dispatch, like for example:

dispatch('logHappened', { logInfo })

Now, if we render both components, we will see how clicking in the pong component will trigger an update on the ping component. We can connect the components both ways now:

function ping(times) {
    return listeningTo({ pong: () => ping(times + 1) },
        element('button', { onclick: () => dispatch('ping') && ping(times) }, 'ping ' + times))
}

function pong(times) {
    return listeningTo({ ping: () => pong(times + 1) },
        element('button', { onclick: () => dispatch('pong') && pong(times) }, 'pong ' + times))
}

window.onload = () => {
    renderOn('#ping', ping(0))
    renderOn('#pong', pong(0))
}

And the HTML to make it work:

<html>
    <head>
        <script src="main.js"></script>
    </head>
    <body>
        <div id="ping"></div>
        <div id="pong" ></div>
    </body>
</html>

This assumes that you have the setup found in the Getting Started tutorial.

Wrap Up

  • To listen to events sent by foreign microfrontends, use listeningTo.
  • To emit events to other microfrontends, use dispatch.
  • Microfrontends should have only one responsibility.

Clone this wiki locally