Skip to content

devlusoft/devix

Repository files navigation

devix

Un meta-framework ligero de React 19 con SSR, impulsado por Vite 8 + Hono.

Construye aplicaciones React full-stack con enrutamiento basado en archivos, renderizado del lado del servidor, generación estática de sitios y rutas API — configuración mínima, control máximo.

Características

  • Vite 8 — HMR instantáneo y builds rápidos con Rolldown
  • React 19 — SSR con renderToString e hydrateRoot
  • Enrutamiento basado en archivos — páginas, layouts anidados y rutas API desde el sistema de archivos
  • SSR por defecto — cada página se renderiza en el servidor
  • SSG — genera HTML estático con generateStaticParams
  • Rutas API — basadas en archivos, con createHandler para tipado de extremo a extremo
  • $fetch — cliente HTTP con body y respuesta tipados, con autocompletado de rutas
  • Carga de datos — funciones loader con hidratación automática en el cliente
  • Navegación programáticauseNavigate() con soporte de replace y View Transitions API
  • Revalidación de datosuseRevalidate() para refrescar datos sin recargar la página
  • Guards de ruta — redirecciones del lado del servidor antes del renderizado
  • SEOmetadata y generateMetadata por página, con soporte de Open Graph y Twitter
  • Hooks de contextouseRequest(), useCtx(), useParams() accesibles desde cualquier función del handler
  • TypeScript primero — inferencia de tipos completa en todo el framework

Instalación

npm install @devlusoft/devix react react-dom

Requiere React 19+, Vite 8+, Node 20+.

Inicio rápido

npx devix dev

1. Crea devix.config.ts:

import { defineConfig } from '@devlusoft/devix/config'

export default defineConfig({
  port: 3000,
})

2. Crea tu primera página en app/pages/index.tsx:

export default function Home() {
  return <h1>¡Hola devix!</h1>
}

3. Ejecuta el servidor de desarrollo:

npx devix dev

Convenciones de archivos

app/
├── pages/
│   ├── layout.tsx          # Layout raíz (envuelve todas las páginas)
│   ├── index.tsx           # → /
│   ├── about.tsx           # → /about
│   └── blog/
│       ├── layout.tsx      # Layout anidado (envuelve páginas de blog)
│       ├── index.tsx       # → /blog
│       └── [slug].tsx      # → /blog/:slug
└── api/
    ├── middleware.ts        # Middleware global de la API
    └── posts/
        └── [id].ts         # → GET/POST /api/posts/:id

Conceptos principales

Loader y datos

import { useLoaderData } from '@devlusoft/devix'
import type { PageProps, LoaderContext } from '@devlusoft/devix'

export async function loader({ params, request }: LoaderContext) {
  const post = await db.posts.findBySlug(params.slug)
  return post
}

export default function BlogPost({ data, params }: PageProps<typeof loader>) {
  return <article>{data.title}</article>
}

Guard de ruta

export async function guard({ request }: LoaderContext) {
  const user = await getSession(request)
  if (!user) return '/login'
  return null
}

Metadata

export const metadata = {
  title: 'Inicio',
  description: 'Bienvenido a mi sitio',
  og: { image: '/og.png', type: 'website' },
  twitter: { card: 'summary_large_image' },
}

// o dinámica:
export async function generateMetadata({ loaderData }) {
  return { title: loaderData.title }
}

Layouts

import type { LayoutProps } from '@devlusoft/devix'

export default function RootLayout({ children }: LayoutProps) {
  return (
    <div>
      <nav>...</nav>
      {children}
    </div>
  )
}

Tipado de params

Pasa el tipo de params directamente sin necesidad de un loader:

import type { PageProps } from '@devlusoft/devix'

export default function ProviderPage({ params }: PageProps<{ providerId: string }>) {
  return <h1>{params.providerId}</h1>
}

Navegación programática

import { useNavigate, useRevalidate } from '@devlusoft/devix'

function MyComponent() {
  const navigate = useNavigate()
  const revalidate = useRevalidate()

  return (
    <>
      <button onClick={() => navigate('/dashboard')}>Ir al dashboard</button>
      <button onClick={() => navigate('/login', { replace: true })}>Login (sin historial)</button>
      <button onClick={() => navigate('/shop', { viewTransition: true })}>Con animación</button>
      <button onClick={() => revalidate()}>Refrescar datos</button>
    </>
  )
}

redirect con replace

import { redirect } from '@devlusoft/devix'

export async function loader({ request }: LoaderContext) {
  const user = await getSession(request)
  if (!user) return redirect('/login', { replace: true })
  return user
}

Rutas API

createHandler da tipado de extremo a extremo — el body y el retorno se infieren automáticamente para $fetch:

import { createHandler, json } from '@devlusoft/devix'

export const GET = createHandler(async () => {
  return json({ hello: 'world' })
})

export const POST = createHandler(async (body: { name: string }) => {
  const item = await db.items.create(body)
  return json(item, 201)
})

export const DELETE = createHandler(async () => null)  // 204
const res = await $fetch('/api/items', {
  method: 'POST',
  body: { name: 'nuevo item' },
})

Generación estática (SSG)

Configura output: 'static' y exporta generateStaticParams desde cualquier página dinámica:

// devix.config.ts
export default defineConfig({ output: 'static' })
// app/pages/blog/[slug].tsx
export async function generateStaticParams() {
  const posts = await db.posts.all()
  return posts.map(p => ({ slug: p.slug }))
}
npx devix generate   # compila y pre-renderiza todas las páginas en dist/client/
npx devix start      # sirve los archivos estáticos (sin SSR en runtime)

Comandos

Comando Descripción
devix dev Inicia el servidor de desarrollo con HMR
devix build Compila para producción
devix start Inicia el servidor de producción
devix generate Compila y pre-renderiza todas las páginas (SSG)

Configuración

// devix.config.ts
import { defineConfig } from '@devlusoft/devix/config'

export default defineConfig({
  port: 3000,                // puerto del servidor dev y producción (default: 3000)
  host: false,               // bind a 0.0.0.0 (default: false)
  appDir: 'app',             // directorio de la app (default: 'app')
  publicDir: 'public',       // directorio de archivos estáticos (default: 'public')
  output: 'server',          // 'server' | 'static' (default: 'server')
  loaderTimeout: 10_000,     // timeout de los loaders en ms (default: 10000)
  css: ['./app/styles/global.css'],  // archivos CSS globales
  envPrefix: 'PUBLIC_',      // expone variables de entorno con este prefijo al cliente
  vite: {},                  // extiende la configuración de Vite
})

Documentación

La documentación completa está en la carpeta docs/:

Licencia

MIT — devix es un proyecto de devlusoft.

About

A lightweight React SSR meta-framework - devix

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors