Go + Inertia.js v3
由 Go 处理函数直接渲染 React 页面,中间无需 API。
tug 是一个 Web 框架,面向前端使用 Inertia.js 的 Go 应用。处理函数用带类型的 props 渲染 React、Vue 或 Svelte 页面,整个应用以单个二进制文件发布。
$ 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
如何衔接
一个 Go 结构体,既是页面的 props,也是它们的类型。
处理函数用一个结构体渲染页面,页面的组件把它作为 props 接收。tug gen 写出这个结构体的 TypeScript,让组件对照 Go 代码接受类型检查;Go 代码改动时,tug dev 会重新写出。
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>
))}
</>
)
}包含什么
应用所需的各个部分,都已与 Inertia 配合好。
会话、flash 消息、验证错误和 CSRF 无需配置即可与 Inertia 配合使用,底层基于标准库。
完整的 Inertia v3
延迟、合并、只加载一次和可选的 props,按路径的部分重载,无限滚动,以及由 Go 设置的页面标题和描述。
来自 Go 的类型
tug gen为每个页面的 props、命名路由、每个表单发送的内容以及 flash 数据的键写出 TypeScript。自动验证的表单
c.BindValid绑定请求,并按结构体标签检查它。未通过验证的表单会带着错误返回,每个字段在失去焦点时就会检查。账户系统,只需一个参数
tug new -auth:注册、邮箱验证、双因素验证码、通行密钥、API 令牌和通知,可用 SQLite、Postgres 或 MySQL。后台任务
任务失败后会重新运行,可以按任意时区的计划运行,无论推送多少次都只运行一次,还可以在应用自己的事务中推送。
单个二进制文件
tug build生成单个内含前端的静态二进制文件,前端由应用自己以 gzip 压缩发送;应用还附带一个 Dockerfile。也可以在服务端渲染
tug new -ssr在应用旁边的 Node 中,用 Inertia 自己的 SSR 渲染首次访问的页面。没有 Node 时,页面在浏览器中渲染。无需浏览器的测试
tugtest包是供 Go 测试使用的 Inertia 客户端:访问、表单、上传和登录,并把页面的 props 读入对应的 Go 结构体。跨实例的事件
broadcast包经由应用的数据库,把频道上的事件送到每个实例上打开的页面,页面随即重新加载变化的部分。
为什么选择 Go
一个小巧的二进制文件,用上所有核心,几毫秒即可启动。
Go 能把 Web 应用做成单个静态二进制文件:一个进程就能用上所有核心,几毫秒内启动,运行只需几十 MB 内存。tug 为 Inertia 应用保留了这一切:单个静态二进制文件,前端的构建产物就在其中,由 Go 自己的 HTTP 服务器提供服务。
性能
在笔记本电脑上每秒处理数万个请求,一个进程就能用上所有核心,只占几十 MB 内存。
启动
只需几毫秒,在可以缩容到零的平台上能压低成本。
部署
只需复制一个文件,无需安装运行时或依赖,在 Mac 上就能为 Linux 或 ARM 构建。
开发
一门小巧、编译快速的语言,标准库中的 HTTP 服务器就足以用于生产环境。
有多快
每秒 60,061 次访问,内存占用 19.9 MB。
一个 Inertia 页面(一篇文章及其评论),由一个如同 tug new 所生成的应用提供,带有会话、CSRF 和 Content-Security-Policy,运行在一个用上所有核心的进程中。
-
60,061 每秒访问次数
Inertia 客户端请求页面,以 JSON 响应,99% 的请求在 4.38 ms 内完成。
-
56,146 每秒首次访问次数
浏览器请求页面,以 HTML 响应,99% 的请求在 5.09 ms 内完成。
-
19.9 MB 负载下的内存占用
启动后空闲时为 6.4 MB。
-
15 ms 启动耗时
从启动二进制文件,到它第一次响应页面请求。
-
9.6 MB 部署体积
单个静态二进制文件,无需另外安装任何东西。
-
75 ns 每个请求增加的耗时
在单个进程中,tug 的 App 相比 Go 自带的路由器 ServeMux 多出的耗时。
于 测得,测试机器为 Apple M1 Max(10 核,macOS 27.0.1)。 全部数据,以及它们的测量方法
- 快速上手
安装 tug,创建并运行应用,再添加一个页面和一个表单。
- 路由与处理函数
App、路由、绝对链接与签名链接、路由组、中间件(其中包括安全响应头)、响应了请求的路由、代理之后的客户端地址、
Ctx、文件、下载、流与事件、请求绑定,以及错误。 - 页面
Inertia 页面及其 props、根模板及其 nonce、延后计算的 props、共享 props、重定向、页面上的下载与事件、错误页面、Vite,以及 Inertia 的 DevTools。
- 服务端渲染
首次访问时,由应用旁边的 Node 在服务端渲染页面,以及
ssr包。 - 表单与会话
验证、应用自己的规则、离开字段时就检查该字段的表单、flash 消息、会话,以及 CSRF。
- 多语言
用请求的语言显示 tug 和应用的文字,每种语言一个文件;
lang包,以及tug lang。 - 文件
上传的文件,按大小和实际类型检查,用
storage包保存在应用的磁盘或 S3 上,以及指向它们的公开链接或签名链接。 - 账户
认证脚手架,可用 SQLite、Postgres 或 MySQL,及其 API 令牌和通知;
auth和mail包,后者支持抄送、附件和一键退订链接。 - 数据库迁移
数据库的表由 SQL 文件创建和修改,每个文件只运行一次,在应用启动时按顺序运行,也可以通过应用的
migrate命令运行;用tug migrate new创建下一个迁移;以及migrate包。 - 授权
用户可以对某个对象做什么,
auth包的权限(ability),拒绝时返回说明原因的 403,以及在页面的 props 中给出当前用户可以做什么。 - 加密
应用的密钥,tug 用它加密和签名的内容,用来加密应用自身数据的
crypt包,以及密钥轮换。 - 后台任务
queue包,用于比请求持续更久的工作:失败时重新运行;按计划运行,也可以按指定的时区;无论被请求多少次,都只排队一次;或者在所有实例上合计,限制同时运行多少个、每秒运行多少个;并告知任务何时彻底失败,以及每次运行的情况。 - 缓存
cache包,用于计算起来很慢的结果,存放在应用的每个实例都能找到的地方;以及锁,用于不能同时运行两次的操作。 - 广播
broadcast包,频道上的事件,由应用的数据库送到每个实例上打开的页面,页面随即重新加载变化的部分。 - TypeScript
tug gen根据 Go 代码写出的类型。 - 测试
tugtest包,即供 Go 测试使用的 Inertia 客户端,用来测试应用的页面、表单、上传和登录;用来测试邮件的mailtest;以及应用的事件。 - 部署
单个二进制文件、Dockerfile、环境变量、由应用自身提供的 HTTPS 及来自 Let's Encrypt 的证书,规定浏览器可以如何对待应用页面的响应头(其中包括 Content-Security-Policy),日志,以及指标。
- 命令行工具
tug new、tug dev、tug gen、tug routes、tug lang、tug migrate、tug build和tug key的完整说明。