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:
- 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;
},
};
- 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.
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.