I am trying to implement module federation in next.js using Turborepo with 2 nex.js apps

This is how the architecture is set up currently: Turbo repo as the mono repo. /apps contains 2 Next.js apps:

  1. searchapp: which is a next.js app that exposes a remote entry to a search module of the app

Next.config.js:

const { NextFederationPlugin } = require('@module-federation/nextjs-mf');

module.exports = {
    reactStrictMode: true,
    transpilePackages: ["ui", "@project/lib", "@project/tailwindconfig"],
    i18n: {
        defaultLocale: "en",
        locales: ["en"],
    },
    images: {
        domains: [
            "localhost",
        ],
    },
    async rewrites() {
        return [
            {
                source: "/api/products/:path*",
                destination: "https://api.project.com/v1/pages/:p*",
            },
        ];
    },

    webpack(config, { isServer }) {

        const federationConfig = {
            name: 'searchapp',
            filename: 'static/chunks/remoteEntry.js',
            exposes: {
                // specify exposed pages and components
                './search': './components/modules/VFinder/index.tsx',
            },
            shared: require("./package.json").dependencies,
        }

        config.plugins.push(
            new NextFederationPlugin(federationConfig),
        );

        return config;
    },
};

  1. webapp: which is also a next.js app that is the consumer of the searchapp module

Next.config.js:

const { NextFederationPlugin } = require('@module-federation/nextjs-mf');

module.exports = {
    reactStrictMode: true,
    transpilePackages: ["ui", "@project/lib", "@project/tailwindconfig"],
    i18n: {
        defaultLocale: "en",
        locales: ["en"],
    },
    images: {
        domains: [
            "localhost"
        ],
    },
    async rewrites() {
        return [
            {
                source: "/api/products/:path*",
                destination: "https://api.project.com/v1/pages/:p*",
            },
        ];
    },
    webpack(config, { isServer }) {

        const sharedDependencies = Object.entries(require("./package.json").dependencies).map(
            ([name, version]) => ({
                [name]: { singleton: true, requiredVersion: false },
            })
        ).reduce((acc, item) => ({ ...acc, ...item }), {});


        config.plugins.push(
            new NextFederationPlugin({
                name: 'web',
                filename: 'static/chunks/webRemoteEntry.js',
                remotes: {
                    // specify remotes
                    searchapp: `searchapp@http://localhost:3001/_next/static/${
                        isServer ? 'ssr' : 'chunks'
                    }/remoteEntry.js`,
                },
                shared: sharedDependencies,
            })
        );

        return config;
    },
};

Component:

import React from "react";
import dynamic from "next/dynamic";

const RemotePage = dynamic(() =>
    // @ts-ignore
    import("searchapp/search").then((mod) => {
        return mod.default;
    }),
    {
        ssr: true,
    }
);

export default function vFinder(props) {
    return (
        <React.Fragment>
            <RemotePage {...props} />
        </React.Fragment>
    );
}

yarn build works for the searchapp but yarn build for web app throws this error:

web:build: [nextjs-mf] You are sharing react from the default share scope. This is not necessary and can be removed.
web:build: [nextjs-mf] You are sharing react-dom from the default share scope. This is not necessary and can be removed.
web:build: (node:31043) [DEP_WEBPACK_MODULE_ID] DeprecationWarning: Module.id: Use new ChunkGraph API
web:build: (Use `node --trace-deprecation ...` to show where the warning was created)
web:build: Failed to compile.
web:build: 
web:build: ../../node_modules/@module-federation/utilities/src/utils/importDelegatedModule.js
web:build: Self-reference dependency has unused export name: This should not happen
web:build: 
web:build: Import trace for requested module:
web:build: ../../node_modules/@module-federation/utilities/src/utils/importDelegatedModule.js
web:build: ../../node_modules/@module-federation/nextjs-mf/src/default-delegate.js?remote=searchapp@http://localhost:3001/_next/static/ssr/remoteEntry.js
web:build: remote searchapp/search
web:build: ./components/modules/HeroBanner/index.tsx
web:build: ./pages/index.tsx
web:build: 
web:build: ../../node_modules/@module-federation/utilities/src/utils/pure.js
web:build: Self-reference dependency has unused export name: This should not happen
web:build: 
web:build: Import trace for requested module:
web:build: ../../node_modules/@module-federation/utilities/src/utils/pure.js
web:build: ../../node_modules/@module-federation/utilities/src/utils/importDelegatedModule.js
web:build: ../../node_modules/@module-federation/nextjs-mf/src/default-delegate.js?remote=searchapp@http://localhost:3001/_next/static/ssr/remoteEntry.js
web:build: remote searchapp/search
web:build: ./components/modules/HeroBanner/index.tsx
web:build: ./pages/index.tsx
web:build: 
web:build: 
web:build: > Build failed because of webpack errors
web:build: error Command failed with exit code 1.
web:build: info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
1

There are 1 answers

1
SerhiiN On

I had the same issue but in a quite different project also with nextjs-mf. The solution I found here by creating a custom delegate-module.js file.