普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月17日首页

🔧 Rattail | 面向 Vite+ 和 AI Agent 的前端工具链

作者 耗子君QAQ
2026年4月17日 00:17

写在前面

掘金的同学们大家好呀,作者是 Varlet UI 的作者。掘金文章已经一年没更新了,去年跳槽到了一家创业公司负责前端架构工作,写文章这件事就一直搁置了。最近稍微缓过来了一点点(其实还是压力很大...),但不妨碍今天来给大家分享一下我们最新的开源项目 rattail

先聊聊 Vite Plus

上个月 VoidZero 正式以 MIT 协议开源了 Vite+,它把 ViteVitestOxlintOxfmtRolldowntsdown 统一收拢到了一个 vp 命令下面,一套工具链覆盖 devbuildtestlintfmtpack 等所有工程化环节。作者第一时间就把 varlet 周边的项目迁移到了 Vite+ 上面试试水,迁移下来发现效果特别好。以前那些散落在各处的 eslint 配置、prettier 配置、lint-staged 配置、commitlint 配置可以统一收拢到一个 vite.config.ts 里面,项目根目录一下子干净了不少(以前打开根目录看到十几个 .xxxrc 文件的日子终于结束了)。而且因为工具链统一了,AI Agent 在理解项目配置的时候幻觉也少了很多。

公司项目迁移

既然体验这么好,作者就决定把公司内部的前端项目也都迁移到 Vite+ 上。迁移的过程中也让作者重新审视了一下 rattail,我们在 varlet 生态里积累了大量的工具函数、请求库、校验规则工厂、CLI 工具链,之前一直是分散在各个包里的,正好借这次机会做一次大整合,于是就有了 rattail 2.0——一个面向 Vite+、对 AI Agent 非常友好的前端工具链。140+ 工具函数、渐进式请求库、链式校验规则工厂、CLI 工具链、类型安全枚举,pnpm add rattail 一条命令全部拉齐。

目前作者也在公司项目中全面使用了 Vite+ + rattail 这套技术栈,体验下来非常舒服。另外值得一提的是,这次 rattail 2.0 的迁移和开发过程中,作者大量使用了 AI 辅助编程,包括工具函数的编写、单元测试的补全、文档的生成等等,效率提升非常明显。配合 rattail 提供的 Agent Skills,AI Agent 能够很好的理解项目上下文并正确使用 rattail 的 API,整个工作流跑下来还是相当丝滑的。后续在业务开发中也明显感觉到,因为 rattail 把工具函数、请求库、校验规则这些东西 all in one 了,AI 在生成代码的时候幻觉变得特别少,而且很会按照规范做事。

相关链接

特性一览

  • ⚙️ 面向 Vite+ 的开箱即用配置预设
  • 🔧 CLI 工具链,支持发布、日志、Git Hooks、Commit Lint、API 生成
  • 🧰 140+ 工具函数,覆盖通用、字符串、数字、数组、对象、数学等场景
  • 🚀 基于 axios 的渐进式请求工具,支持 Vue 组合式 API
  • 📏 链式校验规则工厂,适配任意 UI 框架
  • 🏷️ 类型安全的枚举工具
  • 🤖 提供 Agent Skills,帮助 AI 编程助手理解和使用 Rattail
  • 🌲 可 Tree-shake,轻量,TypeScript 完整类型支持
  • 💪 90%+ 单元测试覆盖率

下面作者挑几个有意思的能力展开聊聊。

Vite+ 配置预设

做过前端工程化的同学应该都有体会,每次新项目光配 eslintprettier 这些东西就够喝一壶的了,配好了还得处理各种冲突。rattail 内置了面向 Vite+ 的开箱即用预设,一个 vite.config.ts 搞定 lintformatstagedgit hooks 等所有工程化配置。

import { lint, fmt, staged, clean, hook, defineConfig } from 'rattail/vite-plus'

export default defineConfig({
  lint: lint(),

  fmt: fmt(),

  staged: staged(),

  rattail: {
    clean: clean(),

    hook: hook(),
    
    api: {},

    release: {},

    changelog: {}
  },
})

之前作者为了配这些东西写了好几个配置文件,现在一个文件就够了(少写代码是第一生产力)。

CLI 工具链

