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
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 elrsbuild.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
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 prefijoVITE
- 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
asrc/bootstrap.tsx
y ensrc/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
porjest
- Se renombran las funciones
importActual
porrequireActual
. (Necesita manualmente quitarse el await y en async de estos mocks)
FAQ¶
Hice la migración pero los test me muestran vitest
- Eliminar la carpeta
node_modules
y el archivopnpm-lock.yml
- Instalar las dependencias nuevamente con
pnpm i
- Ejecutar los test nuevamente con
pnpm test
Hice la migración pero tengo errores con los svg
- Agregar la dependencia de
pnpm add @rsbuild/plugin-svgr
- 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()], });
- 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, }} /> <>
Hice la migración pero tengo errores con paquetes que no tengo instalados
Desde cierta version de nodejs y webpack ya no se agregan ciertos paquetes a los proyectos de frontend, por lo que debes instalar un plugin para poder hacer funcionar tu aplicación como costumbre.
Por lo general si usabas react-app-rewired se ve de esta manera o similar:
// ...codigo ignorado por brevedad
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
"assert": require.resolve("assert"),
"zlib": require.resolve("browserify-zlib"),
"process/browser": require.resolve("process/browser"),
"stream": require.resolve("stream-browserify"),
"util": require.resolve("util"),
"buffer": require.resolve("buffer"),
});
config.resolve.fallback = fallback;
config.plugins = (config.plugins || []).concat([
new webpack.ProvidePlugin({
process: "process/browser",
Buffer: ["buffer", "Buffer"]
})
]);
// ...codigo ignorado por brevedad
-
Agregar la dependencia de
pnpm add @rsbuild/plugin-node-polyfill
-
Agregar el plugin a la config de rsbuild
import { defaultConfig } from "@architecture-it/rsbuild"; import { pluginNodePolyfill } from "@rsbuild/plugin-node-polyfill"; export default defaultConfig({ plugins: [pluginNodePolyfill()], });
Tengo el siguiente error Module not found: Can't resolve 'mui/system'
En ciertos proyectos que usan las primeras versiones de material teniamos esta dependencia, lo ideal sería evitarla, pero si no podemos, se soluciona simplemente agregandola.
- Agregar la dependencia de
pnpm add @mui/system