Module Federation или Micro Frontend не работают в Next js версии 12.2.0

Я выполнил следующие шаги, чтобы добиться объединения модулей в следующем js.

  1. Создайте компонент Insurance_Detail.tsx в репозитории cm-insurance-web внутри папки src/node/components, который будет доступен. Ниже приведен файл next.config.js.
const assetPrefix = '/jobs-assets';
const nextConfig = {
  assetPrefix,
  env: {
    assetPrefix
  },
  experimental: {
    images: {
      unoptimized: true
    }
  },
  reactStrictMode: true,
  webpack5: true,
  srcDir: 'src/node/',
  //distDir: 'build',
  webpack: (config, options) => { // webpack configurations
    config.plugins.push(
        new options.webpack.container.ModuleFederationPlugin({
          name:"InsuranceA",
          filename: "static/chunks/pages/cm_insurance_web.js", // remote file name which will used later
          remoteType: "var",
          exposes: { // expose all component here.
            **"./InsuranceDetail": "./components/Insurance_Details.tsx"**
          },
          shared: [
            {
              react: {
                eager: true,
                singleton: true,
                requiredVersion: false,
              }
            },
            {
              "react-dom": {
                eager: true,
                singleton: true,
                requiredVersion: false,
              }
            },
          ]
        })
    )
      config.cache = false;
    config.output.publicPath = 'http://localhost:3000/_next/';
    return config
  }
}

module.exports = nextConfig
  1. Когда мы собираем репо cm-insurance-web с помощью команды npm run build, мы видим, что файл javascript создается внутри src/node/.next/static/chunks/pages/cm_insurance_web.js. Этот репозиторий проекта работает на порту 3000 на локальном хосте.

  2. Теперь нужно использовать этот javascript в другом репозитории, скажем, cm-job-board-web. Давайте создадим потребительское приложение. Ниже приведен файл next.config.js для него

/** @type {import('next').NextConfig} */
const assetPrefix = '/jobs-assets';
const path = require('path');
const nextConfig = {
  assetPrefix,
  env: {
    assetPrefix
  },
  basePath: '/search-jobs',
  experimental: {
    images: {
      unoptimized: true
    }
  },
  reactStrictMode: true,
  srcDir: 'src/node/',
  webpack: (config, options) => {
    config.plugins.push(
        new options.webpack.container.ModuleFederationPlugin({
          name:"jobboardWeb",
          filename: "static/chunks/cm_job_board_web.js",
          remoteType: "var",
          remotes: {
              InsuranceA: JSON.stringify('InsuranceA@http://localhost:3000/jobs-assets/_next/static/chunks/pages/cm_insurance_web.js')
          },exposes: {},
            shared: [
                {
                    react: {
                        eager: true,
                        singleton: true,
                        requiredVersion: false,
                    }
                },
                {
                    "react-dom": {
                        eager: true,
                        singleton: true,
                        requiredVersion: false,
                    }
                },
            ]
        })
    )
      config.cache = false;
    return config
  },
  webpack5: true
}

module.exports = nextConfig
  1. добавьте тег script в файл _app.tsx потребительского приложения следующим образом:
import { AppProps } from "next/app";
import "bootstrap/dist/css/bootstrap.css";
import "../styles/globals.scss";
import Layout from "../components/layout";
import { persistor, store } from "../store/store";
import { Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import Authentication from "../config/auth.gaurd";
import Head from "next/head";
import React from "react";
import Script from "next/script";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Layout>
        <>
            <Script src = "http://localhost:3000/jobs-assets/_next/static/chunks/pages/cm_insurance_web.js" />
            <Head>
                <link rel = "preconnect" href = "https://fonts.googleapis.com"/>
                <link rel = "preconnect" href = "https://fonts.gstatic.com"/>
                <link rel = "stylesheet" href = "https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@100;200;300;400;500;600;700&display=swap"/>
                <link rel = "shortcut icon" href = "/favicon2.ico"/>
                <title>Jobboard Search</title>
            </Head>
            <Script id = "gtm-script" strategy = "afterInteractive">
                {`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
                    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
                    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
                    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
                    })(window,document,'script','dataLayer','GTM-TKJH8RR');`
                }
            </Script>
            <Provider store = {store}>
                <PersistGate loading = {null} persistor = {persistor}>
                    <Authentication>
                        <noscript dangerouslySetInnerHTML = {{ __html:
                            `<iframe src = "https://www.googletagmanager.com/ns.html?id=GTM-TKJH8RR"
                            height = "0" width = "0" style = "display:none;visibility:hidden"></iframe>
                            `}}>
                        </noscript>
                        <Component {...pageProps} />
                    </Authentication>
                </PersistGate>
            </Provider>
        </>
    </Layout>
  );
}

export default MyApp;
  1. Давайте импортируем этот модуль в файл index.tsx и используем его.
import {NextPage} from "next";
import React, {lazy, Suspense, useState} from "react";
import dynamic from 'next/dynamic'


const InsuranceDetail2 = dynamic(() => import(('InsuranceA/InsuranceDetail')), {
    ssr: false
}) as NextPage;

