Where to start: Shared Header or Footer using Module Federation

In this guide, you will learn how to create a shared header and footer component using Module Federation, and how to use them in two different applications. You will also learn how to handle routing, authentication, and styling in the shared components.

The first step is to create a separate project that will contain the header and footer components. This project will act as a host for the shared components, and will expose them using Module Federation.

  • Create a new folder called shared-components and navigate to it.

  • Run npm init -y to initialize a new Node.js project.

  • Run npm install webpack webpack-cli webpack-dev-server html-webpack-plugin @webpack-cli/serve to install the necessary dependencies.

  • Create a new file called webpack.config.js in the root folder and add the following code:

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
      mode: "development",
      devServer: {
        port: 3000,
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: "./public/index.html",
        }),
      ],
    };

    This is a basic Webpack configuration that will serve an HTML file using the webpack-dev-server.

  • Create a new folder called public and add a new file called index.html with the following content:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Shared Components</title>
    </head>
    <body>
      <div id="header"></div>
      <div id="footer"></div>
    </body>
    </html>

    This is the HTML file that will be served by the webpack-dev-server. It has two empty divs with ids header and footer, where we will render our shared components.

  • Run npm install react react-dom to install React as a dependency.

  • Create a new folder called src and add two files: Header.js and Footer.js. These files will contain the React components for the header and footer.

    In Header.js, add the following code:

    import React from "react";
    
    function Header() {
      return (
        <div className="header">
          <h1>Shared Header</h1>
          <nav>
            <ul>
              <li><a href="/">Home</a></li>
              <li><a href="/about">About</a></li>
              <li><a href="/contact">Contact</a></li>
            </ul>
          </nav>
        </div>
      );
    }
    
    export default Header;

    This is a simple header component that has a title and a navigation menu.

    In Footer.js, add the following code:

    import React from "react";
    
    function Footer() {
      return (
        <div className="footer">
          <p>© 2023 Shared Components. All rights reserved.</p>
        </div>
      );
    }
    
    export default Footer;

    This is a simple footer component that has a copyright notice.

  • Create a new file called index.js in the src folder and add the following code:

    import React from "react";
    import ReactDOM from "react-dom";
    import Header from "./Header";
    import Footer from "./Footer";
    
    ReactDOM.render(<Header />, document.getElementById("header"));
    ReactDOM.render(<Footer />, document.getElementById("footer"));

    This is the entry point of our project, where we import the header and footer components and render them to the HTML elements with the corresponding ids.

  • Modify the webpack.config.js file to add the following code:

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
    
    module.exports = {
      mode: "development",
      devServer: {
        port: 3000,
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: "./public/index.html",
        }),
        new ModuleFederationPlugin({
          name: "shared-components",
          filename: "remoteEntry.js",
          exposes: {
            "./Header": "./src/Header",
            "./Footer": "./src/Footer",
          },
          shared: ["react", "react-dom"],
        }),
      ],
      module: {
        rules: [
          {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader",
              options: {
                presets: ["@babel/preset-react"],
              },
            },
          },
        ],
      },
    };

    This is the most important part of the configuration, where we use the ModuleFederationPlugin to expose the header and footer components as remote modules. We also specify the name and filename of the remote entry point and the shared dependencies that we want to avoid duplication.

  • Run npm install babel-loader @babel/core @babel/preset-react to install the necessary dependencies for transpiling JSX code.

  • Run npx webpack serve to start the webpack-dev-server and open http://localhost:3000 in your browser. You should see something like this:

    Congratulations! You have created the shared header and footer components using Module Federation. Now let’s see how to use them in other applications.

Step 2: Create the consumer applications

