DEV Community

Cover image for Micro-Frontends: The Next Gen Way to build Web Apps
Tapajyoti Bose
Tapajyoti Bose

Posted on • Updated on

Micro-Frontends: The Next Gen Way to build Web Apps

In enterprise-level applications, working on an application from a single code base turns out to be a massive head-ache. For this purpose, Micro-Frontend architecture was born. Let's dive into the world of Micro-Frontend and discuss some of the nitty-gritty of following this approach.

lets go

What is Micro-Frontend?

Let's check the definition a google search spits out:

Micro-frontend architecture is a design approach in which a front-end app is decomposed into individual, independent “micro-apps” working loosely together.

There are two major parts of a Micro-frontend application:

  • Container
  • Sub-Applications

The container determines when each of the sub-application should be displayed on the screen. All the business logic is handled by each of the sub-applications.

micro-frontend architechture

Why use Micro-Frontend?

There are numerous benefits of using Micro-Frontend architecture:

  • You can use different framework in each sub-application
  • Modification or even bugs in one sub-application has no effect on the other sub-applications
  • You can run A/B Tests easily to maximize customer conversions
  • Makes it easier for teams to collaborate on a project (can be hosted as separate repository for each sub-app or a mono-repo)
  • and many more

Key Principles of Micro-Frontend

There are two strict requirements for this architecture:

  1. The micro apps should work absolutely independently of each other, for example, the auth sub-app should not in any way rely on data from the product sub-app
  2. The micro apps can communicate with the container, but the communication should be kept as minimal as possible and should be done in as generic means as possible. So, even if both the container and a sub-app uses the same framework, let's say React, they should not pass React components between them, but some generic functions and objects. This ensures that during a major refactor of either the micro apps or the container, we don't have to work on the other.

Basic Micro-Frontend app

Ok, enough talk! Now it's time to get our hands dirty making a basic Micro-frontend app.

its time

Let's make three folders for:

  • container
  • cart
  • products

We would use faker to generate fake data for the cart and products. To install the library, open the folder in the command prompt, initialize a node project using npm init and use npm install faker.

Implementing Micro-Frontend would be a nightmare for pretty much everyone, but luckily we have Module Federation plugin available with webpack which makes it a piece of cake. To install all webpack associated packages, use (in each folder):

npm install -D webpack webpack-cli html-webpack-plugin webpack-dev-server
Enter fullscreen mode Exit fullscreen mode

Add public/index.html in all three folders

<!-- cart -->
<div id="dev-cart"></div>
Enter fullscreen mode Exit fullscreen mode
<!-- products-->
<div id="dev-products"></div>
Enter fullscreen mode Exit fullscreen mode
<!-- container-->
<div id="product-list"></div>
<hr />
<div id="cart-items"></div>
Enter fullscreen mode Exit fullscreen mode

Now setting up our webpack.config.js:

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    mode: 'development',
    devServer: {
        port: 3000,
    },
    plugins: [
        new HTMLWebpackPlugin({
            template: path.resolve(__dirname, 'public', 'index.html'),
        })
    ],
};
Enter fullscreen mode Exit fullscreen mode

Copy the webpack.config.js at the root of each folder, but make sure you have different port numbers for the dev server.

Now let's set up the Module Federation:

// cart/webpack.config.js

// ...
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const packageJson = require('./package.json')

module.exports = {
    // ...
    plugins: [
        new ModuleFederationPlugin({
            name: 'cart', // name of the item being exposed (required in container)
            filename: 'remoteEntry.js', // name of the file
            exposes: {
                './Cart': './src/bootstrap' // actual file being exposed
            },
            shared: packageJson.dependencies, // to remove duplicate external modules loading in the container
        }),
        // ...
    ]
};
Enter fullscreen mode Exit fullscreen mode
// products/webpack.config.js

// ...
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const packageJson = require('./package.json')

