Complete Beginner’s Guide to Micro Frontends - Day 1

Let’s build your first micro frontend application step-by-step. I’ll guide you through creating a simple setup with two micro frontends that can work together.

Prerequisites

  • Basic knowledge of JavaScript (no expert knowledge needed)
  • Node JS installed (download from nodejs.org if you don’t have it)

Step 1: Check Your Environment

Open your terminal/command prompt and verify your tools:

node -v  
# Should show v16.x.x or higher

npm -v  
# Should show 7.x.x or higher

Step 2: Create Project Structure

First, let’s create our project folders:

# Create main project directory
mkdir my-first-microfrontends  
cd my-first-microfrontends

# Create directories for our container and microfrontend
mkdir container  
mkdir product-list  

Step 3: Set Up the Container App

The "container" is our main application that will host the micro frontends.

# Navigate to container directory
cd container

# Initialize a new npm project
npm init -y

# Install dependencies
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev  
npm install react react-dom  

Step 4: Configure Webpack for the Container

Create a webpack configuration file for the container:

# Create webpack config file
touch webpack.config.js  

Now open webpack.config.js in your code editor and add the following:

const HtmlWebpackPlugin = require("html-webpack-plugin");  
const { ModuleFederationPlugin } = require("webpack").container;  
const path = require("path");

module.exports = {  
  entry: "./src/index",
  mode: "development",
  devServer: {
    static: {
      directory: path.join(__dirname, "dist"),
    },
    port: 3000,
  },
  output: {
    publicPath: "http://localhost:3000/",
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-react"],
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "container",
      remotes: {
        productList: "productList@http://localhost:3001/remoteEntry.js",
      },
      shared: { react: { singleton: true }, "react-dom": { singleton: true } },
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

Step 5: Create Container App Files

Create the necessary directories and files:

mkdir -p src public  
touch public/index.html  
touch src/index.js  
touch src/App.js  
touch .babelrc  

Add content to .babelrc:

{
  "presets": ["@babel/preset-react"]
}

Add content to public/index.html:

<!DOCTYPE html>  
<html>  
  <head>
    <title>Micro Frontend Demo</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>  

Add content to src/App.js:

import React from "react";

// Lazy load the ProductList component from the product-list micro frontend
const ProductList = React.lazy(() => import("productList/ProductList"));

const App = () => {  
  return (
    <div style={{ fontFamily: "'Open Sans', sans-serif", padding: '20px' }}>
      <h1>My Micro Frontend Demo</h1>
      <p>This is the container application.</p>
      <hr />
      <h2>Product List Micro Frontend:</h2>
      <React.Suspense fallback={<div>Loading Product List...</div>}>
        <ProductList />
      </React.Suspense>
    </div>
  );
};

export default App;  

Add content to src/index.js:

import React from "react";  
import ReactDOM from "react-dom";  
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));  

Step 6: Install Babel Dependencies

npm install @babel/core @babel/preset-react babel-loader --save-dev  

Step 7: Set Up the Product List Micro Frontend

Now let’s create our first micro frontend:

# Navigate back to the main directory and into product-list
cd ..  
cd product-list

# Initialize a new npm project
npm init -y

# Install dependencies
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev  
npm install react react-dom  
npm install @babel/core @babel/preset-react babel-loader --save-dev  

Step 8: Configure Webpack for the Product List Micro Frontend

Create a webpack configuration file:

touch webpack.config.js  

Add the following content to webpack.config.js:

const HtmlWebpackPlugin = require("html-webpack-plugin");  
const { ModuleFederationPlugin } = require("webpack").container;  
const path = require("path");

module.exports = {  
  entry: "./src/index",
  mode: "development",
  devServer: {
    static: {
      directory: path.join(__dirname, "dist"),
    },
    port: 3001,
  },
  output: {
    publicPath: "http://localhost:3001/",
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: "babel-loader",
        exclude: /node_modules/,
        options: {
          presets: ["@babel/preset-react"],
        },
      },
    ],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "productList",
      filename: "remoteEntry.js",
      exposes: {
        "./ProductList": "./src/ProductList",
      },
      shared: { react: { singleton: true }, "react-dom": { singleton: true } },
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

Step 9: Create Product List Micro Frontend Files

Create the necessary directories and files:

mkdir -p src public  
touch public/index.html  
touch src/index.js  
touch src/ProductList.js  
touch src/bootstrap.js  
touch .babelrc  

Add content to .babelrc:

{
  "presets": ["@babel/preset-react"]
}

Add content to public/index.html:

<!DOCTYPE html>  
<html>  
  <head>
    <title>Product List Micro Frontend</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>  

Add content to src/ProductList.js:

import React from "react";

const products = [  
  { id: 1, name: "Product 1", price: 19.99 },
  { id: 2, name: "Product 2", price: 29.99 },
  { id: 3, name: "Product 3", price: 39.99 },
];

const ProductList = () => {  
  return (
    <div style={{ border: '1px solid #ddd', borderRadius: '4px', padding: '15px', backgroundColor: '#f9f9f9' }}>
      <h3>Product List (from Micro Frontend)</h3>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            <strong>{product.name}</strong> - ${product.price}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ProductList;  

Add content to src/bootstrap.js:

import React from "react";  
import ReactDOM from "react-dom";  
import ProductList from "./ProductList";

const mount = () => {  
  ReactDOM.render(<ProductList />, document.getElementById("root"));
};

// If we’re running in isolation (standalone mode)
if (document.getElementById("root")) {  
  mount();
}

// We’re exporting the mount function so the container can use it
export { mount };  

Add content to src/index.js:

import("./bootstrap");  

Step 10: Update package.json Scripts

Update the package.json in both the container and product-list directories to include start scripts:

For container/package.json, add:

"scripts": {
  "start": "webpack serve"
}

For product-list/package.json, add:

"scripts": {
  "start": "webpack serve"
}

Step 11: Run the Micro Frontend Demo

Open two terminal windows:

In the first terminal (product-list directory):

cd product-list  
npm start  

In the second terminal (container directory):

cd container  
npm start  

Now open your browser and navigate to:

  • http://localhost:3000 to see the container with the product list micro frontend
  • http://localhost:3001 to see the product list micro frontend on its own

What You Just Built

Congratulations! You’ve created:

  1. A container application (main shell) at port 3000
  2. A product list micro frontend at port 3001
  3. The container dynamically loads the product list from the micro frontend

This demonstrates the core concept of Micro Frontends: separate applications that can run independently but also work together when needed.

Common Issues & Troubleshooting

  1. Error: Cannot find module 'webpack/lib/container/ModuleFederationPlugin'

    • Make sure you’re using Webpack 5 or later
  2. Loading fails with CORS errors

    • Check that your URLs in webpack configs are correct
  3. "Uncaught Error: Shared module is not available for eager consumption"

    • Make sure you’re using dynamic imports with React.lazy in the container app

Next Steps for Tomorrow

  • Add styling and improve the UI
  • Create another micro frontend (e.g., a product details component)
  • Implement communication between micro frontends

You’ve successfully completed Day 1’s implementation! Take a screenshot of your browser showing both applications for your blog post.

Please add your valuable comments here on my Day 1’s LinkedIn Post.



comments powered by Disqus