Saltar a contenido

Rsbuild

Rsbuild es un competidor justamente de Vite o Create-React-App, pero con la ventaja de que es mucho más flexible y configurable. Y cuenta con soporte de primera clase para Module Federation.

Una de las principales ventajas es que está diseñado para ser un cambio 1 a 1 a Webpack y que es muy fácil de configurar, sumado a que está hecho en Rust lo que lo hace más performante inclusive que vite, manteniendo la compatibilidad con desarrollos basados en Webpack. (Todos los CRA, Next.js, etc.)

Migración de CRA a Rsbuild

Hemos disponibilizado un comando en el CLI de @architecture-it/front-cli para facilitar la migración de proyectos de CRA a Rsbuild.

front-cli migrate

Este comando se encargará de realizar los cambios necesarios en el proyecto para que pueda ser ejecutado con Rsbuild.

Migración de CRA (simple) a Rsbuild

  • Se creará un archivo rsbuild.config.ts con la configuración básica.
Ejemplo de rsbuild.config.ts
rsbuild.config.ts
import { defaultConfig } from "@architecture-it/rsbuild";

export default defaultConfig({});
  • Se instalarán las dependencias necesarias para Rsbuild.
Se ejecutan los comandos
pnpm install @architecture-it/rsbuild @rsbuild/core @rsbuild/plugin-react @swc/core @swc/jest @testing-library/jest-dom @testing-library/react @types/jest jest jest-environment-jsdom cross-env identity-obj-proxy -D
  • Se modificará el archivo package.json para que se ejecute el comando de Rsbuild.
Se modifica el archivo package.json
{
  "scripts": {
    "prestart": "react-env --",
    "start": "rsbuild start",
    "build": "rsbuild build",
    "preview": "rsbuild preview",
    "test": "jest test",
    "posttest": "jest posttest",
    "test:coverage": "jest test:coverage",
    "test:coverage:ci": "jest test:coverage:ci",
    "test:watch": "jest test:watch",
    "test:specific": "jest test:specific",
    "test:specific-coverage": "jest test:specific-coverage",
    "test:clear-cache": "jest test:clear-cache"
  }
}
  • Se modificará el archivo tsconfig.json para que se pueda ejecutar con Rsbuild.
  • Se actualizará el archivo public/index.html para que se tome la carpeta pública.
Se reemplaza %PUBLIC_URL% por <%= assetPrefix %>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8" />
    <link rel="icon" href="<%= assetPrefix %>/favicon.png" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
    name="description"
    content="Andreani App"
    />
    <link rel="manifest" href="<%= assetPrefix %>/manifest.json" />
    <title>Andreani App</title>
    <script src="<%= assetPrefix %>/__ENV.js"></script>
    <link href="https://fonts.googleapis.com" rel="preconnect" />
    <link crossOrigin="crossorigin" href="https://fonts.gstatic.com" rel="preconnect" />
    <link
    href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,700&display=swap"
    rel="stylesheet"
    />
</head>
<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>
</html>
  • Se actualizará el archivo Dockerfile para que se pueda ejecutar con Rsbuild. La carpeta de build será dist.
Dockerfile esperado
FROM ghcr.io/architecture-it/react:node-20 AS deps
WORKDIR /app

RUN apk add --no-cache libc6-compat

COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./

RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci --no-progress --silent --maxsockets 1; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else \
    echo "ERROR: Falta archivo lockfile. Ver más en https://architecture-it.github.io/docs/Platform/Front/#manejo-de-dependencias"; \
    exit 1; \
fi

FROM ghcr.io/architecture-it/react:node-20 AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN yarn build

FROM ghcr.io/architecture-it/nginx:latest
COPY --from=builder /app/dist .
# WORKAROUND si se tiene problemas con permisos, (Evitar)
# RUN touch ./public/__ENV.js && chmod 777 ./public/__ENV.js

CMD ["/bin/sh", "-c", "react-env -d ./ -- && nginx -g \"daemon off;\""]
  • Se instalaran las dependencias para que Jest funcione, la diferencia es que se hará con swc y no con babel, para hacerlo más performante. Esto está dentro de la librería por lo que la configuración será transparente y customizable.

En el caso de los microfrontends se agregarán más archivos y configuraciones para que se pueda ejecutar con Rsbuild.

  • Se agregarán las dependencias necesarias para que se pueda ejecutar con Rsbuild.
Se ejecutan los comandos
pnpm install @module-federation/runtime @module-federation/enhanced
  • Se eliminára el archivo modulefederation.config.js y se agregará la confiuracion en el rsbuild.config.ts

  • Se inyectará la configuración necesaria para que se pueda ejecutar con Rsbuild. en el archivo src/bootstrap.tsx (Shell)

