How to Develop Microfrontends Using React: Step-by-Step Guide

Rumesh Eranga Hapuarachchi
Bits and Pieces
Published in
10 min readJul 28, 2020

--

With the advancements of microservices, large applications have benefited in several ways. It helps to efficiently develop, deploy, and scale individual pieces of the application backend. Still, many realized that similar challenges exist for the frontend as well. That is where we typically start decomposing the frontend monolith into micro frontends.

Image by Marna from Pixabay

A Microfrontend is a piece of the frontend, which a team can independently develop, test, and deploy as a unit. However, we need to ensure that we glue these pieces together to represent a single web application to the end-users.

So here are the important things you ultimately want:

1. Split app development into simple, decoupled component codebases
2. Make teams autonomous to build and deliver components — fast
3. Efficiently integrate and share components across many apps
4. Streamline collaboration, changes, and updates
5. Ensure design and development consistency

This can all be achieved with the right component infrastructure. You can build apps and experiences together with independent components, and solve the hard parts about scaling frontend development.

Learn more:

Also watch this demo showing how to extract a feature as an independent component and integrating it back as an MFE in runtime and build time:

Strategies for composing microfrontends

There are mainly two approaches. One approach is to use a single container app composing and hosting each microfrontend. The other approach is to host them separately (similar to pages in a website) where each knows the URL (integration points) with parameters to navigate to the other.

I have used the container app approach in this article. There are different ways to combine microfrontends into the container app. These methods vary from server-side using composition, integration at the front end build time, and at run time. Besides, If you opt into runtime integration, you have multiple choices such as integrate applications using iframes, integrate using JavaScript, or integrate using Web Components.

This article demonstrates a quite naive workflow, and does not go into all the expected challenges of implementing a Micro Frontend design. One obvious challenge is sharing components between repositories (a repo for each micro frontend). That’s crucial both for a consistent UI and for a maintainable and scalable project.

Developing Microfrontends using React

In the real world, microfrontend carries a decent amount of scope. But for this exercise let’s consider a simple web application built with react that shows random images of cats and dogs.

Cats and Dogs Web App

I will be breaking the above application into microfrontends taking you through each step in detail with the relevant code snippets. Then we will be combing them using a container app as the underlying host.

Step 1: Create the underlying project structure using React

In this application, let’s separate the cats’ and dogs’ components into separate applications representing the microfrontends. This approach gives more flexibility to select a wide range of methods to glue them together to a single application.

Now that you are familiar with the concepts of microfrontends, it is time for you to implement something with what you learned so far. We will use the same cats and dogs example application here. We will create a Container app, Cats app, and a Dogs app using React.

You can start from scratch and follow the steps below. If you are familiar with React fundamentals and want to work on converting these applications into microfrontends, you can download the boilerplate using this link and jump into the Converting to Microfrontends section.

  1. Create three React projects using create-react-app I will name these three as the container, cats, and dogs.
npx create-react-app containernpx create-react-app catsnpx create-react-app dogs

2. Now let's work on the smallest microfrontend of our project, which is the Dogs app. In this project, we intend to show a random picture of a dog. The user can click a button to get a new image of a dog.

First clear everything in the App.css file. We don’t need any styling here for now.

Then update the content of the App.js with the following.

App.js of Dogs project

Now you can test your application by starting your application. You will be able to the page as shown below.

yarn start
Preview of Dog App

3. Now its time to update the functionality of the Cats application. In this application, the specialty is that it supports routing. There are two routes to our application. One is the root URL, and it will show us a random cat. Next one should listen to cats/{greeting} and should show us an image of a cat with the param greeting .

First, let's add routing and history support by adding react-router-dom and history . To do this, navigate to your Cats application and execute.

yarn add react-router-dom history

Now lets clear everything in App.css as we don’t need any styling here. After that let's create two components named RandomCat and GreetingCat inside src directory.

Update RandomCat.js with the following code. It is pretty equal to the Dog component.

RandomCat.js

As the next step, we have to create the GreetingCat component. The objective of this component is to listen to the greeting parameter and generate an image accordingly.

GreetingCat.js

Now it is time to add routing to the Cats app. To do this, modify the App.js and add the following content.

App.js of Cats application

Cats application should look like the following.

The main route of the Cats app
Greeting Cat route of the Cats app

Now we have two applications. The next step is to create a container application. Our objective is to have Dog app and Cat app (RandomCat component) in the root, and when navigated, it should present us with the GreetingCat component.

