React + TypeScript + Webpack + Module Federation Plugin - MicroFrontend Application
Tags: microfrontend, typescript, javascript, react
Published: 2022-12-16 08:18:16

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aucyexqcp8wlds4fbwvv.png)

--------

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4rudwixy13v1204v7hot.png)

--------

Step 3::

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

```javascript
   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"],
        },
      },
    }),
```

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.

```javascript
   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"],
        },
      },
    }),

```

--------

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

```javascript
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
}
```

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

```javascript
 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"],
        },
      },
    }),

```
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.

2. Create a simple Home App.

npx create-mf-app home Use PORT - 3001

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

Paste the below code:

```javascript
import React from "react"

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

export {
    HomePage
}
```

4. Open the home/webpack.config.js from the home app:

Replace the code for ModuleFederationPlugin

```javascript
  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"],
        },
      },
    }),
```


5. Open the container/webpack.config.js from the container app.

Replace the code for ModuleFederationPlugin

```javascript
    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"],
        },
      },
    })
```

6. Open the App.tsx file from the container Application.

Add the import:

`import { HomePage } from 'home/Home'
`
use as <HomePage/>


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

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

9. Locate to http://localhost:3000

10. 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