ScanSkill
Sign up for daily dose of tech articles at your inbox.
Loading

A Tutorial On Setting Up Micro Frontend – 2

A Tutorial On Setting Up Micro Frontend – 2
A Tutorial On Setting Up Micro Frontend – 2

In the previous article, we discussed the basic concepts of micro frontends. We understood that Micro frontends is an architectural approach to frontend development with the idea of thinking of a project as a collection of features that different teams can independently own. Today, we will be working on a tutorial on the basic setup of micro frontends. We will be creating a host page and two different modules. We will be using module federation architecture which allows the sharing of code and dependencies between two different application codebases.

Step 1: Create Three Different React Projects (Micro Frontends)

npx create-mf-app
Create module federation apps
Create module federation apps

Step 2: Go to Folder and Install Node Modules

cd host
npm install
npm start

Repeat this step for all the modules.

After installing node modules with npm install of all the modules.The explorer looks something like this:

Micro Frontends
VS Code explorer

on npm start:

The landing page shows the details that we chose while setting up the module federation app.

Step 3: Create Components

Now we create components on module apps that we will consume in host page later on.

First lets create a simple counter app with some styling using CSS in moduleOne app.

Create Counter.js file in moduleApp

Counter.js

import React, { useState } from 'react'
import './style.css'

function Counter() {
    const [count, setCount] = useState(0);
    const handleIncrement = () => setCount(count + 1);
    const handleDecrement = () => setCount(count - 1);
  return (
    <div className='counter'>
        <h3>This is Counter App Module</h3>
        <p><strong>{count}</strong></p>
        <div>
        <button onClick={handleIncrement} className='counter-btn'>+</button>
        <button onClick={handleDecrement} className='counter-btn'>-</button> 
        </div>
        
      </div>
  )
}

export default Counter

Import Counter in App,js of moduleOne.

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

import "./index.css";

const App = () => (
  <div className="container">
    This is module one header, Hello!
    <Counter/>
  </div>
);
ReactDOM.render(<App />, document.getElementById("app"));

Output

moduleOne Counter
moduleOne Counter

Now Lets create a timer component in moduleTwo using react-countdown

Timer.js

import React from 'react';
import "./style.css";
import Countdown from 'react-countdown';

function Timer() {
  return (
    <div className="custom">
        <Countdown date={Date.now() + 100000} />
    </div>
  )
}

export default Timer

Import Timer.js in app.js of moduleTwo

App.js

import React from "react";
import ReactDOM from "react-dom";
import 'bootstrap/dist/css/bootstrap.min.css';

import "./index.css";
import Timer from "./Timer";

const App = () => (
  <div className="container">
    Hello, This is Module Two Header
    <Timer/>
  </div>
);
ReactDOM.render(<App />, document.getElementById("app"));

Output

We have created two components Counter and Timer from two different modules. Now, lets merge these components in the host page.

Step 3: Edit webpack.config.js

The most of the works are done in webpack.config.js files.

Webpack is a static module bundler for modern JavaScript applications.It helps to create different individual builds or modules from a single app. It compiles JS modules and creates dependency graph that consists of all the modules that our app requires. These modules comes from the node modules folder that are turned into a single JS file by Webpack.

Lets start from the moduleOne’s webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "moduleOne",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        "./Counter":"./src/Counter.js"
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
  ],

Here, name is the unique name for the exposed container. It will be used as the file name for the container’s relative path.

filename is used to specify the file name for the output bundle. It is considered the local chunk in the remote repository that stores the remote entry files from its module.

remote is a list of static remote modules that can be accessed by the local module.

exposes is the path to the module or files exposed by the container and that can be consumed by other modules.

shared allows us to share the node libraries which the exposed module needs to run.

Similarly, in the moduleTwo webpack.config.js

 plugins: [
    new ModuleFederationPlugin({
      name: "moduleTwo",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        "./Timer" : "./src/Timer.js"
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
  ],

Now, in the host webpack.config.js

  plugins: [
    new ModuleFederationPlugin({
      name: "host",
      filename: "remoteEntry.js",
      remotes: {
        moduleOne:"moduleOne@http://localhost:8081/remoteEntry.js",
        moduleTwo:"moduleTwo@http://localhost:8082/remoteEntry.js"
      },
      exposes: {},
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
  ],

Now import the components in host App.js

import React from "react";
import ReactDOM from "react-dom";
import Counter from 'moduleOne/Counter';
import Timer from 'moduleTwo/Timer';

import "./index.css";

const App = () => (
  <div className="container">
    <h2> This is Host Page </h2>
    <Counter/>
    <Timer/>
  </div>
);
ReactDOM.render(<App />, document.getElementById("app"));

Output

Host page
Host page

Conclusion

In this tutorial, we learned how to setup a basic micro frontends app. Here, we created components from different modules and consumed it in the host page using webpack module federation method.

Sign up for daily dose of tech articles at your inbox.
Loading