Go + Inertia.js v3
Páginas de React directamente desde handlers de Go, sin una API de por medio.
tug es un framework web para aplicaciones en Go cuyo frontend es Inertia.js. Los handlers renderizan páginas de React, Vue o Svelte con props tipadas, y toda la aplicación se distribuye como un único binario.
$ go install github.com/cuonggt/tug/cmd/tug@latest
$ tug new blog # -auth for accounts
$ cd blog
$ tug dev
tug │ serving http://localhost:8080, built in 268ms
^C
$ tug build
tug build: blog, 9.6 MB, frontend included
Cómo encaja todo
Las props de una página, y sus tipos, son un struct de Go.
Un handler renderiza una página con un struct, que el componente de la página recibe como props. tug gen escribe el TypeScript del struct, así que el componente se comprueba frente al código Go, y tug dev lo vuelve a escribir cuando ese código cambia.
type PostsIndexProps struct {
Posts []Post `json:"posts"`
Stats inertia.DeferProp[Stats] `json:"stats"`
}
var PostsIndex = tug.Page[PostsIndexProps]("Posts/Index")
func index(c *tug.Ctx) error {
return PostsIndex.Render(c, PostsIndexProps{
Posts: store.List(),
Stats: inertia.Defer(store.Count), // after the page shows
})
}// Code generated by tug gen from the Go types. DO NOT EDIT.
export interface PostsIndexProps {
posts: Post[]
stats?: Stats
}import { Deferred, Link } from '@inertiajs/react'
import type { PageProps } from '../../tug/pages'
import { route } from '../../tug/routes'
type Props = PageProps<'Posts/Index'>
export default function Index({ posts, stats }: Props) {
return (
<>
<Deferred data="stats" fallback={<p>Counting…</p>}>
{stats && <p>{stats.posts} posts</p>}
</Deferred>
{posts.map((post) => (
<Link
key={post.id}
href={route('posts.show', { id: post.id })}
>
{post.title}
</Link>
))}
</>
)
}Qué incluye
Las piezas que necesita una aplicación, que ya funcionan con Inertia.
Las sesiones, los mensajes flash, los errores de validación y la protección CSRF funcionan con Inertia sin configurar nada, con la biblioteca estándar por debajo.
Inertia v3, completo
Props diferidas, fusionadas, opcionales y que se envían una sola vez, recargas parciales de props anidadas, scroll infinito, y el título y la descripción de una página desde Go.
Tipos desde Go
tug genescribe el TypeScript de las props de cada página, las rutas con nombre, lo que envía cada formulario y las claves de los datos flash.Formularios que se validan solos
c.BindValidllena un struct con una petición y la comprueba según las etiquetas del struct. Un formulario que no es válido vuelve con sus errores, y cada campo se comprueba al salir de él.Cuentas, con una sola opción
tug new -auth: registro, correo verificado, autenticación de dos factores, llaves de acceso, tokens de API y notificaciones, en SQLite, Postgres o MySQL.Tareas en segundo plano
Tareas que se vuelven a ejecutar si fallan, programadas en cualquier zona horaria, una sola vez por muchas veces que se encolen, y en la propia transacción de la aplicación.
Un solo binario
tug buildcrea un único binario estático con el frontend dentro, que la propia aplicación envía comprimido con gzip, y la aplicación viene con un Dockerfile.Renderizado en el servidor, si quieres
tug new -ssrrenderiza la página de una primera visita con el propio SSR de Inertia, en Node junto a la aplicación. Sin Node, las páginas se renderizan en el navegador.Pruebas sin navegador
El paquete
tugtestes el cliente de Inertia para las pruebas en Go: visitas, formularios, subidas de archivos e inicios de sesión, con las props de una página leídas en su struct de Go.Eventos en todas las instancias
El paquete
broadcastlleva eventos por canales, a través de la base de datos de la aplicación, a las páginas abiertas en todas las instancias, que recargan lo que cambió.
Por qué Go
Un binario pequeño que usa todos los núcleos y arranca en milisegundos.
Go convierte una aplicación web en un único binario estático, que usa todos los núcleos en un solo proceso, arranca en milisegundos y funciona con decenas de MB de memoria. tug conserva todo eso para una aplicación de Inertia: un único binario estático, con la compilación del frontend dentro, servido por el propio servidor HTTP de Go.
Rendimiento
Decenas de miles de peticiones por segundo en un equipo portátil, en un proceso que usa todos los núcleos, con decenas de MB de RAM.
Arranque
En milisegundos, lo que mantiene bajo el gasto en una plataforma que escala a cero.
Despliegue
Un archivo que copiar, sin entorno de ejecución ni dependencias que instalar, compilado para Linux o ARM desde macOS.
Desarrollo
Un lenguaje pequeño que compila rápido, con un servidor HTTP en su biblioteca estándar lo bastante bueno para producción.
Velocidad
60.061 visitas por segundo, con 19,9 MB de memoria.
Una página de Inertia, una entrada y sus comentarios, servida por una aplicación como la que crea tug new, con su sesión, CSRF y Content-Security-Policy, en un proceso que usa todos los núcleos.
-
60.061 visitas por segundo
El cliente de Inertia pide la página y la recibe en JSON, 99 de cada 100 veces en 4,38 ms o menos.
-
56.146 primeras visitas por segundo
Un navegador pide la página y recibe su HTML, 99 de cada 100 veces en 5,09 ms o menos.
-
19,9 MB de memoria bajo carga
6,4 MB tras arrancar, en reposo.
-
15 ms para arrancar
Desde que arranca el binario hasta que responde por primera vez con la página.
-
9,6 MB para desplegar
Un único binario estático, sin nada más que instalar.
-
75 ns añadidos a una petición
Lo que la App de tug añade a ServeMux, el router propio de Go, en un solo proceso.
Medido el en Apple M1 Max, 10 núcleos, macOS 27.0.1. Todas las cifras, y cómo se midieron
La guía
De una aplicación nueva a una desplegada.
18 partes, en el orden en que las necesita una aplicación. La documentación de cada paquete, en pkg.go.dev, tiene el resto de los detalles.
- Primeros pasos
instalar tug, crear una aplicación, ejecutarla y añadirle una página y un formulario.
- Rutas y handlers
la App, las rutas, los enlaces absolutos y firmados, los grupos, los middleware, entre ellos los de las cabeceras de seguridad, la ruta que respondió, la dirección del cliente detrás de un proxy,
Ctx, archivos, descargas, streams y eventos, el binding de peticiones y los errores. - Páginas
las páginas de Inertia y sus props, la plantilla raíz y su nonce, las props que se calculan más tarde, las props compartidas, las redirecciones, las descargas y los eventos en una página, las páginas de error, Vite y las DevTools de Inertia.
- Renderizado en el servidor
páginas renderizadas en el servidor para una primera visita, por Node junto a la aplicación, y el paquete
ssr. - Formularios y sesiones
la validación, reglas propias de la aplicación, formularios que comprueban cada campo al salir de él, los mensajes flash, las sesiones y CSRF.
- Idiomas
lo que dicen tug y la aplicación, en el idioma de la petición, a partir de un archivo por idioma, el paquete
langytug lang. - Archivos
los archivos subidos, comprobados por su tamaño y por lo que son, guardados en el disco de la aplicación o en S3 con el paquete
storage, y los enlaces a ellos, públicos o firmados. - Cuentas
el kit de inicio de autenticación, en SQLite, Postgres o MySQL, sus tokens de API y notificaciones, y los paquetes
authymail, con copias, archivos adjuntos y un enlace para darse de baja con un clic. - Migraciones
las tablas de la base de datos, creadas y modificadas por archivos SQL que se ejecutan una vez cada uno, en orden, al arrancar la aplicación y con su comando
migrate, contug migrate newpara crear el siguiente, y el paquetemigrate. - Autorización
lo que un usuario puede hacer con algo, las habilidades del paquete
auth, una negativa en forma de 403 que dice por qué, y lo que puede hacer el usuario de una página, en sus props. - Cifrado
la clave de la aplicación, lo que tug cifra y firma con ella, el paquete
crypt, para los valores propios de la aplicación, y la rotación de la clave. - Tareas en segundo plano
el paquete
queue, para el trabajo que dura más que la petición: se vuelve a ejecutar cuando falla, se ejecuta según un horario, también en una zona horaria, queda en cola una sola vez por muchas veces que se pida, o como mucho tantas a la vez o por segundo, en todas las instancias, y avisa cuando ha fallado definitivamente, y cuenta cómo ha ido cada ejecución. - Caché
el paquete
cache, para lo que es lento de calcular, guardado donde lo encuentran todas las instancias de la aplicación, y bloqueos para lo que no debe ejecutarse dos veces a la vez. - Difusión de eventos
el paquete
broadcast, eventos en canales llevados por la base de datos de la aplicación hasta las páginas abiertas en todas las instancias, que recargan lo que cambió. - TypeScript
los tipos que
tug genescribe a partir del código Go. - Pruebas
el paquete
tugtest, el cliente de Inertia para las pruebas en Go de las páginas, los formularios, las subidas de archivos y los inicios de sesión de una aplicación,mailtest, para su correo, y sus eventos. - Despliegue
un único binario, el Dockerfile, el entorno, HTTPS servido por la propia aplicación, con certificados de Let's Encrypt, las cabeceras que dicen qué puede hacer un navegador con las páginas de la aplicación, entre ellas una Content-Security-Policy, los logs y las métricas.
- La CLI
tug new,tug dev,tug gen,tug routes,tug lang,tug migrate,tug buildytug key, en detalle.