const Insurance: NextPage = ({}: any) => {

    return (

            <InsuranceDetail2 />

    )
}


export default Insurance

После выполнения вышеуказанных шагов я смог увидеть, что удаленный файл js загружается на вкладке сети браузера, но удаленный компонент не отображается и получает пустую страницу.

Пожалуйста, найдите прикрепленный скриншот

Пожалуйста, дайте мне знать, если я что-то пропустил здесь. Я взял ссылку из ссылок ниже.

  1. https://blog.logrocket.com/micro-frontend-react-next-js/
  2. https://blog.logrocket.com/building-micro-frontends-webpacks-module-federation/
  3. https://dev.to/omher/building-react-app-with-module-federation-and-nextjsreact-1pkh
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
772
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Установка nextjs-mf ⚠️ Внимание: для работы приложения с функциями Module Federation вам необходимо иметь доступ к https://app.privjs.com/package?pkg=@module-federation/nextjs-mf[[nextjs-ssr^] плагин, который в настоящее время требует платной лицензии!

Чтобы установить инструмент, нам нужно войти в [PrivJs}(https://privjs.com/^) с помощью npm, для этого выполните следующую команду:

npm логин --registry https://r.privjs.com

Как только это будет сделано, файл, содержащий ваши учетные данные, будет сохранен в ~/.npmrc. Теперь вы можете установить nextjs-mf с помощью следующей команды:

npm install @module-federation/nextjs-mf --registry https://r.privjs.com

поэтому федерация модулей является платным модулем в следующем js, и с помощью платного модуля я могу этого добиться.

  1. next.config.js модуля страхования.
/** @type {import('next').NextConfig} */
const NextFederationPlugin = require('@module-federation/nextjs-mf');
const assetPrefix = '/jobs-assets';
const nextConfig = {
  assetPrefix,
  env: {
    assetPrefix
  },
  reactStrictMode: true,
  webpack5: true,
  srcDir: 'src/node/',
  //distDir: 'build',
  webpack: (config, options) => { // webpack configurations
      if (!options.isServer) {
          config.plugins.push(
              new NextFederationPlugin({
                  name: "insurancea",
                  filename: "static/chunks/pages/cm_insurance_web.js", // remote file name which will used later
                  exposes: { // expose all component here.
                      "./insurancedetail": "./components/Insurance_Details.tsx"
                  },
                  shared:
                      {
                          react: {
                              singleton: true,
                              requiredVersion: false,
                          }
                      }
              }),
          );
      }
      return config
  }
};

module.exports = nextConfig

  1. добавить зависимость объединения модулей в package.json.
"dependencies": {

 "@module-federation/nextjs-mf": "^5.9.2",
}
  1. добавить импорт в файл _app.tsx того же страхового модуля.
import '@module-federation/nextjs-mf/src/include-defaults';

Вот и все, что касается компонента expose

  1. Теперь обновите его для удаленного компонента (потребительское приложение — cm-job-board-web) в next.config.js.
/** @type {import('next').NextConfig} */
const NextFederationPlugin = require('@module-federation/nextjs-mf');
const assetPrefix = '/jobs-assets';
const path = require('path');
const nextConfig = {
  assetPrefix,
  env: {
    assetPrefix
  },
  basePath: '/search-jobs',
  reactStrictMode: true,
  srcDir: 'src/node/',
  webpack: (config, options) => {
      if (!options.isServer) {
          config.plugins.push(
              new NextFederationPlugin({
                  name: "jobboardWeb",
                  filename: "static/chunks/cm_job_board_web.js",
                  remotes: {
                      //  cm_insurance_web: options.isServer ? 'http://localhost:3000/jobs-assets/_next/static/chunks/cm_insurance_web.js' : 'fe1'
                      insurancea: 'insurancea@http://localhost:3000/jobs-assets/_next/static/chunks/pages/cm_insurance_web.js'
                  }, exposes: {},
                  shared: {}
              }),
          );
      }
    return config
  },
  webpack5: true
};

module.exports = nextConfig

  1. добавить зависимость федерации модулей в package.json потребительского приложения.
"dependencies": {

 "@module-federation/nextjs-mf": "^5.9.2",
}
  1. добавить импорт в файл _app.tsx потребительского приложения.
import '@module-federation/nextjs-mf/src/include-defaults';
  1. наконец, импортируйте этот модуль в файл index.tsx и используйте его в пользовательском приложении.
import { Suspense } from 'react'
import React from 'react'
import dynamic from 'next/dynamic'

const DynamicComponent4 = dynamic(
    () => import('insurancea/insurancedetail'),
    { loading: () => <p>Loading caused by client page transition ...</p>, ssr: false }
)


export default function Insurance() {
    return (
        <div>

                <DynamicComponent4 />

        </div>
    )
}

Вот и все.

Это устарело, исходный код проекта был полностью открыт в июле 2021 года, и платного уровня больше нет github.com/module-federation/module-federation-examples/…

Tom 07.12.2022 18:03

Другие вопросы по теме