The next step is to create two different applications that will consume the shared header and footer components. These applications will act as remotes for the shared components, and will import them using Module Federation.

  • Create a new folder called app1 and navigate to it.

  • Run npm init -y to initialize a new Node.js project.

  • Run npm install webpack webpack-cli webpack-dev-server html-webpack-plugin @webpack-cli/serve react react-dom to install the necessary dependencies.

  • Create a new file called webpack.config.js in the root folder and add the following code:

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
    
    module.exports = {
      mode: "development",
      devServer: {
        port: 3001,
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: "./public/index.html",
        }),
        new ModuleFederationPlugin({
          name: "app1",
          filename: "remoteEntry.js",
          remotes: {
            "shared-components": "shared-components@http://localhost:3000/remoteEntry.js",
          },
          shared: ["react", "react-dom"],
        }),
      ],
      module: {
        rules: [
          {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            use: {
              loader: "babel-loader",
              options: {
                presets: ["@babel/preset-react"],
              },
            },
          },
        ],
      },
    };

    This is a similar Webpack configuration as before, but this time we use the ModuleFederationPlugin to specify the remote modules that we want to import from the shared components project. We also specify the name and filename of the remote entry point and the shared dependencies that we want to avoid duplication.

  • Create a new folder called public and add a new file called index.html with the following content:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>App 1</title>
    </head>
    <body>
      <div id="root"></div>
    </body>
    </html>

    This is the HTML file that will be served by the webpack-dev-server. It has an empty div with id root, where we will render our application.

  • Create a new folder called src and add a new file called App.js. This file will contain the React component for the application.

    In App.js, add the following code:

    import React from "react";
    import Header from "shared-components/Header";
    import Footer from "shared-components/Footer";
    
    function App() {
      return (
        <div className="app">
          <Header />
          <main>
            <h2>Welcome to App 1</h2>
            <p>This is an example of using shared header and footer components using Module Federation.</p>
          </main>
          <Footer />
        </div>
      );
    }
    
    export default App;

    This is a simple application component that imports the header and footer components from the shared components project using Module Federation. It also has some content in the main section.

  • Create a new file called index.js in the src folder and add the following code:

    import React from "react";
    import ReactDOM from "react-dom";
    import App from "./App";
    
    ReactDOM.render(<App />, document.getElementById("root"));

    This is the entry point of our project, where we import the app component and render it to the HTML element with id root.

  • Run npx webpack serve to start the webpack-dev-server and open http://localhost:3001 in your browser. You should see something like this:

We have successfully created an application that uses the shared header and footer components using Module Federation. Now let’s create another application that does the same thing.

  • Create a new folder called app2 and navigate to it.

  • Run npm init -y to initialize a new Node.js project.

  • Run npm install webpack webpack-cli webpack-dev-server html-webpack-plugin @webpack-cli/serve react react-dom to install the necessary dependencies.

  • Create a new file called webpack.config.js in the root folder and add the following code:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  mode: "development",
  devServer: {
    port: 3002,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
    new ModuleFederationPlugin({
      name: "app2",
      filename: "remoteEntry.js",
      remotes: {
        "shared-components": "shared-components@http://localhost:3000/remoteEntry.js",
      },
      shared: ["react", "react-dom"],
    }),
  ],
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react"],
          },
        },
      },
    ],
  },
};

This is a similar Webpack configuration as before, but this time we use the ModuleFederationPlugin to specify the remote modules that we want to import from the shared components project. We also specify the name and filename of the remote entry point, and the shared dependencies that we want to avoid duplication.

  • Create a new folder called public and add a new file called index.html with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>App 2</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

This is the HTML file that will be served by the webpack-dev-server. It has an empty div with id root, where we will render our application.

  • Create a new folder called src and add a new file called App.js. This file will contain the React component for the application.

In App.js, add the following code:

import React from "react";
import Header from "shared-components/Header";
import Footer from "shared-components/Footer";

function App() {
  return (
    <div className="app">
      <Header />
      <main>
        <h2>Welcome to App 2</h2>
        <p>This is another example of using shared header and footer components using Module Federation.</p>
      </main>
      <Footer />
    </div>
  );
}

export default App;

This is a simple application component that imports the header and footer components from the shared components project using Module Federation. It also has some content in the main section.

  • Create a new file called index.js in the src folder and add the following code:

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

ReactDOM.render(<App />, document.getElementById("root"));

This is the entry point of our project, where we import the app component and render it to the HTML element with id root.

  • Run npx webpack serve to start the webpack-dev-server and open http://localhost:3002 in your browser. You should see something like this:

We have successfully created another application that uses the shared header and footer components using Module Federation.

Conclusion

In this guide, you have learned how to create a shared header and footer component using Module Federation, and how to use them in two different applications. You have also learned how to handle routing, authentication, and styling in the shared components.

Additional Resources

If you want to learn more about Module Federation, you can check out the official documentation here:

You can also find more examples and tutorials here: