Vafast:一个让我放弃 Express 和 Hono 的 TypeScript Web 框架

Vafast:一个让我放弃 Express 和 Hono 的 TypeScript Web 框架

声明式路由 + 端到端类型安全 + 比 Express 快 1.8 倍,这就是我想要的 Node.js 框架

前言

作为一个写了多年 Node.js 后端的开发者,我用过 Express、Koa、Fastify、Hono、Elysia... 每个框架都有自己的优点,但也有让我难受的地方:

  • Express:生态丰富,但性能差、类型支持弱
  • Hono:轻量快速,但链式 API 一长就看不清有哪些路由
  • Elysia:性能强、类型好,但 Bun 限定,且链式调用让类型跨文件就丢失

直到我遇到了 Vafast,一个专为 TypeScript 设计的声明式 Web 框架。

为什么选择 Vafast?

1. 路由一眼看清,不用翻代码

先看看传统框架怎么写路由:

typescript 复制代码
// Hono / Express 风格
app.get('/users', getUsers)
app.post('/users', createUser)
app.get('/users/:id', getUser)
app.put('/users/:id', updateUser)
app.delete('/users/:id', deleteUser)
app.get('/posts', getPosts)
// ... 100 行后你还能找到某个路由吗?

再看 Vafast:

typescript 复制代码
// Vafast 风格
const routes = defineRoutes([
  { method: 'GET',    path: '/users',     handler: getUsers },
  { method: 'POST',   path: '/users',     handler: createUser },
  { method: 'GET',    path: '/users/:id', handler: getUser },
  { method: 'PUT',    path: '/users/:id', handler: updateUser },
  { method: 'DELETE', path: '/users/:id', handler: deleteUser },
  { method: 'GET',    path: '/posts',     handler: getPosts },
])

路由就是数组,所有 API 端点一目了然。 这在团队协作和代码 Review 时特别有用。

2. 类型安全,从请求到响应全程覆盖

Vafast 基于 TypeBox 实现 Schema 验证,定义一次,类型自动推断:

typescript 复制代码
import { createHandler, Type } from 'vafast'

const createUser = createHandler(
  { 
    body: Type.Object({ 
      name: Type.String(), 
      email: Type.String({ format: 'email' }),
      age: Type.Number({ minimum: 0 })
    }) 
  },
  ({ body }) => {
    // body.name 是 string ✅
    // body.email 是 string ✅
    // body.age 是 number ✅
    return { success: true, user: body }
  }
)

运行时验证 + 编译时类型推断,一举两得。

3. 前后端类型自动同步

这是我最喜欢的特性。服务端定义好路由,客户端自动获得完整类型提示:

typescript 复制代码
// 服务端
export const routes = defineRoutes([
  {
    method: 'POST',
    path: '/login',
    handler: createHandler(
      { body: Type.Object({ email: Type.String(), password: Type.String() }) },
      ({ body }) => ({ token: 'xxx', user: { id: '1', email: body.email } })
    )
  }
])
export type AppRoutes = typeof routes

// 客户端
import { eden, InferEden } from '@vafast/api-client'
import type { AppRoutes } from './server'

type Api = InferEden<AppRoutes>
const api = eden<Api>('http://localhost:3000')

// 完整类型提示 ✅
const { data } = await api.login.post({ 
  email: 'test@example.com',  // 必填,有提示
  password: '123456'          // 必填,有提示
})
console.log(data?.token)  // string 类型 ✅

不用写接口文档,不用手动同步类型,不用生成代码。

4. 性能:比 Express 快 1.8 倍

框架 RPS 相对性能
Elysia ~118K 100%
Vafast ~101K 86%
Hono ~56K 47%
Express ~56K 48%

测试环境:Bun 1.2.20, macOS, wrk (4线程, 100连接, 30s)

Vafast 通过以下优化实现高性能:

  • JIT 编译验证器:Schema 验证器首次编译后缓存,后续调用直接使用
  • Radix Tree 路由:O(k) 时间复杂度的路由匹配
  • 优化的请求解析:Query/Cookie 解析比标准方法快 2x

5. 一套代码,到处运行

Vafast 基于 Web 标准 Fetch API 构建,同一份代码可以跑在:

typescript 复制代码
// Bun
export default { port: 3000, fetch: server.fetch }

// Cloudflare Workers
export default { fetch: server.fetch }

// Node.js
import { serve } from 'vafast'
serve({ fetch: server.fetch, port: 3000 })

快速上手

安装

bash 复制代码
npm install vafast

最小示例

typescript 复制代码
import { Server, defineRoutes, createHandler } from 'vafast'

const routes = defineRoutes([
  {
    method: 'GET',
    path: '/',
    handler: createHandler(() => ({ message: 'Hello Vafast!' }))
  }
])

const server = new Server(routes)
export default { port: 3000, fetch: server.fetch }

带验证的 CRUD

typescript 复制代码
import { Server, defineRoutes, createHandler, Type, err } from 'vafast'

const users = new Map()

const routes = defineRoutes([
  // 获取用户列表
  {
    method: 'GET',
    path: '/users',
    handler: createHandler(() => Array.from(users.values()))
  },
  
  // 创建用户
  {
    method: 'POST',
    path: '/users',
    handler: createHandler(
      { body: Type.Object({ name: Type.String(), email: Type.String() }) },
      ({ body }) => {
        const id = crypto.randomUUID()
        const user = { id, ...body }
        users.set(id, user)
        return user
      }
    )
  },
  
  // 获取单个用户
  {
    method: 'GET',
    path: '/users/:id',
    handler: createHandler(
      { params: Type.Object({ id: Type.String() }) },
      ({ params }) => {
        const user = users.get(params.id)
        if (!user) throw err.notFound('用户不存在')
        return user
      }
    )
  }
])

const server = new Server(routes)
export default { port: 3000, fetch: server.fetch }

中间件

Vafast 的中间件直接声明在路由上,清晰明了:

typescript 复制代码
const authMiddleware = async (req, next) => {
  const token = req.headers.get('Authorization')
  if (!token) return new Response('Unauthorized', { status: 401 })
  return next()
}

const routes = defineRoutes([
  // 公开接口
  { method: 'GET', path: '/public', handler: publicHandler },
  
  // 需要认证的接口
  { method: 'GET', path: '/profile', middleware: [authMiddleware], handler: profileHandler },
])

内置 Format 验证

Vafast 内置 30+ 常用格式验证器,开箱即用:

typescript 复制代码
const UserSchema = Type.Object({
  email: Type.String({ format: 'email' }),
  phone: Type.String({ format: 'phone' }),      // 中国手机号
  website: Type.String({ format: 'url' }),
  avatar: Type.String({ format: 'uuid' }),
  birthday: Type.String({ format: 'date' }),
})

支持的格式包括:emailurluuidphonedate-timeipv4ipv6jwtbase64emoji 等。

错误处理

Vafast 提供语义化的错误 API:

typescript 复制代码
import { err } from 'vafast'

throw err.badRequest('参数错误')     // 400
throw err.unauthorized('请先登录')   // 401
throw err.forbidden('无权限')        // 403
throw err.notFound('资源不存在')     // 404
throw err.conflict('数据冲突')       // 409
throw err.internal('服务器错误')     // 500

统一的错误响应格式:

json 复制代码
{
  "error": "NOT_FOUND",
  "message": "资源不存在"
}

与其他框架对比

特性 Express Hono Elysia Vafast
路由风格 链式 链式 链式 声明式数组
路由可读性 一般 一般 一般 优秀
类型推断
跨文件类型 ⚠️
性能 56K 56K 118K 101K
运行时 Node 全部 Bun 全部

适合什么场景?

  • ✅ 需要路由一览表,方便团队协作和代码审查
  • ✅ 需要端到端类型安全,减少前后端联调成本
  • ✅ 需要跨运行时部署,同一代码跑 Node/Bun/Workers
  • ✅ 喜欢声明式配置,而非链式调用
  • ✅ 追求高性能,但不想牺牲开发体验

资源链接

总结

Vafast 不是要取代所有框架,而是提供一种结构、清晰、可控的开发方式。

如果你:

  • 厌倦了在链式调用中找路由
  • 受够了跨文件类型丢失的问题
  • 想要更好的团队协作体验

那么 Vafast 值得你试一试。

bash 复制代码
npx create-vafast-app my-app
cd my-app
npm run dev

觉得有用的话,欢迎 Star ⭐️ 支持一下!

如果你有任何问题或建议,欢迎在评论区留言交流~

相关推荐
IT=>小脑虎16 小时前
2026版 Go语言零基础衔接进阶知识点【详解版】
开发语言·后端·golang
图南随笔17 小时前
Spring Boot(二十三):RedisTemplate的Set和Sorted Set类型操作
java·spring boot·redis·后端·缓存
麦兜*17 小时前
Spring Boot 整合 Apache Doris:实现海量数据实时OLAP分析实战
大数据·spring boot·后端·spring·apache
源代码•宸17 小时前
Golang基础语法(go语言指针、go语言方法、go语言接口、go语言断言)
开发语言·经验分享·后端·golang·接口·指针·方法
Bony-17 小时前
Golang 常用工具
开发语言·后端·golang
pyniu17 小时前
Spring Boot车辆管理系统实战开发
java·spring boot·后端
love_summer17 小时前
深入理解Python控制流:从if-else到结构模式匹配,写出更优雅的条件判断逻辑
后端
牛奔17 小时前
GVM:Go 版本管理器安装与使用指南
开发语言·后端·golang
武子康17 小时前
大数据-207 如何应对多重共线性:使用线性回归中的最小二乘法时常见问题与解决方案
大数据·后端·机器学习