Vite

@module-federation/vite leva o Module Federation para o Vite 5, 6, 7 e 8:

  • Gera módulos que seguem as especificações de carregamento do Module Federation.
  • Consome, por meio de aliases, módulos que seguem as especificações do Module Federation.
  • Permite configurar dependências compartilhadas entre módulos, de modo que, quando o ambiente host do módulo carregado já tem a dependência correspondente, ela não é carregada de novo.
  • Quando um módulo tem tipos remotos, baixa e consome esses tipos automaticamente.
  • Faz hot update de módulos remotos dentro do host durante o desenvolvimento.
  • Renderiza módulos remotos no servidor para hosts com SSR.
Frameworks

Usa Nuxt, TanStack Start ou Vinext? Veja os guias de Nuxt, TanStack e Vinext para a configuração específica de cada framework, incluindo SSR.

Início rápido

Instalação

Instale o plugin com um dos comandos abaixo:

npm
yarn
pnpm
bun
npm add @module-federation/vite --save

Crie o module-federation.config.ts

Crie o arquivo module-federation.config.ts com o seguinte conteúdo:

module-federation.config.ts
import { createModuleFederationConfig } from '@module-federation/vite';

export default createModuleFederationConfig({
  name: 'vite_provider',
  manifest: true,
  remotes: {
    esm_remote: {
      type: 'module',
      name: 'esm_remote',
      entry: 'https://[...]/remoteEntry.js',
    },
    var_remote: 'var_remote@https://[...]/remoteEntry.js',
  },
  exposes: {
    './button': './src/components/button',
  },
  shared: {
    react: {
      singleton: true,
    },
    'react/': {
      singleton: true,
    },
  },
});

Registre o plugin

No Vite, adicione o plugin pela opção plugins do arquivo vite.config.ts:

vite.config.ts
import { federation } from '@module-federation/vite';
import { defineConfig } from 'vite';
import mfConfig from './module-federation.config';

export default defineConfig({
  server: {
    origin: 'http://localhost:2000',
    port: 2000,
  },
  base: 'http://localhost:2000',
  plugins: [federation(mfConfig)],
  // Do you need to support build targets lower than chrome89?
  // You can use 'vite-plugin-top-level-await' plugin for that.
  build: {
    target: 'chrome89',
  },
});

Remotes definidos como objeto sem type mantêm o padrão legado "var" e geram um aviso no log. Use type: 'module' para remotes do Vite e type: 'var' apenas para remotes em formato global, como containers do Webpack ou do Rspack, ou a saída varFilename de um remote do Vite.

Configure o plugin de build

  • Tipo: federation(options: ModuleFederationOptions)

  • A estrutura de configuração do plugin do Module Federation é a seguinte:

type ModuleFederationOptions = {
  name: string;
  filename?: string;
  exposes?: Record<string, string | { import: string }>;
  remotes?: Record<string, string | RemoteObjectConfig>;
  shared?: ShareInfos;
  // ...plus the Vite-specific options below
};

As opções de configuração comuns estão explicadas em detalhes na página Visão geral da configuração. As opções a seguir são específicas do plugin do Vite:

OpçãoTipoPadrãoDescrição
hostInitInjectLocation'html' | 'entry''html'Onde o script de inicialização do host é injetado. Use 'entry' em apps sem index.html, como hosts com SSR.
varFilenamestringGera um remote entry var adicional para hosts legados que carregam remotes com type: 'var'.
ssrFilenamestring<filename base>.ssr.jsNome do arquivo do remote entry de SSR.
bundleAllCSSbooleanfalseAdiciona todos os assets CSS do bundle a cada módulo exposto.
moduleParseTimeoutnumber10Tempo máximo, em segundos, de espera pelo parsing de módulos durante o build.
moduleParseIdleTimeoutnumberIgual a moduleParseTimeout, mas o contador reinicia a cada módulo processado. Prefira esta opção em codebases grandes.
target'web' | 'node''web', ou 'node' quando build.ssr está ativoAmbiente de destino, usado para fazer tree-shaking do runtime de federation.
disableRemotebooleanfalseRemove do runtime o suporte ao consumo de remotes. Não ative quando houver remotes configurados.
disableSharedbooleanfalseRemove do runtime o suporte a dependências compartilhadas. Não ative quando houver shared configurado.
disableSnapshotbooleantrue em builds Node/SSR, senão falseRemove o suporte a snapshots, incluindo remotes baseados em manifest, preload, dicas de tipos dinâmicas, HMR e a integração com o devtools.
ssrEntryLoaderSsrEntryLoaderConfigControla como hosts com SSR carregam os remote entries. Veja Renderização no servidor.
ssrExternalsstring[]Pacotes adicionais, exclusivos do Node, que devem ficar externos no remote entry de SSR. Pacotes compartilhados e de runtime já são externos por padrão.

A opção manifest também aceita um objeto com fileName, filePath, disableAssetsAnalyze e um hook additionalData para alterar os arquivos mf-manifest.json e mf-stats.json gerados.

