/module-federation-example

Example of Micro-Frontend Architecture via Module Federation 🤝

Primary LanguageJavaScriptOtherNOASSERTION

Module Federation Example

About The Project

The purpose of this project is to demonstrate an example of a Micro-Frontend Architecture powered by Webpack 5 Module Federation. This reference architecture is to demonstrate the capabilities and is not meant as a production grade example.

Micro-Frontend Architecture enables teams to work independently, in parallel.

Module Federation is how we stitch together the work done by these independent teams, at runtime.

In the context of this project, the home app is the host, while the pdp and cart apps are the remotes. While each app runs on a separate port, http://localhost:3000 is where we will see our app being stitched together at runtime.

Please see the Notes and Resources sections at the end of this document for some additional thoughts and materials I put together while researching and building this project.

In this reference architecture I am building a e-commerce application using a Cart, a PDP (Product Display Page), and a Login to demonstrate state management, module federation, and error handling.




Architecture

An example of how modules are stitched together in this project (http://localhost:3000/product/2):


illustration of how modules are stitched together in project

In the illustration above I highlight how the components are stitched together.

  • The home application is the host
    • home pulls in the remote <PDPContent /> module that is exposed by the PDP application
  • The PDP application pulls in the remote <ReviewsContent /> module that is exposed by the Reviews application
    • <ReviewsContent /> is considered a child component of the <PDPContent /> module and error handling will need be to done in the <PDPContent /> module in the event the <ReviewsContent /> module could not be rendered.

Built With

  • Frontend(s)
    • React 18
    • React Router
    • Webpack 5
      • Module Federation Plugin
    • Zustand
      • See ADR under adr directory
    • Tailwind
  • Backend
    • Nest
    • TypeScript



Getting Started

Follow theses steps to get the project up and running locally.

Prerequisites

This is an example of how to list things you need to use the software and how to install them.

  • npm

    npm install -g npm@latest

Installation

*NOTE: In the project's current state, all apps need to be running in order for any single app to work. Once you have gone through the installation steps, refresh each page if you are seeing blank screens.

  1. Clone the repo

    git clone https://github.com/LucasFrazier/module-federation-example.git
  2. For each directory (home, pdp, cart, reviews, server do the following.

  3. cd into the directory

    cd <directory>
  4. run npm install

    npm install
  5. For home, pdp, cart, & reviews run npm run build

    npm run build
  6. run npm start

    npm start
  7. Refresh browser windows




Usage

Basics

The project mimics an ecommerce site experience and consists of 5 separate applications: home, pdp, cart, reviews, and server.

In this project, home is the host, while pdp, cart, and reviews are the remotes

Each application runs on a separate port:

Once all apps are running, navigate to http://localhost:3000 to begin using the stitched together site.

Most of the magic is happening in the webpack.config.js files within the home, pdp, cart, and reviews apps. Looking at the ModuleFederationPlugin settings in each file will show you what is being exposed (exposes: {...}- see cart's webpack ) and what is being consumed (remotes: {...}).

The exposed data becomes available via a remoteEntry.js file that Webpack creates in the dist directory at the root of each app.

For example, in the context of our application, pdp exposes <PDPContent />, and then home hosts that content when the user navigates to /product/:id.

A basic example really is that straightforward. If you know how to import/export, you know how to use Module Federation.


Actions You Can Take

You can use the username, sally, and the password, 123 to log in, or you can remain logged out.

You can add products to your cart from the Home and PDP pages. You can view your cart on the Cart page or at any time using the cart icon in the global header.

  • Your cart will remain in state as you navigate around the site, but the data will be cleared on refresh
  • I have also implemented state "freshness" controls
    • If a user navigates to /cart or clicks the cart icon in the top nav, a "freshness" check is run
    • If a user is logged in and the timestamp on the cart is older than 5 seconds, I fetch fresh cart data from the server
    • You can test this by logging in, adding some new products to cart, and waiting 5 seconds
      • Your cart will be reset to two items the next time you navigate to /cart or click the cart icon

Error Handling

If you navigate to http://localhost:3000/product/2, you will see that the reviews module is broken.

I am catching this error using an Error Boundary component.

What to do about the error

  • You can fix the error by commenting out or removing {x.toString()} in reviews/src/Reviews.jsx
  • You can remove the <ErrorBoundary /> that wraps <Reviews />
    • If you do this, you will see the PDP <ErrorBoundary /> catch the error
      • You could take this even further, removing the <ErrorBoundary /> that wraps <PDPContent />
        • In which case you will see the Home <ErrorBoundary /> catch the error

*Note: I have a Roadmap item for creating / exposing a reusable Error Boundary component in the home app




Roadmap

  • Implement State Management Solution
  • Implement Error Handling
  • Upgrade Tailwind CSS v2 -> v3
  • Utilize Quantity Property on Cart Items
  • Create new app template
  • Create / Expose reusable Error Boundary component in home app
  • Create global config for Tailwind CSS



Notes

  • You can use Module Federation to share any kind of JavaScript
  • Modules can be updated at runtime
  • State Management can be implemented in all the most common ways
    • Prop Drilling, Context, Zustand, Redux, etc.
  • CSS is not something you can share across Module Federation
    • Must be JS or CSS-in-JS
  • Error Handling can be accomplished by using a combination of
  • Routes can be controlled under a namespace
    • In this project, this is enforced by the host app, home

Resources




Back to Top