Micro Front-End: Module Federation


What is Module Federation? 

To understand Module Federation, we need to first know some basics of webpack: Webpack Basics

Now that we know that webpack 

  1. bundles all the source files 
  2. the bundled files sits in a /dist folder (or as configured in webpack.config.js)
  3. We need to add plugins if we need to bundle HTML files
  4. We need to add "rules" if we need to bundle CSS files
  5. Just like how we had to add a special plugin to bundle HTML files, we also need a special plugin for Module Federation

Basic idea behind Module Federation

  1. An app can have multiple "micro apps". Each containing its own "package.json".
  2. Each of these apps run on their own in their own port.
  3. These apps can still share some code and talk to each other.
  4. To summarize, each of these apps can expose certain modules and consume certain modules
  5. They share these modules at runtime. They don't depend on the contents of the "dist" folder

GITHUB

EXAMPLE


Create 2 folders (remote-app, host-app)

In each of these folders

  1. Create a blank HTML, JS, webpack.config.js files in each of these folders
  2. npm init -y
  3. npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin
  4. In package.json file add a new script => "build": "webpack"

Contents that go in these files

In both the index.html files
<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <script src="bundle.js"></script>
    </body>
</html>

remote-app\remoteModuleIndex.js
//A simple Module that exposes a function
export function remoteModuleGreet() {
  return "Hello from remote module!";
}

host-app\index.js
import("remoteApp/Module").then((module) => {
    document.body.innerHTML = module.remoteModuleGreet();
})

Finally comes the WebPack config. 

  1. Host app consumes the remote module dynamically.
  2. Remote app exposes remoteModuleIndex.js as ./Module

host-app\webpack.config.js

const path = require("path");
const { ModuleFederationPlugin } = require("webpack").container;
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: "development",
  entry: "./index.js",
  output: {
    publicPath: "http://localhost:8080/",
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "hostApp",
      remotes: {
        remoteApp: "remoteApp@http://localhost:8081/remoteEntry.js",
      },
    }),
    new HtmlWebpackPlugin({
        template: './index.html',  
        filename: 'index.html'
    })
  ],
  devServer: {
    port: 8080,
    host: "0.0.0.0",
    static: path.join(__dirname, "dist"),
  },
};

remote-app\webpack.config.js

const path = require("path");
const { ModuleFederationPlugin } = require("webpack").container;
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: "development",
  entry: "./remoteModuleIndex.js",
  output: {
    publicPath: "http://localhost:8081/",
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "remoteApp",
      filename: "remoteModuleIndex.js",
      exposes: {
        "./Module": "./remoteModuleIndex.js",
      },
    }),
    new HtmlWebpackPlugin({
        template: './index.html',
        filename: 'index.html'    
    })
  ],
  devServer: {
    port: 8081,
    host: "0.0.0.0",
    static: path.join(__dirname, "dist"),
  },
};

Now, host app runs on http://localhost:8080/

Remote app runs on http://localhost:8081/

Finally in both the apps, run 

  • npm i
  • npm run build
  • npx webpack serve --mode development




Comments

Popular posts from this blog

Inside the JavaScript Memory Box: Visualizing Variables, References, and Copies

React & State Management: All Concepts

React: Communication between components