Introduction #
I am going to give a brief overview of this proof of concept application I've built [0] and then a series of write-ups will follow detailing the components in a more detailed fashion.
What's a micro frontend? #
A micro frontend is a method of developing frontend applications. What makes micro frontends different is the fact that each component of the application is independently deployable, providing benefits such as:
- Incremental upgrades
- Loose coupling
- Independent deployments
- Autonomous teams
The benefits and alternative approaches to micro frontends are outlined comprehensively in a blog post by Cam Jackson titled Micro Frontends [1].
The goal #
A colleague Adrian Hesketh [2] brought micro frontends to my attention, along with the potential performance benefits it could provide if used in conjunction with Server-Side Rendered (SSR) components and a nifty tool named Hotwire [3].
I decided to build a proof of concept, to test both the performance of the solution and the workflow in which to implement it. The obvious application was the same one that Cam Jackson built for his write-up “Feed me” [4].
Architecture #
In Cam Jackson's example the container app renders micro frontends by loading the react-app's JS and rendering it within the page. The main concern here is that waiting for that JS to be fetched and rendered potentially before any additional data fetching is kicked off means that the first meaningful paint depends on 2 requests, not including the container app, in the case that an API call is required to populate the page.
The way I built Go Feed Me [5] circumvents this by SSR driving the micro frontends, in my case it's a few docker containers hosting Go servers, being orchestrated by Hotwire.
The structure of my application is as follows:
- Container: The application which all micro frontends are fed through.
- Content: Contains the images used for the app and the JSON document containing restaurant information.
- Proxy: A web proxy for routing by path.
- Micro frontends:
- Basket: For updating and displaying basket information.
- Browse: For displaying and searching across restaurants.
- Details: For displaying a restaurant, and it's menu.
- Random: Redirects the user to a random restaurant.
First page load #
The main drivers of the application are turbo frames [6] they are part of the Hotwire tool set. They are used to contain the HTML from each micro front end response. They can also be used to lazy-load content.
This diagram outlines what happens when a user first enters the Go Feed Me website. I've removed the proxy for simplicity, but it decides which container to route traffic to.
- Initial request
- The browser makes a request to the root path of: “/”.
- The proxy routes this to the Container app.
- The container app responds with the basic page structure, including the nav bar and a turbo frame pointed at the restaurants list URL.
- The response also provides the link to the turbo JS file.
- Request to the micro frontend
- Turbo detects the frame in the response and makes a request to the provided restaurants list URL.
- The proxy routes this to the Browse micro frontend.
- The Browse app requires a JSON list of restaurants which is provided by the Content app (this would likely be an API in a real world application).
- The Browse app responds with only the HTML required to populate main content of the page.
- Turbo renders the response within the turbo frame.
- Image loading
- The images for each restaurant is referenced in the micro frontend and are loaded from the content app.
Internal navigation #
Now that the user has the main Container app displayed along with the restaurants list what would happen if they clicked a restaurant to view more details?
- Clicked link
- Turbo intercepts the web request and stops the page from fully reloading.
- The turbo frame is pointed at the Details app URL for their chosen restaurant.
- Request to the micro frontend
- We skip straight to this step now that the Container app is already present.
- The proxy routes this request to the Details app.
- The Details app requests the details of the restaurant from the Content app.
- The Details app responds with only the HTML required to populate the details of the chosen restaurant.
- Turbo replaces the restaurant list with the detail response.
- Image loading
- The images for each restaurant is referenced in the micro frontend and are loaded from the content app.
Conclusion #
This way of building applications allows a high level of separation and decoupling in the codebase, and the SSR responses mean that the latency is sub 100ms 95% of the time.
It also means that each frontend has hyper-focused responsibility, each team only needs to worry about the functionality that their frontend provides.