1
resposta

[Dúvida] Não consigo reproduzir o projeto da aula de Single SPA

Estou fazendo o curso de Single SPA https://cursos.alura.com.br/course/single-spa-orquestrando-micro-frontends mas não estou conseguindo passar da segunda aula pois não consigo reproduzir o projeto.

O comando create-single-spa cria um projeto react que sequer é capaz de instalar as dependências corretamente, quando consigo resolver o problema das dependências, o arquivo js gerado dá erro com o orquestrador.

application '@empresa/projeto' died in status LOADING_SOURCE_CODE: The specifier "react" was a bare specifier, but not remapped to anything. Relative module specifiers must start with "./", "../" or "/".

Estou utilizando uma VM Ubuntu 24.04 pra evitar problemas de ambiente, e mesmo utilizando a versão que o professor indica para o nodejs (21.5.0) não funciona. Já tentei também as versões LTS 22 e 20, mas dão os mesmos problemas.

1 resposta

Oi, Leandro! Como vai? Vamos resolver isso.

Com base no que você explicou o problema aqui é que react e react-dom não estão mapeados no import map, então o navegador interrompe com bare specifier.

Siga esses passos para resolver:

1) index.ejs — mantenha seu arquivo e adicione os mapeamentos e o @empresa/projeto no bloco local:


<!-- dentro do bloco local do import map -->
<script type="injector-importmap">
{
  "imports": {
    "@home-hub/root-config": "//localhost:9000/home-hub-root-config.js",
    "@single-spa/welcome": "https://cdn.jsdelivr.net/npm/single-spa-welcome/dist/single-spa-welcome.min.js",

    "react": "https://cdn.jsdelivr.net/npm/react@18.2.0/+esm",
    "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@18.2.0/+esm",
    "react-dom/client": "https://cdn.jsdelivr.net/npm/react-dom@18.2.0/client/+esm",

    "@empresa/projeto": "//localhost:9001/empresa-projeto.js"
  }
}
</script>

Observação: sua CSP já permite https: e localhost:*, então estes CDNs funcionam.

2) root-config — registre o microfrontend @empresa/projeto:


// root-config/src/root-config.ts
import { registerApplication, start } from "single-spa";

registerApplication({
  name: "@empresa/projeto",
  app: () => import("@empresa/projeto"),
  activeWhen: (loc) => loc.pathname.startsWith("/")
});

start();

3) @empresa/projeto — exponha os lifecycles (React 18):


// projeto/src/root.component.tsx
import React from "react";

export default function Root() {
  return <div style={{ padding: 8 }}>Hello World - MF React</div>;
}

// projeto/src/empresa-projeto.tsx
import React from "react";
import * as ReactDOMClient from "react-dom/client";
import singleSpaReact from "single-spa-react";
import Root from "./root.component";

const lifecycles = singleSpaReact({
  React,
  ReactDOMClient,
  rootComponent: Root,
  errorBoundary() {
    return React.createElement("div", null, "Erro no microfrontend");
  },
});

export const bootstrap = lifecycles.bootstrap;
export const mount = lifecycles.mount;
export const unmount = lifecycles.unmount;

4) webpack — ajuste org/project, mantenha externals e ESM:


// projeto/webpack.config.js
const { merge } = require("webpack-merge");
const singleSpaDefaults = require("webpack-config-single-spa-react-ts");

module.exports = (webpackConfigEnv, argv) => {
  const defaultConfig = singleSpaDefaults({
    orgName: "empresa",
    projectName: "projeto",
    webpackConfigEnv,
    argv,
    outputSystemJS: false, // ESM nativo com import-map
  });

  return merge(defaultConfig, {
    externals: ["react", "react-dom", "react-dom/client"], // resolvidos via import map
    devServer: {
      port: 9001,
      headers: { "Access-Control-Allow-Origin": "*" },
      historyApiFallback: true,
      hot: true,
    },
    output: {
      filename: "empresa-projeto.js",
      publicPath: "http://localhost:9001/",
    },
  });
};

5) package.json — confira o name e scripts:


// projeto/package.json (trechos)
{
  "name": "@empresa/projeto",
  "scripts": {
    "start": "webpack serve --mode development",
    "build": "webpack --mode production"
  },
  "dependencies": {
    "single-spa-react": "^5.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

Faça a reinstalação de dependências tanto no root como no projeto e agora deve funcionar normalmente.

Checklist rápido do que conferir:


[ ] index.ejs mapeia **react**, **react-dom**, **react-dom/client**
[ ] index.ejs mapeia **@empresa/projeto** para 9001/empresa-projeto.js
[ ] webpack usa **externals** para react* e **publicPath/filename** corretos
[ ] root-config faz **import("@empresa/projeto")**
[ ] portas e CORS conferem (9000/9001, Access-Control-Allow-Origin: *)

Espero ter ajudado. Conte com o apoio do Fórum na sua jornada. Fico à disposição.

Abraços e bons estudos!