Hot update entre remotes

Ative dev.remoteHmr no host para fazer hot update de módulos remotos enquanto os dois apps rodam em desenvolvimento:

vite.config.ts
federation({
  name: 'host',
  remotes: {
    // ...
  },
  dev: {
    remoteHmr: true,
  },
});

Com true, remotes em React (@vitejs/plugin-react ou @vitejs/plugin-react-swc) e Vue (@vitejs/plugin-vue ou @vitejs/plugin-vue-jsx) usam o HMR nativo do framework, e os demais frameworks recorrem a um recarregamento completo da página. Use 'full-reload' para sempre recarregar a página. O remoteHmr vem desativado por padrão. As outras opções de dev estão descritas em dev.

Renderização no servidor

Um remote gera um entry de servidor ao lado do entry do navegador, chamado <filename base>.ssr.js por padrão ou com o nome definido em ssrFilename, e o anuncia como metaData.ssrRemoteEntry no mf-manifest.json. Hosts com SSR que consomem remotes pelo manifest escolhem automaticamente o entry do navegador ou o do servidor.

ssrEntryLoader controla como o host avalia os remote entries durante o build e o preview:

vite.config.ts
federation({
  name: 'host',
  remotes: {
    // ...
  },
  ssrEntryLoader: {
    strategy: 'temp-file', // or 'vm'
    maxAgeMs: 60_000,
    fetchTimeoutMs: 5_000,
    fetchMaxBytes: 5 * 1024 * 1024,
  },
});
  • 'temp-file' (padrão) busca o grafo do remote, reescreve os imports para apontar para os pacotes compartilhados do host, grava arquivos temporários e os carrega com import().
  • 'vm' avalia o grafo em memória com vm.SourceTextModule. Exige que o Node.js rode com --experimental-vm-modules e, se essa flag estiver ausente, recorre a 'temp-file' com um aviso.
  • maxAgeMs verifica de novo o manifest de cada remote depois do tempo indicado, para que um remote republicado na mesma URL seja detectado. Se omitido, o cache dura até o processo terminar.
  • fetchTimeoutMs e fetchMaxBytes limitam cada requisição, com padrão de 10 segundos e 10 MiB. 0 desativa o limite.

No desenvolvimento com Vite 8 é usado o ModuleRunner do Vite, então essas opções afetam principalmente o build e o preview.

O entry de SSR mantém @module-federation/runtime, @module-federation/runtime-core e @module-federation/sdk como externos, para que o Node os resolva a partir do host. Se o host não conseguir resolver esses pacotes, como no caso de um host que usa apenas @module-federation/enhanced, configure ssr.noExternal do Vite no remote para gerar um entry autocontido.

Experimentos

Runtime externo

Compartilhe uma única instância de @module-federation/runtime-core a partir do host, para que os remotes não incluam a própria cópia no bundle. Defina experiments.provideExternalRuntime: true no host e experiments.externalRuntime: true em cada remote. Apenas um container na página deve fornecer o runtime, e ele precisa carregar antes de qualquer remote que o utilize.

Host fornece todos os shared

Quando um único host fornece todas as dependências compartilhadas e os remotes apenas as consomem, experiments.hostProvidesAllShared: true resolve as dependências compartilhadas por meio de um import map nativo do navegador, em vez do runtime de federation. Defina a opção no host e em todos os remotes:

remote/vite.config.ts
federation({
  name: 'remote',
  exposes: { './Button': './src/Button.tsx' },
  shared: { react: {}, 'react-dom': {}, 'react/jsx-runtime': {} },
  experiments: { hostProvidesAllShared: true },
});
host/vite.config.ts
federation({
  name: 'host',
  remotes: { remote: 'https://cdn.example.com/remote/mf-manifest.json' },
  shared: { react: {}, 'react-dom': {}, 'react/jsx-runtime': {} },
  experiments: { hostProvidesAllShared: true },
});

Os módulos compartilhados viram imports ES estáticos comuns, então código que lê um valor compartilhado durante a avaliação dos módulos funciona sem eager. Esse modo não carrega o runtime de federation e, por isso, não oferece negociação de versões, import: false, plugins de runtime, SSR, loadRemote nem interoperabilidade com containers do Webpack e do Rspack.

Ilhas React com SSR

experiments.ssrMode: 'ISLAND' permite que um remote que não compartilha o React seja renderizado no servidor e hidratado com o próprio React, fora da árvore React do host. Veja Ilhas React isoladas.

Divisão em chunks

O plugin gerencia a divisão em chunks para que o runtime de federation e os wrappers de dependências compartilhadas carreguem na ordem correta. Definir codeSplitting como false é ignorado com um aviso.

No Vite 8, seus build.rolldownOptions.output.codeSplitting.groups são mantidos abaixo dos grupos de federation, e manualChunks é ignorado com um aviso; mova esse agrupamento para codeSplitting.groups. Do Vite 5 ao 7, uma função manualChunks continua rodando para os módulos que o plugin não assume, enquanto a forma de objeto é ignorada.