安装 rattail 后会注册一个 rt 命令,覆盖了作者日常开发中最常用的几个场景。

# 清理产物
rt clean

# 安装 git hooks
rt hook

# 发布
rt release

# 生成 changelog
rt changelog

# 从 OpenAPI 生成 API 模块
rt api

这些命令都支持通过 vite.config.ts 中的 rattail 字段进行配置,也就是说项目根目录不需要再多出一堆 .xxxrc 文件了。这一点作者是比较在意的,毕竟谁也不想打开项目根目录看到十几个配置文件吧(有些项目根目录比 node_modules 还热闹)。

140+ 工具函数

lodash 大家都耳熟能详了,rattail 里的工具函数覆盖的场景和 lodash 类似,包括类型判断数组对象字符串数学函数集合文件等分类,用法就不逐个列举了。和 lodash 不同的是,这些函数从第一天就是用 TypeScript 写的,类型推导是第一优先级,全部可 Tree-shake。除了 lodash 风格的工具函数以外,rattail 还内置了一些前端项目中常用的实用工具,比如 sumHash 计算哈希、uuid 生成唯一 ID、mitt 事件总线、duration 时间格式化、storage / cookieStorage 存储封装、copyText 复制文本、download 文件下载等等,省得同学们每次都要单独装一堆小包。更多的可以去文档里查看完整的 API 列表。

类型安全的枚举工具

这个是作者个人比较喜欢的一个工具。前端项目里到处都是枚举值,比如订单状态、用户角色之类的。一般我们用 enum 或者常量对象来管理它们,但是 labeldescription 这些配套信息就只能另外维护了。enumOf 把值和它的元信息放在一起管理,并且类型推导是完备的。

import { enumOf } from 'rattail'

const Status = enumOf({
  Pending: { value: 0, label: '待处理' },
  Active: { value: 1, label: '进行中' },
  Done: { value: 2, label: '已完成' },
})

Status.Pending        // 0
Status.Active         // 1
Status.values()       // [0, 1, 2]
Status.labels()       // ['待处理', '进行中', '已完成']
Status.label(Status.Pending) // '待处理'
Status.options()      // [{ value: 0, label: '待处理' }, ...]

// 直接丢给 select 组件的 options,再也不用手动维护了

前端项目里到处都需要枚举值和它对应的文案,以前每次都要写个 map 或者 switch,现在一个 enumOf 就够了。另外 enumOflabeldescription 支持传入一个 getter 函数,配合 vue-i18n 之类的国际化方案可以很方便的实现多语言:

const Status = enumOf({
  Pending: { value: 0, label: () => t('status.pending') },
  Active: { value: 1, label: () => t('status.active') },
  Done: { value: 2, label: () => t('status.done') },
})

基于 axios 的渐进式请求工具

这个能力来自于作者之前开源的 @varlet/axle,现在通过 rattail/axle 直接引入。熟悉作者的同学可能看过之前介绍 axle 的文章,它在兼容 axios 的同时,天然支持 Vue3 Composition API

import { createAxle } from 'rattail/axle'
import { createUseAxle } from 'rattail/axle/use'

const axle = createAxle({ baseURL: '/api' })
const useAxle = createUseAxle({ axle })

const [users, getUsers, { loading, error }] = useAxle({
  method: 'get',
  url: '/user',
  params: { current: 1, pageSize: 10 },
})

作者一直觉得前端请求库和 Vue 的响应式系统应该有更好的结合方式,axle 就是在这个方向上的一个尝试。如果你不喜欢 axle 也完全没问题,rattail 的其他能力和请求库是解耦的,换成你喜欢的方案就好。

OpenAPI 生成 API 模块

rt api 可以直接解析后端提供的 OpenAPI / Swagger schema 文件,自动生成类型安全的 API 调用代码,这个在实际项目里把工作流做通之后体验可太好了。

vite.config.ts 里配置好 schema 路径和输出目录:

import { defineConfig } from 'rattail/vite-plus'

export default defineConfig({
  rattail: {
    api: {
      input: './openapi.json'
    },
  },
})

执行 rt api 后会自动生成这样的代码:

import { api } from '@/request'
import { type paths } from './_types'

