Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 23, 2022 06:40 am GMT

Building React App with Module Federation and NextJS/React

Module Federation Architecture

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 your next.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 your webpack.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 of webpack.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 your webpack.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 of webpack.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 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

Blog 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

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 />);

- Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')

Solution

  • By default NextJS adds a meta tag in its HTML called: __next_css__DO_NOT_USE__ to their HTML files
  • We need that tag on our non next apps so the injector can find and load css below that tag

  • index.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

Getting 404 for remotes Components

Solution

  • webpack thinks public path is / which is wrong. You want it to calculate the path based on document.currentScript.src
  • Set publicPath:auto in your webpack.config.js
  • Not adding all the configuration of webpack.config.js of the app
    output: {        publicPath: 'auto',    },

Resources


Original Link: https://dev.to/omher/building-react-app-with-module-federation-and-nextjsreact-1pkh

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To