E-commerce de demonstração (shell + 3 microfrontends) que prova, com código real, como Module Federation 2.0 resolve composição por rota, estado compartilhado, dependências singletons e isolamento de falhas. Stack: Vite + React 19 + Tailwind 4 + TypeScript, roteamento com React Router 7.
Funcionalidades
Shell (host) monta páginas inteiras (bridge) e widgets (
cart/MiniCart,catalog/ProductGrid) dos remotesNavegação SPA entre MFEs sem reload (
MfeLink+ popstate sintético,RouterSync)Store do carrinho singleton em todos os apps, persistida em
localStoragee limitada ao estoqueEvent bus tipado (
cart:item-added,order:placed,remote:status…) com toasts no shell — sem importar código dos remotesResiliência: error boundary, card de fallback com porta + botão Recarregar, degradação do badge para a store local
StatusChipsno header: status por remote (ok/erro) + contagem de instâncias da store e do bus (detecção de singleton quebrado)Cada remote roda standalone (deploy independente)
Design tokens compartilhados (
@theme), CSS compilado por app, dark modeQualidade:
typecheck,lint, testes (21), smoke E2E (17 passos), verificação de produção e de resiliência
Começando
Requisitos: Node ^20.19 || >=22.12 (testado em Node 24.11 + npm 11.6) e Microsoft Edge instalado (os scripts E2E usam playwright-core com channel: 'msedge').
npm install
npm run dev # shell + catalog + cart + checkout
Abra http://localhost:5000 — os remotes sobem nas portas 5001–5003.
Scripts
Comando | O que faz |
|---|---|
| 4 dev servers Vite ( |
| build de todos os workspaces (gera |
| serve os builds de produção (rode |
|
|
| ESLint flat config único |
| Vitest (21 testes: store + event-bus) |
| smoke E2E no build de dev (17 checks, Edge headless) |
Scripts de verificação (exigem os dev servers no ar):
Comando | O que prova |
|---|---|
| produção: CSS dos remotes no host, singletons (7/7) |
| cart fora do ar: shell + catálogo seguem (8/8) |
| gera as imagens de |
Variáveis opcionais (apps/shell/.env.example): VITE_CATALOG_ENTRY, VITE_CART_ENTRY, VITE_CHECKOUT_ENTRY — permitem apontar o shell para builds remotos sem recompilar.
Arquitetura
flowchart LR
subgraph shell["shell :5000 (host)"]
Layout["Layout + rotas + chips + toast"]
end
subgraph pkgs["packages (fronteira entre times)"]
Contracts["contracts"]
Store["cart-store (singleton)"]
Bus["event-bus (singleton)"]
UI["ui (tokens)"]
end
subgraph remotes["remotes"]
Catalog["catalog :5001"]
Cart["cart :5002"]
Checkout["checkout :5003"]
end
Layout -->|loadRemote bridge| Catalog
Layout -->|loadRemote bridge| Cart
Layout -->|loadRemote bridge| Checkout
Catalog --> Store
Cart --> Store
Checkout --> Store
Catalog --> Bus
Cart --> Bus
Checkout --> Bus
shell --> Contracts
shell --> UI
remotes --> UI
Três camadas de comunicação (nenhum app importa código do outro):
@microstore/contracts— tipos + registryREMOTES(fonte única de nome/porta/rota);@microstore/cart-store— estado síncrono,sharedsingleton via MF;@microstore/event-bus— eventos tipados para efeitos transversais.
O bloco shared (react, router, store, bus) é declarado uma única vez em packages/build-config e herdados pelos 4 vite.config.ts — anti-drift de versões. Detalhes: docs/01, docs/03, docs/04.
Estrutura do projeto
poc-microfrontends/
├── apps/
│ ├── shell/ # host (:5000) — layout, rotas, chips, toast, remotes/
│ ├── catalog/ # remote (:5001) — listagem, detalhe, ProductGrid
│ ├── cart/ # remote (:5002) — CartPage, MiniCart
│ └── checkout/ # remote (:5003) — CheckoutPage
├── packages/
│ ├── contracts/ # tipos, eventos, registry REMOTES
│ ├── cart-store/ # store Zustand persistida (singleton via MF)
│ ├── event-bus/ # barramento tipado (singleton via MF)
│ ├── ui/ # theme.css (@theme), componentes compartilhados
│ └── build-config/ # bloco shared, alias, URLs de entry
├── docs/ # 8 guias (arquitetura → tradeoffs)
├── scripts/ # smoke, verify-preview, verify-resilience, screenshots
├── PLANO.md # decisões técnicas, riscos e critérios de aceite
└── PRODUCT.md # produto, personas e requisitos
Testes
npm test # unit: store (clamp de estoque + persistência) e bus
npm run smoke # E2E: fluxo completo home → catálogo → carrinho → checkout
O smoke cobre os 17 passos do happy path (inclusive remotes standalone e 404) e reporta pageerrors/console.errors/requestfailed no resumo. Os avisos de console exclusivos de dev (React 19 × bridge-react/next-themes) são filtrados por serem ausentes na build de produção — ver docs/06.
O mesmo conjunto (typecheck, lint, unit e smoke) roda no CI a cada push/PR — .github/workflows/ci.yml — e um push em master publica o site no GitHub Pages (job deploy, após os dois verdes).
Documentação
Doc | Responde |
|---|---|
01 — Arquitetura | como as peças se conectam |
02 — Composição e roteamento | como um remote é montado e navega |
03 — Comunicação e estado | como os apps conversam sem se importar |
04 — Shared deps e singletons | como evitar React duplicado |
05 — Estilos e design tokens | como o CSS se mantém isolado |
06 — Resiliência e observabilidade | o que acontece quando um remote cai |
07 — Deploy e versionamento | como publicar um remote sozinho |
08 — Tradeoffs e alternativas | quando não usar microfrontends |
Limitações conhecidas
POC sem backend: pagamento/pedido são simulados; sem SSR nem auth (PLANO.md §1) — o CI (typecheck, lint, unit, smoke) roda no GitHub Actions e o push em
masterpublica emhttps://gustavomssell.github.io/poc-microfrontends/(docs/07).O fallback de remote derrubado oferece recarregar a página — não há retry in-place (o
React.lazycacheia a falha).Em desenvolvimento, o React 19 emite 2 avisos de console (bridge-react × unmount; next-themes × script inline) que não existem na build de produção — docs/06.
A navegação interna de um remote não repinta o
NavLinkativo do shell até o próximo popstate (cosmético) — docs/02.
Licença
MIT — ver LICENSE.

