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 frontendhttp://localhost:3001
to see the product list micro frontend on its own
What You Just Built
Congratulations! You’ve created:
- A container application (main shell) at port 3000
- A product list micro frontend at port 3001
- 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
Error: Cannot find module 'webpack/lib/container/ModuleFederationPlugin'
- Make sure you’re using Webpack 5 or later
Loading fails with CORS errors
- Check that your URLs in webpack configs are correct
"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.