module.exports = {
    // ...
    plugins: [
        new ModuleFederationPlugin({
            name: 'products', // name of the item being exposed (required in container)
            filename: 'remoteEntry.js', // name of the file
            exposes: {
                './ProductIndex': './src/bootstrap' // actual file being exposed
            },
            shared: packageJson.dependencies, // to remove duplicate external modules loading in the container
        }),
        // ...
    ]
};
Enter fullscreen mode Exit fullscreen mode
// container/webpack.config.js

// ...
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
const packageJson = require('./package.json')

module.exports = {
    // ...
    plugins: [
        new ModuleFederationPlugin({
            name: 'container', 
            remotes: {
                products: 'products@http://localhost:8000/remoteEntry.js', // importing products file from port 8000
                cart: 'cart@http://localhost:8001/remoteEntry.js', // importing cart file from port 8001
            },
        }),
        // ...
    ]
};
Enter fullscreen mode Exit fullscreen mode

With webpack now setup, we need to add our cart, products and container:

// cart/src/bootstrap.js

import faker from 'faker'

const mount = (element) => {
  // generating fake data
  element.innerHTML = `
  <p>You have ${faker.datatype.number(10)} items in your cart</p>
`
}

const mountPt = document.querySelector('#dev-cart')
if (process.env.NODE_ENV === 'development' && mountPt) {
  mount(document.querySelector('#dev-cart'))
}

export { mount } // sharing generic mount function
Enter fullscreen mode Exit fullscreen mode
// products/src/bootstrap.js

import faker from 'faker'

const PRODUCTS_COUNT = 5

const mount = (element) => {
    // generating fake data
    let productsArr = []
    for (let i = 0; i < PRODUCTS_COUNT; i++) {
        const product = faker.commerce.productName();
        productsArr.push(`<div>${product}</div>\n`)
    }

    const products = productsArr.join('')
    element.innerHTML = products
}

const mountPt = document.querySelector('#dev-products')
if (process.env.NODE_ENV === 'development' && mountPt) {
    mount(mountPt)
}

export { mount } // sharing generic mount function
Enter fullscreen mode Exit fullscreen mode
// container/src/bootstrap.js

import { mount as mountProducts } from 'products/ProductIndex'
import { mount as mountCart } from 'cart/Cart'

mountProducts(document.querySelector('#product-list'))
mountCart(document.querySelector('#cart-items'))
Enter fullscreen mode Exit fullscreen mode

Now finally create an index.js file in the src folder of each sub-app & container

import('./bootstrap')
Enter fullscreen mode Exit fullscreen mode

Creating this file with dynamic import is absolutely crucial as webpack fails to import the external packages without it (since the packages are shared, so they behave differently).

Now your app is ready. You can add the following script in the scripts section of package.json:

"scripts": {
    "dev": "webpack serve"
}
Enter fullscreen mode Exit fullscreen mode

and call npm run dev to start up the webpack server

Products (port 8000)

products

Cart (port 8001)

cart

Container & the entire app (port 3000)

container

Wrapping Up

In this article, we went through the basics of Micro-frontend architecture. Hope it helps you in your development journey :)

I am currently working on a project utilizing Micro-frontend architecture, feel free to check it out:

GitHub logo ruppysuppy / Crypto-Crowdfund

🤑💰 Platform backed by Ethereum Blockchain to bring your creative projects to life

Thanks for reading

Looking for ways to boost your productivity? Check out my Bi-Weekly Productivity Blogs on Medium

Need a Top Rated Front-End Development Freelancer? Contact me on Upwork

Want to see what I am working on? Check out my GitHub

I am a freelancer who will start off as a Digital Nomad in mid-2022. Want to catch the journey? Follow me on Instagram

Follow my blogs for Weekly new Tidbits on Dev

FAQ

These are a few commonly asked questions I get. So, I hope this FAQ section solves your issues.

  1. I am a beginner, how should I learn Front-End Web Dev?
    Look into the following articles:

    1. Front End Development Roadmap
    2. Front End Project Ideas
  2. Would you mentor me?

    Sorry, I am already under a lot of workload and would not have the time to mentor anyone.

  3. Would you like to collaborate on our site?

    As mentioned in the previous question, I am in a time crunch, so I would have to pass on such opportunities.

Connect to me on

Discussion (0)