An Interest In:
Web News this Week
- April 2, 2024
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
Building React App with Module Federation and NextJS/React
This document will take you step-by-step through the tasks required to set up a module federation module, with react app as host with NextJS and React Apps as remote apps. This document's how-to will show you the failing issues I encountered and how I solve them; I hope it will help others when they try to do the same.
* Disclaimer for NextJS apps you need the latest version of @module-federation/nextjs-mf
that is a paid module, you can read more here
Prerequisites
- Knowledge in Module Federation Concepts and miro-frontends
- NodeJS installed (preferable > 14)
2 Running React App with access to
webpack.config.js
- Preferable not created using CRA(create react app)
- At least one React Component
- One will be the host app
- The other will a remote app
Running NextJS App
- At least one React Component
- This will be the remote app
Basic Knowledge in Webpack
License for
@module-federation/nextjs-mf
Terminology
Host: It is a top-level app that depends on modules exposed from a remote app
Remote: Exposes components to another app called a host.
Configuring Remote App - NextJS
- Use
withFederatedSidecar
in yournext.config.js
of the app that you wish to expose modules from. We'll call this "remote_nextjs_module".
const { withFederatedSidecar } = require("@module federation/nextjs-mf"); module.exports = withFederatedSidecar({ name: "remote_nextjs_module", filename: "static/chunks/remoteEntry.js", exposes: { "./BB8": "./components/BB8.js", }, shared: { }, })({ // your original next.config.js export reactStrictMode: true, });
Configuring Remote App - React
- Use
ModuleFederationPlugin
in yourwebpack.config.js
of the app that you wish to expose modules from. We'll call this "remote_react_module". - I'm demonstrating here only the implementation of
ModuleFederationPlugin
and not adding all the configuration ofwebpack.config.js
of the app
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin; plugins: [ new ModuleFederationPlugin({ name: 'remote_react_module', filename: 'RemoteEntry.js', exposes: { './Kylo': './src/components/Kylo', }, shared: { }, }),
Configuring Host App Host - React
- Use
ModuleFederationPlugin
in yourwebpack.config.js
of the app that you wish to consume modules. We'll call this "host_react_module". - I'm demonstrating here only the implementation of
ModuleFederationPlugin
and not adding all the configuration ofwebpack.config.js
of the app
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin; // your original webpack.config.js configuration plugins: [ new ModuleFederationPlugin({ name: 'host_react_module', filename: 'remoteEntry.js', remotes: { remote_nextjs_module: 'remote_nextjs_module@http://localhost:8081/_next/static/chunks/remoteEntry.js', remote_react_module: 'remote_react_module@http://localhost:8082/remoteEntry.js', }, shared: { react: { // Notice shared are NOT eager here. requiredVersion: false, singleton: true, }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ],
Configure HTML
- Go to your
HTML
file and add the following
<noscript id="__next_css__DO_NOT_USE__"></noscript>
- By default NextJS adds a meta tag in its HTML called:
__next_css__DO_NOT_USE__
to their HTML files - We need this tag on our non next apps so the injector can find and load
css
below that tag
- Go to your
Go to your component in the React Host App where you want to consume the remote components
Use
React.lazy
or low level api to import remotes.
import React, { Suspense } from 'react'; const Kylo = React.lazy(() => import('remote_react_module/Kylo')); const BB8 = React.lazy(() => import('remote_nextjs_module/BB8')); function App() { return ( <> <Suspense fallback={'loading...'}> <BB8 /> <Kylo /> </Suspense> </> ); }export default App;
Result
- I have a
React
Host App that consumes two remote components and one local component, here - One component from a
NextJS
Remote App, here - One component from a
React
Remote App, here - One component from the host App
Troubleshooting
- Uncaught Error: Shared module is not available for eager consumption
Solution
For example, your entry looked like this:
index.js
import App from './App'; import React from 'react'; import { createRoot } from 'react-dom/client'; const container = document.getElementById('root'); const root = createRoot(container); root.render(<App />);
- Let's create
bootstrap.js
file and move contents of the entry into it, and import that bootstrap into the entry: index.js
import('./bootstrap');
bootstrap.js
import App from './App'; import React from 'react'; import { createRoot } from 'react-dom/client'; const container = document.getElementById('root'); const root = createRoot(container); root.render(<App />);
- More in here
- Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')
Solution
- By default
NextJS
adds a meta tag in itsHTML
called:__next_css__DO_NOT_USE__
to theirHTML
files We need that tag on our non next apps so the injector can find and load
css
below that tagindex.html
- non next app
<!DOCTYPE html> <html lang="en"> <head> </head> <noscript id="__next_css__DO_NOT_USE__"></noscript> <body> <div id="root"></div> </body> </html>
- Getting 404 for remotes Components
Solution
webpack
thinks public path is/
which is wrong. You want it to calculate the path based ondocument.currentScript.src
- Set
publicPath:auto
in yourwebpack.config.js
- Not adding all the configuration of
webpack.config.js
of the app
output: { publicPath: 'auto', },
Resources
- Github repo link
App
Original Link: https://dev.to/omher/building-react-app-with-module-federation-and-nextjsreact-1pkh
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To