Executando verificação de segurança...
1

Como usar module federation com Nextjs 14 e typescript?

Estou trabalhando em um novo projeto com Nextjs 14 e typescript, e temos que compartilhar entre diferentes projetos, (de times diferentes) o Header e o Footer. Pesquisando um pouco vi que para desafios como esse, é possivel usar Module Federation, porem tudo o que encontrei esta usando versoes anteriores do Nextjs e/ou javascript.
Alguem sabe me dizer como configurar o ModuleFederationPlugin do webpack ou NextFederationPlugin module-federation/nextjs-mf?

Abaixo as alternativas que tentei:

Usando webpack ModuleFederationPlugin

No projeto que exporta os componentes, estou chamando ele de main, temos o seguinte next.config.mjs

import ModuleFederationPlugin from 'webpack/lib/container/ModuleFederationPlugin.js';

import ModuleFederationPlugin from 'webpack/lib/container/ModuleFederationPlugin.js';

/** @type {import('next').NextConfig} */
const nextConfig = {
    reactStrictMode: true,
    webpack: (config, options) => {
        const { isServer } = options;
        config.plugins.push(
            new ModuleFederationPlugin({
                name: 'main',
                remotes: {
                    shop: `shop@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
                },
                exposes: {
                    './footer': './src/components/Footer.tsx',
                    './header': './src/components/Header.tsx',
                },
                filename: 'static/chunks/remoteEntry.js',
                shared: {}
            }),
        );
        return config;
    }
};
export default nextConfig;

Com esse código a aplicacao main funciona corretamente, porem o projeto que precisa usar o Header e o Footer, retorna erro
ReferenceError: document is not defined while loading "./header" from webpack/container/reference/main while loading "./footer" from webpack/container/reference/main

Tentei usar de duas formas

const Header = dynamic(() => import("main/header"));

const Footer = dynamic(() => import("main/footer").then((mod) => mod.Footer),
  {
    ssr: true
  }
);

E este é o next.config.mjs do projeto que consome o Header e o Footer

import ModuleFederationPlugin from 'webpack/lib/container/ModuleFederationPlugin.js';

const nextConfig = {
  reactStrictMode: true,
  webpack(config, { isServer }) {
    config.plugins.push(
      new ModuleFederationPlugin({
        name: 'shop',
        remotes: {
          main: ``main@http://localhost:3000/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js``,
        },
        filename: 'static/chunks/remoteEntry.js',
      })
    );

    return config;
  },
}

export default nextConfig;

NextFederationPlugin

No projeto main o meu arquivo next.config.mjs fica assim:

import { NextFederationPlugin } from '@module-federation/nextjs-mf';

/** @type {import('next').NextConfig} */
const nextConfig = {
    reactStrictMode: true,
    webpack(config, options) {        
        const { isServer } = options;
        config.plugins.push(
            new NextFederationPlugin({
                name: 'main',
                exposes: {
                    './footer': './src/components/Footer.tsx',
                },
                remotes: {
                    home: `home@http://localhost:3001/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
                },
                filename: 'static/chunks/remoteEntry.js',
                shared: {}
            }),
        );

        return config;
    }
};

export default nextConfig;

Com esse código a aplicao main nao funciona, ao tentar rodar recebo este erro:

Error: Compiling RuleSet failed: Expected condition but got falsy value (at ruleSet[1].rules[14].oneOf[5].exclude[0]: undefined)

Carregando publicação patrocinada...
1

Rapaz, eu não tenho experiência em Next.js, mas quero dizer que, onde eu trabalho atualmente, o líder técnico decidiu utilizar o module federation. Sendo assim, fomos "forçados" a implementá-lo em nossa aplicação, e vou te dizer, foi bug atrás de bug por mais de um mês até conseguirmos algo estável.

Minha experiência foi muito desagradável.