First, add react-router-dom and history packages to the Container app.
yarn add react-router-dom history

Then update the App.js with the following content.

App.js of Container

It is time to add styling to the Container application. Replace the content of App.css the following stylings.

Step 2: Converting to Microfrontends

The first problem we have to solve is how does the container app know about the microfrontends. To address this, we can use the .env file to maintain the list of microfrontends.

When it comes to local development, all the microfrontends will run on the localhost, and we need to allocate different ports to our MFEs. Let's use the following ports.
1. Container App: Port 3000
2. Dogs App: Port 3001
3. Cats app: Port 3002

Create the .env file in the container app root level with the following content.

Now we know from where to get each microfrontend. But how does the Container app know how to add microfrontends to the relevant section of the app?

To address this question, all our micro app development teams must agree on how to define the entry point and how to discover apps. In this example, the way we are going to tackle is to use the asset-manifest.json created by the build scripts.

asset-manifest.json of Dogs app

If you look closely, you can see inside the files object we have the main.js file path. Build scripts that will bundle the entire application to main.js. Inside this main.js we must have a function to render as well as unmount the component. Let's use the following convention.

Render function name: render{AppName}
Unmount function name: unmount{AppName}

Example: Dogs app function names

renderDogs
unmountDogs

Since now we know how to render and unmount a component, it is time for us to create a generic component inside the Container app to hold these microfrontends. Let's start by adding the MicroFrontend component to the Container App. Here I have used Cam Jackson’s MicroFrontend component as the base.

Create src/MicroFrontend.js in the Container app.

MicroFrontend.js

This MicroFrontend the component will take name, host, and history as params. If you look at line 17, you will see that this component will first fetch the asset-manifest.json from the host and create a script object using the main.js file. After that, it will use the render function to mount component.

The next step is to use this component and mount Cat application and Dogs application to our app. To do this, modify the App.js of the container as follows.

Updated App.js of Container

Form line 10 till line 13, the objective is to read the app servers form .env file. If you read from lines 24–41, you will notice that we have created three components using microfrontends.

Lines 81–82 will tell the application that the app should render these routes. At the root path, we will render both Cats app and the Dogs app. However, for the/cat/:greeting path, we will only render the Cats app. The same route will be visible for Cats microfrontend as well. So it will render an image of a cat with a text as expected.

That is it for the container. Now it is time to modify existing microfrontends.

Step 3: Modify Cats and Dogs microfrontend apps.

Modify Cats microfrontend app

We must add react-app-rewired, history and react-router-dom to Cats application.

yarn add react-app-rewired history react-router-dom

When the container app tries to load the MFE, everything should be in one JS file. But if you look at the above asset-manifest.json you can see there are multiple chunks available. We must disable the chunking. To do this, we will use thereact-app-rewired package. Using this, we can override the build config without ejecting the app. Create config-overrides.js in the root level of Cats application and add the following content.

config-overrides.js

The next step is to instruct package.json to use this override. Update the scripts section as follows. Then you will notice that it has removed all the chunks and bundle everything to main.js.

package.json
asset-manifest.json after configuring to ignore chunking.

As all our microfrontends and container will be hosted in different subdomains, we must enable CORS in all our microfrontends. To do this create src/setupProxy.js and add the following content.

setupProxy.js

The final modification we need for the Cats microfrontend is to update its index.js with the render function and unmount function. To do this, edit the index.js with the following content

index.js of Cats microfrontend

Modify Dogs microfrontend app.

You have to repeat the same changes as Cats application. Make sure to update the port address inside package.json to 3001 and to edit the function names inside index.js.

If you configured everything successfully, you would be able to see the final result below.

Final Result. A container and two microservices with routing support

Recap

In this article, we discussed the basics of microfrontends and how to implement microfrontends successfully using React.

First, we created a container app and a Placeholder component called MicroFrontend, which knows how to render and unmount a microfrontend to the container. Next, we discussed how to convert our existing application into a microfrontend. Finally, we discuss how we can use the address bar to communicate with different microfrontends.

You can find the sources in following GitHub repos.

  1. https://github.com/rehrumesh/react-microfrontend-container
  2. https://github.com/rehrumesh/react-microfrontend-container-cats-app.git
  3. https://github.com/rehrumesh/react-microfrontend-container-dogs-app

Build Microfrontends with reusable components

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

Learn more

--

--