Home

Published

- 4 min read

Micro-Frontend with Module Federation in Next.js

img of Micro-Frontend with Module Federation in Next.js

Micro Frontend

What?

Micro-Frontend are a design architecture that breaks down a web application into smaller, independent, and interchangeable front-end units. These units can be developed, tested, and deployed independently, promoting modularity and scalability.

Benefit Micro-Frontend:

  1. Improved Agility
  2. Enhanced Scalability
  3. Technology Flexibility
  4. Reduced Risk
  5. Easier Maintenance

In essence, micro-frontend offer a more modular and scalable approach to building web applications, enabling faster development, easier maintenance, and better flexibility.

Module Federations

Webpack module federation was created by Zackary Jackson and now officially part of webpack. This GitHub organization provides additional resources for folks looking to learn more about Module Federation.

Webpack Module Federation (MF) is a feature of webpack that allows for the dynamic loading of multiple versions of a module from multiple independent build systems.

Stages and Installation

  1. We will create 1 as host or root project and 2 remote project we can called it as ChildAuthSevices and ChildProjectServices. In each project we will install libraries @module-federation/nextjs-mf and webpack.
   npx create-next-app root-app
cd root-app
npm install webpack
npm install @module-federation/nextjs-mf
   npx create-next-app child-project-app
cd child-project-app
npm install webpack
npm install @module-federation/nextjs-mf
   npx create-next-app child-auth-app
cd child-auth-app
npm install webpack
npm install @module-federation/nextjs-mf

2. Configure the child-project-app with add new file called RemoteComponent.js inside folder components.

   import React from 'react'

const RemoteComponent = () => {
  return (
    <div>Remote Child Project Services</div>
  )
}

export default RemoteComponent

3. Change configuration the next.config.mjs in the folder child-project-app. In this configuration we give a name our remote component as childProjectServices.

   // next.config.mjs
import NextFederationPlugin from '@module-federation/nextjs-mf';

export default {
  webpack(config, options) {
    const { isServer } = options;
    config.plugins.push(
      new NextFederationPlugin({
        name: 'childProjectServices',
        remotes: {
          host: `host@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'
            }/remoteEntry.js`,
        },
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          './RemoteComponent': './components/RemoteComponent.js',
        },
        shared: {
          react: {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
          'react-dom': {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
        },
      }),
    );

    return config;
  },
};

4. The concept of micro-frontend is we had several apps which run together but had the different port. Therefore, we will set this project to run on the port 3002. On the child-project-app setup the package.json in the line scripts/dev with this code.

   "dev": "NEXT_PRIVATE_LOCAL_WEBPACK=true next dev -p 3002"

Run this project with

   npx run dev

5. Configure the child-auth-app with add new file called RemoteComponent.js inside folder components.

   import React from 'react'

const RemoteComponent = () => {
  return (
    <div>Remote Child Auth Services</div>
  )
}

export default RemoteComponent

6. Change configuration the next.config.mjs in the folder child-auth-app. In this configuration we give a name our remote component as childAuthServices.

   // next.config.mjs
import NextFederationPlugin from '@module-federation/nextjs-mf';

export default {
  webpack(config, options) {
    const { isServer } = options;
    config.plugins.push(
      new NextFederationPlugin({
        name: 'childAuthServices',
        remotes: {
          host: `host@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'
            }/remoteEntry.js`,
        },
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          './RemoteComponent': './components/RemoteComponent.js',
        },
        shared: {
          react: {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
          'react-dom': {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
        },
      }),
    );

    return config;
  },
};

7. Run this project on the port 3001 and do some configuration in the package.json

   "dev": "NEXT_PRIVATE_LOCAL_WEBPACK=true next dev -p 3001"
   npx run dev

8. Finally, we change to our root or host project and do some configuration in the pages/index.js.

   import dynamic from 'next/dynamic';
const RemoteComponentAuth = dynamic(() => import('childAuthServices/RemoteComponent'), {
  ssr: false,
});
const RemoteComponentProject = dynamic(() => import('childProjectServices/RemoteComponent'), {
  ssr: false,
});
export default function Home() {
  return (
    <div>
      <h1>Host Application</h1>
      <RemoteComponentAuth />
      <RemoteComponentProject />
    </div>
  );
}

9. Change the next.config.mjs so we can load the component from our remote components.

   // next.config.mjs
import NextFederationPlugin from '@module-federation/nextjs-mf';

export default {
  webpack(config, options) {
    const { isServer } = options;
    config.plugins.push(
      new NextFederationPlugin({
        name: 'host',
        remotes: {
          childAuthServices: `childAuthServices@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'
            }/remoteEntry.js`, // for auth services
          childProjectServices: `childProjectServices@http://localhost:3002/_next/static/${isServer ? 'ssr' : 'chunks'
            }/remoteEntry.js`, // for project services
        },
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          // host can also expose components 
        },
        shared: {
          react: {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
          'react-dom': {
            singleton: true,
            eager: true,
            requiredVersion: false,
          },
          // files or dependencies we want to share
        },
      }),
    );

    return config;
  },
};

10. In package.json change the scripts/dev, add a little configuration

   "dev": "NEXT_PRIVATE_LOCAL_WEBPACK=true next dev"
   npm run dev

Access my mini-research on Micro-FrontEnd freely through this link https://github.com/sadewa25/micro-frontend-nextjs.