Micro-Frontends Are Remote UI Components

Also: Seven reasons why you might not want/need remote UI rendering

Dan Fabulich
Code Red

--

Dan Fabulich is a Principal Engineer at Redfin. (We’re hiring!)

When I first read the definition of micro-frontends, I didn’t “get it.” Specifically, when I read Cam Jackson’s article on martinfowler.com and Michael Geers’ mini-site micro-frontends.org, I was still asking myself questions like:

  • Are we already doing micro-frontends? We’ve been using UI component frameworks for years. Are micro-frontends just UI components?
  • If not, how would our code be different if we were using micro-frontends?
  • But, seriously, what are micro-frontends?!

After more thinking and research, I’ve now figured out why I was struggling: both articles go to some lengths to avoid giving “micro-frontends” a clear definition, instead preferring to define the term using code examples and analogies. I think I’ve figured out a simple definition that makes more sense to me; I hope it makes more sense to you.

Micro-frontends are remote UI components, where subcomponent renderer code runs in a separate process from the “composer” code that composes subcomponents.

As a result of running subcomponents in separate processes:

  • You can redeploy/restart a “micro-frontend” subcomponent process without redeploying/restarting other subcomponents, or the composer process. If a subcomponent process crashes, it doesn’t take down the other processes.
  • The subcomponent processes don’t have to share any code with the composer. Taken to an extreme, each subcomponent can use its own UI component framework. (We probably want to avoid this, but if we want to switch frameworks, it’s nice to have this tool in our toolbox.)
  • The composer can be very lightweight, since it doesn’t have to include subcomponent code. This is especially useful when the composer has to run on the client side, where downloading more code means launching more slowly.
  • Subcomponents can render in parallel. (You don’t have to run subcomponents in separate processes to render them in parallel, but running them in separate processes does ensure that subcomponents can be run in parallel.)
  • As in any distributed system, sometimes the composer may be unable to access its subcomponents. Ideally, the composer can fail gracefully, rendering at least some parts of the UI that are available. (But, on the other hand, we might want a particular component to fail completely if certain critical subcomponents aren’t available.)

There are many kinds of remote UI components (many kinds of micro-frontends)

UI components come in many shapes and sizes; each UI framework offers a different approach to composing UI out of reusable pieces. Similarly, there’s a wide variety of UI frameworks that support remote UI rendering.

  • Server-side frameworks can have remote subcomponents. For example, you can have a no-JS server-side composer that requests pre-rendered HTML fragments from other backend services and assembles them into an HTML document. (This composer can be as simple as a web proxy, e.g. edge-side includes.)
  • Some client-side frameworks, like Turbo (aka Turbolinks), support fetching different parts of the UI with parallel requests and composing them on the client side.
  • Or you can go old-school and build a page out of <iframe>s! (But iframes mess with the browser’s back button—they’re like a miniature tab in the middle of your webpage—so you might prefer to use a lightweight mini-framework, making little gadgets that look like iframes but don’t mess with the back button.)
  • New in 2021, React has Server Components whose code runs only on the server side; React can fetch the HTML for these components and embed them into the page without requiring the client to download client-side code to render/rerender the components.

This is the reason why why it’s so hard to wrap your head around micro-frontends. There are so many different kinds of micro-frontends, at least as many as there are UI frameworks. It’s notoriously difficult to do an apples-to-apples comparison of UI frameworks, and micro-frontend frameworks are no exception.

Seven reasons why you might not want/need remote UI rendering

Micro-frontends are the right choice for organizations that can afford the overhead in order to scale up. But you might not be able to afford the overhead, and you might not need those benefits in order to scale.

  • All of the popular introductions to micro-frontends talk about how micro-frontends “allow” you to have multiple full-stack teams of developers, each team owning their own frontend and backend code. But you don’t have to use remote UI components to have multiple full-stack teams. You can have a monolithic UI runtime, where each team owns UI components that run together in the same process. (This is how most native apps have worked, since forever.) But beware, any one component in a monolithic UI process can take the whole app down with it.
  • If subcomponents need to communicate with each other, it may be faster/easier to run them in the same process.
  • If each subcomponent process is running duplicated framework code, it may save server resources (memory/CPU/money) to combine them into a single process. In addition, each process has to be monitored separately, which adds to the overhead of a distributed system.
  • If you don’t need to redeploy subcomponents separately, you might not need remote UI components. (For example, if all subcomponents share the same UI framework, and you redeploy all subcomponents whenever you upgrade the framework, it might be better to just run them all in a single process and redeploy them all whenever any subcomponent changes.)
  • You might want to run all of your code in a single process on the client for performance reasons. First-load performance is typically faster when you render on the server, running as little code as possible on the client, but once the client has all of the code, second-load performance can be faster when you render on the client, making as few network requests as possible. It’s a tradeoff!
  • Sometimes we don’t want/need graceful degradation, when we want the whole UI to show an error if any component isn’t available.
  • It’s possible to allow UI teams to deploy on different schedules while running code in a monolithic UI runtime by having the composer download renderer code, rather than requesting rendered UI from separate services. On the client side, this is the difference between rendering remote HTML in an <iframe> vs. downloading remote <script> and running it in the current page. (This is a typical pattern for “Login with Google/Facebook/Apple” buttons.) When you download renderer code at runtime, you get the advantages of decoupled deploys and easy communication between components, but you also take on the risk of one component crashing the entire UI.

P.S. Redfin is hiring.

A puzzle piece built out of smaller puzzle pieces. It’s like life.

--

--