export type ApiGetUsers = paths['/users']['get']
export type ApiCreateUser = paths['/users']['post']
export type ApiGetUser = paths['/users/{uuid}']['get']
export type ApiUpdateUser = paths['/users/{uuid}']['put']
export type ApiDeleteUser = paths['/users/{uuid}']['delete']

export type ApiGetUsersQuery = ApiGetUsers['parameters']['query']
export type ApiGetUsersRequestBody = undefined
export type ApiGetUsersResponseBody = ApiGetUsers['responses']['200']['content']['application/json']
// ... 其他类型同理

export const apiGetUsers = api<
  ApiGetUsersResponseBody, ApiGetUsersQuery, ApiGetUsersRequestBody>('/users', 'get')
export const apiCreateUser = api<
  ApiCreateUserResponseBody, ApiCreateUserQuery, ApiCreateUserRequestBody>('/users', 'post')
export const apiGetUser = api<
  ApiGetUserResponseBody, ApiGetUserQuery, ApiGetUserRequestBody>('/users/:uuid', 'get')
export const apiUpdateUser = api<
  ApiUpdateUserResponseBody, ApiUpdateUserQuery, ApiUpdateUserRequestBody>('/users/:uuid', 'put')
export const apiDeleteUser = api<
  ApiDeleteUserResponseBody, ApiDeleteUserQuery, ApiDeleteUserRequestBody>('/users/:uuid', 'delete')

请求类型、响应类型全部从 schema 里提取,不需要手写。后端接口变了,重新跑一遍 rt api 就行,前后端的类型始终保持同步。这个工作流对 AI Agent 也特别友好,AI 可以直接基于生成的类型去写业务代码,不会出现参数类型对不上的问题。甚至 AI Agent 可以通过 api 定义的变化,推测出你接下来要写什么业务。默认使用 axle,也支持 axios 的预设,同时支持 自定义输出

链式校验规则工厂

做表单的同学应该都写过类似 requiredminmax 这些校验规则。不同的 UI 框架校验规则的格式还不一样,每个项目都要适配一遍。rattail 提供了一个链式校验规则工厂,写起来很流畅,并且可以适配任意 UI 框架。这种内联的声明式写法和 TailwindCSS 的思路类似,可读性和可迁移性都非常好,对 AI 也特别友好,AI 可以直接从模板里读懂校验意图,生成和修改规则的准确度很高。

Naive UIElement Plus 为例:

<!-- Naive UI -->
<script setup lang="ts">
import type { FormItemRule } from 'naive-ui'
import { rulerFactory } from 'rattail/ruler'

const r = rulerFactory<FormItemRule>((validator, params = {}) => ({
  trigger: ['blur', 'change', 'input'],
  validator: (_, value) => validator(value),
  ...params,
}))
</script>

<template>
  <n-form :model>
    <n-form-item 
      path="name" 
      label="姓名"
      :rule="r().required('必填').min(2, '长度不正确').done()"
    >
      <n-input v-model:value="model.name" />
    </n-form-item>
  </n-form>
</template>
<!-- Element Plus -->
<script setup lang="ts">
import type { FormItemRule } from 'element-plus'
import { rulerFactory } from 'rattail/ruler'

const r = rulerFactory<FormItemRule>((validator, params) => ({
  validator(_, value, callback) {
    const e = validator(value)
    e ? callback(e) : callback()
  },
  trigger: ['blur', 'change', 'input'],
  ...params,
}))
</script>

<template>
  <el-form :model>
    <el-form-item 
      prop="email" 
      label="邮箱"
      :rules="r().email('必须是邮箱格式').done()"
    >
      <el-input v-model="model.email" />
    </el-form-item>
  </el-form>
</template>

AI Agent Skills

rattail 提供了一套 Agent Skills,说白了就是给 AI 写了一份"说明书",让 AI Agent 知道 rattail 有哪些能力、怎么用,不用你每次都手动告诉 AI。作者觉得未来的开源库都应该考虑对 AI Agent 的友好度。

写在最后

rattail 的工具函数和能力大多来自前端社区的通用实践。感谢同学们能看到这里,但是希望 rattail 能够帮助到大家。项目基于 MIT 协议。如果在使用的过程中遇到任何问题,欢迎在 issue 里反馈给我们,同时也十分欢迎对项目有兴趣的同学给我们发 pull request

支持我们的话留下一个 star 就好~

❌
❌