Ejemplo de src/bootstrap.tsx
src/bootstrap.tsx
import { createRoot } from "react-dom/client";
import { StyleSystemProvider } from "@architecture-it/stylesystem";
import { CssBaseline } from "@mui/material";
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "store/store";
import { initializeMicrofronts } from "@architecture-it/rsbuild/initializeMicrofronts";
import * as ReactRouterDom from "react-router-dom";
import { AuthProvider } from "@architecture-it/react-auth";

import pkg from "../package.json";

import rum from "./monitor";
import App from "./App";

const dependencies = pkg.dependencies;

initializeMicrofronts("shell", {
dependencies,
shared: {
    "react-router-dom": {
    version: dependencies["react-router-dom"],
    scope: "default",
    // por default toma esta instancia de la librería
    lib: () => ReactRouterDom,
    shareConfig: {
        singleton: true,
        requiredVersion: dependencies["react-router-dom"],
    },
    },
    "react-redux": {
    scope: "default",
    shareConfig: {
        singleton: true,
        requiredVersion: false,
    },
    },
},
});

rum.setInitialPageLoadName("Home");

const container = document.getElementById("root") as HTMLElement;
const root = createRoot(container);

root.render(
<BrowserRouter>
    <Provider store={store}>
    <AuthProvider>
        <StyleSystemProvider>
        <CssBaseline />
        <App />
        </StyleSystemProvider>
    </AuthProvider>
    </Provider>
</BrowserRouter>
);

Migración de Vite a Rsbuild

  • Se instalarán las dependencias necesarias para Rsbuild.
  • Se eliminaran las dependencias de vite así como los archivos de configuración.
  • Se cambiarán los nombres de las variables de los archivos de environments .env .devops/values-qa.yml ...
  • Se creará un archivo rsbuild.config.ts con la configuración básica.
  • Se modificará el archivo package.json para que se ejecute el comando de Rsbuild. Así como el tipo de module se eliminara.
  • Se modificará el archivo tsconfig.json para que se pueda ejecutar con Rsbuild.
  • Se actualizará el archivo public/index.html para que se tome la carpeta pública.
  • Se actualizará el archivo Dockerfile para que se pueda ejecutar con Rsbuild. La carpeta de build será dist. Y no necesitará el prefijo VITE
  • Se instalaran las dependencias para que Jest funcione, la diferencia es que se hará con swc y no con babel, para hacerlo más performante. Esto está dentro de la librería por lo que la configuración será transparente y customizable.

En el caso de los microfrontends se agregarán más archivos y configuraciones para que se pueda ejecutar con Rsbuild.

  • Se agregarán las dependencias necesarias para que se pueda ejecutar con Rsbuild.
  • Se agreará la confiuracion básica en el rsbuild.config.ts. Necesita configuración manual
  • Se inyectará la configuración necesaria para que se pueda ejecutar con Rsbuild. en el archivo src/App.tsx (Shell)
  • Se renombrará el arcivo src/main.tsx a src/bootstrap.tsx y en src/index.tsx se dejará el entrypoint de la aplicación, asincrono como lo require modue federation.

Si se agrega el flag de migrateToJest (confirmación), se ejecutaran automatizaciones sobre la carpeta src/__test__ para que se pueda ejecutar con Jest, así como el linter y el formatter de conseguirlo.

Se automatizaron los siguientes cambios:

  • Se eliminan todos los import de vitest
  • Se eliminan los llamados de vi por jest
  • Se renombran las funciones importActual por requireActual. (Necesita manualmente quitarse el await y en async de estos mocks)

FAQ

Hice la migración pero los test me muestran vitest
  1. Eliminar la carpeta node_modules y el archivo pnpm-lock.yml
  2. Instalar las dependencias nuevamente con pnpm i
  3. Ejecutar los test nuevamente con pnpm test
Hice la migración pero tengo errores con los svg
  1. Agregar la dependencia de pnpm add @rsbuild/plugin-svgr
  2. Agregar el plugin a la config de rsbuild
        import { defaultConfig } from "@architecture-it/rsbuild";
        import { pluginSvgr } from "@rsbuild/plugin-svgr";
        export default defaultConfig({
        plugins: [pluginSvgr()],
        });
    
  3. Ejemplo de implementación en un componente
        import AndreaniLongTruck from "@/assets/svg/andreani_long_truck.svg";
        <>
            <Chip
                  label={<AndreaniLongTruck height="100%" width="100%" />}
                  sx={{
                    color: "#5B5B5B",
                    backgroundColor: "#EEEEEE",
                    fontSize: 16,
                  }}
                />
        <>