React + TypeScript + Webpack + Module Federation Plugin - MicroFrontend Application

harish_soni

Harish Soni

Posted on December 16, 2022

React + TypeScript + Webpack + Module Federation Plugin - MicroFrontend Application

Hello DEV,

Let's get to the point straight, I am writing this to learn and build a MicroFrontend Application using React + TS.

We will be using the below npm packages:

  1. React.js
  2. TypeScript
  3. Webpack - Module Federation Plugin.
  4. create-mf-app (https://www.npmjs.com/package/create-mf-app)

So if you are here, searching for a microfrontend using React.js, then I assume you already know what is React and how does it works with TypeScript.


So let's do it step by step:
Steps:

  1. To know about what is module federation plugin?
  2. How it helps in creating a microfrontend application.
  3. What we need to configure to make the core app, import from the other services which are running on the different PORTS.
  4. How to write export and import component on the one go?

Step 1::

According to Google:

Module Federation is one of the most exciting features in Webpack 5 and is considered a game-changer in JavaScript architecture. It supports more independent and straightforward code sharing at runtime among JavaScript applications, making the applications more adaptive and dynamic.

Image description


Step 2::

So we have configuration in the Module Federation which we use to connect the different application on a single container and access those application according to the concerns.

Image description


Step 3::

Below is the least example how how we export and import the components from the different application:

   new ModuleFederationPlugin({
      name: "home", // Application Name to use
      filename: "homeEntry.js", // Filename to use when we remote this application from other app.
      remotes: {
      },
      exposes: {
        "./Home": "./src/Components.tsx" // Components to export/expose
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),
Enter fullscreen mode Exit fullscreen mode

So let's learn the things one by one.

name - This is a unique value which we will use when we will import/remote this application on other application let's call this as container?

filename - It will be the bundled filename which will be loaded when the container application is loaded, as part of the page, and provides the exposed/exported code.

remotes - This is the part where in the application, we import the code from other application, the basic syntax for this is

{nameOfTheRemoteApplication}@http://{urlOfthe RunningApp}/{fileNameProvidedInWebpackOfTheRemoteApp}.js

login@http://localhost:3003/loginEntry.js

login: the Login Application where the name is provided as login.

http://localhost:3003: The URL of the Remote App running, with the PORT For local development

remoteEntry.js: The fileName which is provided in the remote application.

Below if how the Login Application webpack.config.js would look like.

   new ModuleFederationPlugin({
      name: "login",
      filename: "loginEntry.js",
      remotes: {

      },
      exposes: {
        './Login': './src/ExportedComponents.tsx'
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),

Enter fullscreen mode Exit fullscreen mode

Step 4::

Once the application is created and the setup is done, we move to create the ExportedComponents.tsx file, for explaining simple here is what I have in my ExportedComponents.tsx

import React from 'react'

const LoginMain = () => {
    return <div> New Deployment</div>
}

const LoginHome = () => {
    return <div>The new era is coming here </div>
}

export {
    LoginHome,
    LoginMain
}
Enter fullscreen mode Exit fullscreen mode

NOTE: HERE WE CANNOT EXPORT THE COMPONENT AS DEFAULT.

Named export would work for us, now let's use this LoginHome and LoginMain in our container application:

here is how the container/webpack.config.js would look like

 new ModuleFederationPlugin({
      name: "container", // Current App name
      filename: "remoteEntry.js", // filename
      remotes: { // the micro frontends to use in container the things which we want import from other service.
        login: 'login@http://localhost:3003/loginEntry.js',      }, 
      exposes: {}, // to give components to other services
      shared: { 
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),

Enter fullscreen mode Exit fullscreen mode

You can learn what is shared in this config on the ModuleFederationPlugin docs.

Now let's move to importing the component, the syntax will be:

import { ComponentName } from 'NameOfTheApplication{from ModuleFederationPlugin config of the remote app}/KeyFromExposes{{from ModuleFederationPlugin config of the remote app}}'

example:

import { LoginMain, LoginHome } from 'login/Login'

Now this will simply render the component from the Login App.


Let's try creating a simple Micro Frontend Applllication.

  1. Create a container application using the below command:

npx create-mf-app container - Use PORT 3000

It will ask you some configs, do it accordingly.

  1. Create a simple Home App.

npx create-mf-app home Use PORT - 3001

  1. Create a Components.tsx file in Home/src/Components.tsx

Paste the below code:

import React from "react"

const HomePage = () => {
    return <div>Homepage from the Home App</div>
}

export {
    HomePage
}
Enter fullscreen mode Exit fullscreen mode
  1. Open the home/webpack.config.js from the home app:

Replace the code for ModuleFederationPlugin

  new ModuleFederationPlugin({
      name: "home", // name
      filename: "homeEntry.js",
      remotes: {
      },
      exposes: {
        "./Home": "./src/Components.tsx"
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    }),
Enter fullscreen mode Exit fullscreen mode
  1. Open the container/webpack.config.js from the container app.

Replace the code for ModuleFederationPlugin

    new ModuleFederationPlugin({
      name: "container", // name
      filename: "remoteEntry.js",
      remotes: {
        home: "home@http://localhost:3001/homeEntry.js"
      },
      exposes: {
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
      },
    })
Enter fullscreen mode Exit fullscreen mode
  1. Open the App.tsx file from the container Application.

Add the import:

import { HomePage } from 'home/Home'

use as

  1. Go to the container application folder, do yarn && yarn start

  2. Go to the home application on the different tab of the terminal, do yarn && yarn start

  3. Locate to http://localhost:3000

  4. See if working if not add a comment with your doubt.

I have made a sample application here:

https://github.com/harish9312/microfrontend-example/tree/master

  • Thanks
💖 💪 🙅 🚩
harish_soni
Harish Soni

Posted on December 16, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related