Init Inicializar App
Inicializa tu aplicación Blue Bird.
npx blue-bird
Una estructura potente basada en Express y React, diseñada para construir aplicaciones rápidas y todo lo que necesitas pre-configurado.
npm install @seip/blue-bird
¿Cansado de configurar CORS, Cookies, etc y el Routing cada vez que empiezas un proyecto? Blue Bird proporciona una base sólida y pre-configurada para que vayas directo a la lógica de negocio, sin perder la extensibilidad pura de Express.
Express, React (con Vite), Tailwind CSS, JWT Auth y más. Todo listo para usar.
SSR Híbrido para SEO, caché en memoria y bundle optimizado para una carga instantánea.
Respuesta en microsegundos. Las plantillas renderizadas se guardan en la memoria RAM del servidor.
Protección XSS automática en cada validación y manejo de errores profesional que nunca expone tu código.
Compresión nativa activada. Tus assets y JSON viajan a la máxima velocidad posible por la red.
Inicializa tu aplicación Blue Bird.
npx blue-bird
Configura React para tu aplicación Blue Bird.
npm run react
Editar package.json para soporte "module" y "type": "module"
{
"type": "module",....
}
Inicia el servidor backend:
npm run dev
Inicia el servidor frontend (Vite):
npm run vite:dev
Configura las variables de entorno para tu aplicación.
# URL Pública (SEO, Sitemap, Swagger)
APP_URL="https://blue-bird.com"
# Configuración del Servidor
HOST="localhost"
PORT=3000
# Metadatos Globales (Fallback)
TITLE_META="Blue Bird"
DESCRIPTION_META="Mi increíble proyecto"
| Variable | Descripción |
|---|---|
| APP_URL | La URL pública de tu sitio. Es crucial para generar sitemaps correctos y etiquetas SEO absolutas. |
| HOST | Interfaz donde escucha el servidor (usar 'localhost' para Nginx o '0.0.0.0' para acceso directo). |
| PORT | Puerto interno de la aplicación. |
Configuración central de tu servidor Express.
import App from "@seip/blue-bird/core/app.js";
import routerUsers from "./routes/users.js";
const app = new App({
port: 3000,
routes: [routerUsers],
cors:{},
rateLimit:{
windowMs: 10 * 60 * 1000,
max: 300
}
});
app.use(myCustomMiddleware);
app.run();
| Opción | Tipo | Default |
|---|---|---|
| routes | Array | [] |
| middlewares | Array | [] |
| port | Number | 3000 |
| host | String | "http://localhost" |
| cors | Object | {} |
| static | Object | { path: null, options: {} } |
| rateLimit | Boolean | Object | false |
| logger | Boolean | false |
| notFound | Boolean | true |
| json | Boolean | true |
| urlencoded | Boolean | true |
| cookieParser | Boolean | true |
| swagger | Boolean | Object | false |
Gestiona tus rutas de forma modular y limpia.
import Router from "@seip/blue-bird/core/router.js";
import Template from "@seip/blue-bird/core/template.js";
const routerUsers = new Router("/")
routerUsers.get("/users", (req, res) => {
const users = [
{
name: "John Doe",
email: "john.doe@example.com",
},
{
name: "Jane Doe2",
email: "jane.doe2@example.com",
},
]
res.json(users)
})
routerUsers.get("*", (req, res) => {
// Renderizado SPA con React
return Template.renderReact(res, "App", { title: "Mi Proyecto" });
})
export default routerUsers;
Renderiza componentes React con SEO automatizado y soporte multi-idioma.
El método router.seo() permite registrar
múltiples
rutas con sus metadatos y props en una sola llamada.
import Router from "@seip/blue-bird/core/router.js";
import seoData from "./seo.js"; // Archivo externo de datos SEO
const frontendRouter = new Router();
// Opción A: Meta simple (sin i18n)
frontendRouter.seo([
{ path: "/", component: "Home", meta: { titleMeta: "Home", descriptionMeta: "Bienvenido" }, props: { id: 1 } }
]);
// Opción B: Multilenguaje con archivo externo seoData (recomendado)
frontendRouter.seo([
{ path: "/", component: "Home", seoKey: "home", props: { id: 1 } },
{ path: "/about", component: "About", seoKey: "about", props: { id: 2 } }
], { languages: ["en", "es"], defaultLanguage: "en", seoData });
// Genera: /, /en, /es, /about, /en/about, /es/about
// Opción C: Multilenguaje inline
frontendRouter.seo([
{
path: "/",
component: "Home",
meta: {
en: { titleMeta: "Home", descriptionMeta: "Welcome" },
es: { titleMeta: "Inicio", descriptionMeta: "Bienvenido" }
}
}
], { languages: ["en", "es"], defaultLanguage: "en" });
Similar al patrón seo.php, centraliza los meta
tags multilenguaje:
// backend/routes/seo.js
export default {
home: {
en: { titleMeta: "Home - Blue Bird", descriptionMeta: "Welcome", keywordsMeta: "home" },
es: { titleMeta: "Inicio - Blue Bird", descriptionMeta: "Bienvenido", keywordsMeta: "inicio" }
},
about: {
en: { titleMeta: "About", descriptionMeta: "About us" },
es: { titleMeta: "Acerca", descriptionMeta: "Acerca de nosotros" }
}
};
Este método es ideal para el SEO porque los bots e IAs detectan el renderizado inicial desde el servidor con los meta tags correctos (title, description, keywords) antes de que el JavaScript de React tome el control.
El framework ahora soporta etiquetas para redes sociales y generación automática de archivos esenciales para buscadores.
// Navegación SPA: cuando ?source=frontend se detecta, renderReact
// devuelve JSON {meta, props, component, lang} en vez de HTML.
fetch('/about?source=frontend')
.then(r => r.json())
.then(data => {
// data = { meta: {titleMeta, descriptionMeta, ...}, props: {...}, component: "About", lang: "en" }
});
Al usar router.seo(), se registran automáticamente las rutas
/sitemap.xml y /robots.txt, vinculadas al host
configurado en core/config.js.
Recuerda eliminar los archivos,si tienes sitemap.xml o robots.txt en
frontend/public , para que este cambio se aplique
Inyección automática de tags og:title, og:image y
twitter:card para que tus enlaces luzcan perfectos al compartirse
en redes sociales.
Ideal para Landing Pages, Términos y Condiciones o Políticas de Privacidad que requieren una carga instantánea sin el peso de React.
router.get("/", (req, res) => {
// Carga frontend/landing.html, aplica SEO de .env y lo guarda en caché RAM
return Template.renderHtml(res, "landing", {
withAssets: false, // Zero JavaScript para máxima velocidad
metaTags: { titleMeta: "Oferta Exclusiva" }
});
});
Puedes registrar la misma ruta en Express y en React Router Dom para crear una experiencia híbrida:
Si necesitas más control, puedes usar
Template.renderReact directamente. Maneja automáticamente el atributo
<html lang="..."> si se provee langMeta.
import Template from "@seip/blue-bird/core/template.js";
router.get("/custom", (req, res) => {
return Template.renderReact(res, "Custom", { some: "prop" }, {
metaTags: {
titleMeta: "Página Custom",
descriptionMeta: "Descripción custom",
langMeta: "es" // Setea automáticamente
},
skeleton: true // Habilita el skeleton loading automáticamente
});
});
Valida datos de entrada con prevención automática de XSS.
Soporta es,en,pt,br,fr (Español,Ingles,Portugues,Brasil-Portugues,Frances)import Validator from "@seip/blue-bird/core/validate.js";
const schema = {
// La sanitización XSS se aplica por defecto a todos los campos string.
email: { required: true, email: true },
password: { required: true, min: 6 },
// Puedes desactivarla explícitamente para permitir contenido HTML/React
html_content: { required: true, xss: false }
};
const validate = new Validator(schema, 'es');
// El segundo parámetro permite devolver errores localizados según el idioma del cliente.
router.post("/register", validate.middleware(), (req, res) => {
res.json({ message: "OK" });
});
El validador detecta automáticamente el idioma para los
mensajes de error en este orden: Body, Query String, Cookies o el Header
Accept-Language.
Opción A: Usando Headers (Recomendado)
fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept-Language': 'es' // El validador devolverá errores en español
},
body: JSON.stringify(data)
});
Opción B: URL Query Params
// Útil para pruebas rápidas o links directos
fetch('/api/register?lang=esp', {
method: 'POST',
body: JSON.stringify(data)
});
Opción C: En el Body JSON
fetch('/api/register', {
method: 'POST',
body: JSON.stringify({
...data,
lang: 'pt' // Prioridad máxima sobre el resto
})
});
Lila integra soporte nativo para múltiples idiomas en el frontend mediante un Context
Provider, usando la clave blue_bird_lang en el localStorage
para
mantener la preferencia del usuario.
Nota: Por defecto, Blue Bird ya incluye LanguageProvider
en
App.jsx para gestionar aplicaciones multiidioma de forma nativa. Si deseas
removerlo, simplemente edita App.jsx y elimina el wrapping del provider.
import { LanguageProvider } from './blue-bird/contexts/LanguageContext.jsx';
export default function App() {
return (
<LanguageProvider>
<Router>
{/* Tus rutas */}
</Router>
</LanguageProvider>
);
}
Luego, dentro de cualquier componente o página puedes utilizar el hook
useLanguage():
import { useLanguage } from '../../blue-bird/contexts/LanguageContext.jsx';
export default function Login() {
const { t, lang, setLang } = useLanguage();
return (
<div>
{/* Las traducciones están en frontend/resources/js/blue-bird/locales/[lang].json */}
<p className="error">{t('error_general')}</p>
</div>
);
}
Para acelerar el desarrollo, incluimos componentes React elegantes y listos para usar.
Están
estilizados con Tailwind CSS (el cual ahora se integra nativamente vía Vite en
vite.config.js,
asegurando un rendimiento óptimo). Destacan:
Helmet no se aplica globalmente por defecto. Aplícalo por router donde
sea necesario usando App.helmet().
import App from "@seip/blue-bird/core/app.js";
import Router from "@seip/blue-bird/core/router.js";
// Aplicar helmet a un router específico
const webRouter = new Router("/web");
webRouter.use(App.helmet()); // Helmet con defaults
webRouter.use(App.helmet({ contentSecurityPolicy: false })); // Opciones custom
// O habilitar globalmente en el constructor de App (no recomendado)
new App({ helmet: true });
// Helmet con CSP personalizado
new App({
helmet: {
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "'unsafe-inline'"],
"style-src": ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
}
}
}
});
Aplicar Helmet globalmente puede bloquear scripts inline, CDNs o estilos en rutas que no lo necesitan (APIs, landing pages estáticas). Aplicándolo por router tienes control granular sobre qué rutas tienen protección CSP.
El framework incluye un SPAProvider que conecta la navegación de React
Router con los datos SEO del backend.
En cada navegación por <Link>, hace un fetch al backend y actualiza
document.title + meta tags automáticamente.
import { SPAProvider } from './blue-bird/contexts/SPAContext.jsx';
// Envolver las rutas con SPAProvider
<SPAProvider languages={["en", "es"]} defaultLanguage="en">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* Las rutas con prefijo de idioma se generan automáticamente */}
<Route path="/en" element={<Home />} />
<Route path="/es" element={<Home />} />
<Route path="/en/about" element={<About />} />
<Route path="/es/about" element={<About />} />
</Routes>
</SPAProvider>
El framework provee componentes que encapsulan la lógica de localización para una sintaxis más limpia.
Reemplaza el Link de
react-router-dom para persistir el idioma automáticamente.
import Link from "../blue-bird/components/Link";
// El componente añade el prefijo /es/ o /en/ automáticamente según la sesión
<Link to="/about">Sobre nosotros</Link>
Encapsula la lógica de navigateToLang.
import LanguageButton from "../blue-bird/components/LanguageButton";
<LanguageButton lang="es" variant="outline">Español</LanguageButton>
<LanguageButton lang="en" variant="outline">English</LanguageButton>
Si tu aplicación solo usa un idioma, simplemente deja el array LANGUAGES
vacío en App.jsx. El framework desactivará automáticamente toda la lógica
de prefijos.
// App.jsx
const LANGUAGES = []; // Aplicación monolingüe
const DEFAULT_LANGUAGE = "es";
<Link>, SPAProvider hace
fetch(path?source=frontend).
{meta, props, component, lang} en vez de HTML.
Cada Router soporta el método use() para aplicar middlewares a
todas las rutas de ese router.
Esto es ideal para proteger grupos de rutas sin repetir el middleware en cada una.
import Router from "@seip/blue-bird/core/router.js";
import App from "@seip/blue-bird/core/app.js";
const routerFrontend = new Router();
routerFrontend.use(App.helmet()); // Helmet solo para este router
// Todas las rutas de este router están protegidas por Helmet
routerFrontend.get("/", (req, res) => { ... });
routerFrontend.get("/about", (req, res) => { ... });
Perfecto para crear routers de admin, dashboard o rutas autenticadas. El middleware se aplica una sola vez y protege todas las rutas del router.
import Router from "@seip/blue-bird/core/router.js";
import Middleware from "@seip/blue-bird/core/middleware.js";
import Auth from "@seip/blue-bird/core/auth.js";
// Opción 1: Usando Middleware pre-configurado
const routerAdmin = new Router("/admin");
routerAdmin.use(Middleware.auth); // Todas las rutas requieren JWT
routerAdmin.get("/dashboard", (req, res) => {
res.json({ user: req.user }); // req.user disponible en todas
});
routerAdmin.get("/settings", (req, res) => {
res.json({ settings: {} });
});
// Opción 2: Usando Auth.protect() con redirect
const routerDashboard = new Router("/dashboard");
routerDashboard.use(Auth.protect({ redirect: "/login" }));
routerDashboard.get("/", (req, res) => {
return Template.renderReact(res, "Dashboard");
});
const routerApi = new Router("/api");
// Middleware personalizado de logging
routerApi.use((req, res, next) => {
console.log(`[API] ${req.method} ${req.url}`);
next();
});
// Múltiples middlewares
routerApi.use(Middleware.auth);
routerApi.use(App.helmet());
routerApi.get("/users", (req, res) => { ... });
Usa router.use() para agrupar rutas con la misma protección.
Crea un router por grupo de permisos: routerPublic,
routerAuth, routerAdmin.
Registra todos en
App({ routes: [routerPublic, routerAuth, routerAdmin, routerFrontend] }).
Protege rutas API y React con autenticación JWT. Los tokens se leen de Cookies o del
header Authorization.
import Auth from "@seip/blue-bird/core/auth.js";
// Proteger ruta API (retorna 401 si falla):
router.get("/profile", Auth.protect(), (req, res) => {
res.json({ user: req.user });
});
// Proteger ruta React (redirige a login):
router.get("/dashboard", Auth.protect({ redirect: "/login" }), (req, res) => {
return Template.renderReact(res, "Dashboard");
});
// Generar token:
const token = Auth.generateToken({ id: user.id, email: user.email });
// Verificar token:
const decoded = Auth.verifyToken(token);
import Middleware from "@seip/blue-bird/core/middleware.js";
// Middleware auth pre-configurado
router.get("/api/profile", Middleware.auth, controller.profile);
// Middleware web auth (redirige a / si falla)
router.get("/dashboard", Middleware.webAuth, (req, res) => {
return Template.renderReact(res, "Dashboard");
});
Middleware simple de cache en memoria para respuestas JSON. Permite mejorar el rendimiento evitando ejecutar el controlador repetidamente durante un período definido.
import Cache from "@seip/blue-bird/core/cache.js";
import Router from "@seip/blue-bird/core/router.js"
const routerStats = new Router("/")
routerStats("/stats",
Cache.middleware(120), // 120 segundos
controller.stats
);
//Testing
routerStats("/stats_",
Cache.middleware(120),
async (req, res) => {
await new Promise(resolve => setTimeout(resolve, 2000));
res.json({
message: 'Login successful',
note: 'Esta respuesta tardó 2 segundos en llegar.'
});
}
);
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
| seconds | Number | 60 | Tiempo en segundos que la respuesta permanece en cache. |
req.originalUrl como clave de cache.res.json() para almacenar la respuesta.Integración de documentación automática utilizando Swagger (OpenAPI 3). Permite visualizar y probar endpoints directamente desde el navegador.
Primero instala swagger con npm o cli blue-bird :
npm run swagger-install
const app = new App({
routes: [routerUsers],
cors: {},
middlewares: [],
port: 3000,
host: "http://localhost",
swagger:{
info: {
title: "Blue Bird API",
version: "1.0.0",
description: "Blue Bird Framework API Documentation"
},
url : "http://localhost:8000"
}
})
/**
* @swagger
* /users:
* get:
* summary: Get all users
* tags: [Users]
* responses:
* 200:
* description: List of users
*/
router.get("/users", controller.getUsers);
/**
* @swagger
* components:
* schemas:
* User:
* type: object
* properties:
* name:
* type: string
* email:
* type: string
*/
/docs.components.securitySchemes.
@swagger deben estar correctamente indentados./docs.El módulo Debug permite monitorear el rendimiento de tu aplicación en tiempo real. Registra métricas como tiempo de respuesta, uso de memoria RAM, consumo de CPU y estadísticas por ruta. Cuando en .env es Debug=true queda activada la ruta.
Luego accede al panel visual en:
http://localhost:3000/debug
fetch/debug?fetch=true/debugGET /debug?fetch=true
Devuelve las métricas en formato JSON:
{
"requests": [
{
"method": "GET",
"url": "/users",
"status": 200,
"responseTime": 32.14,
"ramUsedMB": 45.21,
"cpuUsedMS": 1.23,
"date": "2026-02-27T12:00:00.000Z"
}
],
"routes": {
"GET /users": {
"count": 5,
"totalTime": 160.5
}
}
}
Blue Bird está diseñado para producción. Con características como caching, compresión gzip, y manejo de errores robusto, puedes estar seguro de que tu aplicación funcionará correctamente.
Para producción, se recomienda usar un servidor proxy como Nginx para manejar el SSL, la compresión gzip, y el balanceo de carga.
Primero edita .env , poniendo DEBUG=false
DEBUG=false
Luego ejecuta el comando para generar la build de react con vite:
npm run vite:build
Para ejecutar en producción se utiliza "npm run start" , por lo que con PM2 haremos:
pm2 start npm --name "blue-bird" -- run start
Esto iniciará la aplicación en producción y la mantendrá viva
.
pm2 save
Esto guardará la configuración de PM2 para que se inicie
automáticamente al reiniciar el servidor.