vite-plugin-openapi-ts:让 Vite 项目消费 OpenAPI 更优雅

138 阅读7分钟

vite-plugin-openapi-ts:让 Vite 项目消费 OpenAPI 更优雅

在很多前后端分离项目里,后端已经提供了比较完整的 OpenAPI(Swagger)文档,但前端依然需要:

  • 手写一堆 axios / fetch 封装;
  • 自己维护接口类型,接口一改就容易“代码没改全”;
  • 在多个项目里重复造一遍轮子。

vite-plugin-openapi-ts 就是为这个场景准备的:
它是一个 Vite 插件,可以从 OpenAPI 规范自动生成 TypeScript 类型类型安全的 API 客户端,同时还提供 CLI,方便集成到各种工作流里。


核心卖点一览

  • ✨ 自动生成代码:从 OpenAPI 生成 TS 类型 + API 客户端
  • 🔒 类型安全:请求参数、响应数据都有完整类型提示
  • 🎯 框架无关:只要是 Vite 项目,都能用(Vue / React / Svelte / …)
  • 📦 零配置起步:只需给一个 OpenAPI 地址即可跑起来
  • 🔄 自动同步:构建时自动生成 / 更新类型
  • 📄 多格式支持:JSON、YAML 都支持
  • 🌐 OpenAPI 3.0 & 3.1:兼容主流版本规范
  • 🛠 CLI 工具:支持命令行生成和清理缓存/生成文件

如果你正在用 Vite + TypeScript,并且有现成的 OpenAPI 文档,这个插件基本可以“零成本”提升你的开发体验和代码质量。


快速上手:三步搞定

1. 安装依赖

pnpm add -D vite-plugin-openapi-ts
# 或者
npm install -D vite-plugin-openapi-ts
yarn add -D vite-plugin-openapi-ts

2. 在 Vite 中注册插件

vite.config.ts 里加入:

import { defineConfig } from 'vite';
import openapiPlugin from 'vite-plugin-openapi-ts';

export default defineConfig({
  plugins: [
    openapiPlugin({
      url: 'http://localhost:8080/v3/api-docs', // OpenAPI 文档地址
      baseUrl: 'http://localhost:8080',          // API 基础地址,可省略让插件自动推导
      outputDir: 'src/openapi',                  // 生成代码输出目录,默认也是这个
    })
  ]
});

支持 JSON 也支持 YAML:

openapiPlugin({
  url: 'http://localhost:8080/swagger.yaml',
  baseUrl: 'http://localhost:8080',
  outputDir: 'src/openapi',
});

如果你本地已经有一个 OpenAPI 文件,也可以直接用“本地文件路径”作为输入,例如:

openapiPlugin({
  // 直接指向本地 openapi.json / openapi.yaml
  url: './openapi.yaml',
  // 本地文件场景下,建议总是显式配置一个正确的 baseUrl
  baseUrl: 'https://api.example.com',
  outputDir: 'src/openapi',
});

此时插件会在构建/启动 Dev Server 时读取本地文件内容,并生成对应的类型和客户端代码。

构建或启动开发服务器时,插件会自动拉取 OpenAPI 规范,根据内容生成:

  • src/openapi/schemes.ts:所有 schema 对应的 TS 类型
  • src/openapi/index.ts:带拦截器、错误封装的 API 客户端

3. 在代码中直接调用

import apiClient from '@/openapi'; // 对应 outputDir

// 路径参数 + 类型安全
const { data: user } = await apiClient(
  '/users/{id}',
  'get',
  {
    params: { id: '123' },
  }
);

// 查询参数
const { data: users } = await apiClient(
  '/users',
  'get',
  {
    query: { page: 1, limit: 10 },
  }
);

// 带请求体
const { data: newUser } = await apiClient(
  '/users',
  'post',
  {
    body: { name: 'Alice', email: 'alice@example.com' },
  }
);

接口路径、方法名、参数结构、返回类型,都会有完整的 TypeScript 提示和校验。


高级特性:不仅仅是“生成类型”而已

1. 全局配置与基础设置

生成的客户端通常还会导出一个 config 对象,你可以统一设置:

import apiClient, { config } from '@/openapi';

config.baseUrl = 'https://api.example.com';
config.headers = {
  'Content-Type': 'application/json',
  Authorization: 'Bearer your-token',
};

const { data } = await apiClient('/users', 'get');

在团队项目里,可以在应用初始化阶段设置一次,全局生效。

2. 请求 / 响应拦截器

和你在 axios 里习惯的用法类似,生成的客户端也支持拦截器:

import apiClient, { interceptors } from '@/openapi';

// 请求拦截器:统一加 token、打日志等
const removeRequestInterceptor = interceptors.request.use(async (config) => {
  config.headers['Authorization'] = `Bearer ${getToken()}`;
  console.log('Request:', config.method, config.url.pathname);
  return config;
});

// 响应拦截器:统一处理状态码
interceptors.response.use(async (response) => {
  console.log('Response:', response.response.status);
  return response;
});

// 错误拦截器:集中处理 401 / 500 等
interceptors.error.use(async (error) => {
  if (error.status === 401) {
    // 比如跳转登录
    window.location.href = '/login';
  }
  throw error;
});

这让你可以在一个地方集中处理认证、日志上报、全局错误提示等逻辑。

3. 请求取消、超时与重试

  • 支持通过 AbortController 取消请求,非常适合 React / Vue 组件卸载时清理。
  • 支持设置全局超时时间,避免某些接口“卡死”。
  • 支持配置自动重试策略,对网络抖动比较友好。

这些能力在生成的客户端中已经帮你封装好,你只需要在需要的位置打开相关配置即可。


CLI 支持:适合 CI / 工具链集成

除了 Vite 插件,你还可以使用 CLI 命令:

npx openapi-ts generate --url http://localhost:8080/v3/api-docs --base-url http://localhost:8080

常见能力包括:

  • generate / gen:根据 OpenAPI 生成类型和客户端;
  • clean:删除生成的 schemes.tsindex.ts,可选是否清理缓存;
  • clean-cache:单独清理 .openapi-cache.json

配合 CI 或 monorepo,你可以在构建前先跑一遍生成脚本,再让各个子应用消费统一生成的客户端。

生成策略与缓存机制

实际落地时,你通常不希望“每次构建都重新拉一次 OpenAPI 然后生成代码”,否则在 CI 或本地开发场景下会浪费不少时间。
为此,vite-plugin-openapi-ts 内部做了一个很轻量的缓存机制,大致规则是:

  • 每次生成时,会计算 OpenAPI 文本内容的哈希(以及当前使用的 baseUrl);
  • 在输出目录下写入一个 .openapi-cache.json,记录本次的哈希值和时间戳;
  • 下次生成时,如果发现“哈希没变 + baseUrl 一致”,就直接跳过生成;
  • 你也可以通过配置:
    • enableCache:关闭或开启缓存(默认开启);
    • skipTimeout:设置“最近多久之内不要重复生成”(单位毫秒);
    • force:强制重新生成,忽略缓存和 skipTimeout

简单理解就是:在接口文档没变的情况下,插件会尽量不打扰你,把生成这件事变成一次“几乎无感”的操作。

用 openapi.config.json 统一管理配置

为了方便在不同环境(本地 / CI / 多个子项目)之间共享配置,插件和 CLI 还支持从项目根目录下读取一个 openapi.config.json 文件:

  • 当你在 vite.config.ts 里调用 openapiPlugin()、但不传入任何参数时,插件会尝试读取 openapi.config.json 中的配置;
  • 当你在命令行里执行 npx openapi-ts generate 时,CLI 会把 openapi.config.json 作为默认值,再用命令行参数进行覆盖。

这个配置文件长得大概像这样:

{
  "url": "http://localhost:8080/v3/api-docs",
  "baseUrl": "http://localhost:8080",
  "outputDir": "src/openapi",
  "enableCache": true,
  "skipTimeout": 0,
  "force": false
}

一种比较推荐的使用方式是:

  • 把团队约定好的默认配置都写在 openapi.config.json 里(文档地址、基础 URL、输出目录、缓存策略等);
  • 开发和测试环境里,直接:
    • Vite 里用 openapiPlugin() 空参启动;
    • 命令行里用 npx openapi-ts generate
  • 如果某个环境需要临时覆盖配置(比如 CI 想连另一个环境的网关),就用命令行参数覆盖:
npx openapi-ts generate \
  --url https://api-dev.example.com/openapi.json \
  --base-url https://api-dev.example.com \
  --force

这样,媒体文章的读者即使完全没看过 README,也可以直接照着这几段配置抄过去,在自己的项目里跑起来。


适用场景与团队收益

这里只列几个典型场景:

  • 已经有比较规范的 Swagger / OpenAPI 文档,希望前端自动获得接口类型和客户端;
  • 团队内部有多个前端项目,希望统一一套“接口 SDK”,减少重复封装;
  • 希望在 PR / CI 阶段就能发现“接口字段改了,前端没改”的问题,而不是靠线上报错;
  • 倾向用 TypeScript 做强类型约束,减少因 any 带来的隐性 bug。

实战体验上,vite-plugin-openapi-ts 能明显减少手写接口层的工作量,同时提高接口变更的可见性和安全性,是非常典型的“提升团队长期生产力”的工具。


总结:为什么值得一试?

综合来看,这个项目有几个非常值得推荐的点:

  • 聚焦 Vite + OpenAPI 这个高频组合,定位清晰;
  • 功能覆盖到位,不只是“生成 d.ts”,而是“生成可用、可配置、可拦截的客户端”;
  • 工程实现干净,缓存、日志、类型推导都考虑得比较细;
  • 文档友好,中英文兼顾,对上手门槛要求不高。

需要特别说明的是:vite-plugin-openapi-ts 目前是我个人开发、在业余时间维护的开源项目,虽然在常见场景下已经可以正常使用,但我无法保证在所有 OpenAPI 规范、所有运行环境下都 100% 不出问题。建议大家优先在非生产环境或非关键资产项目里尝试使用,确认符合团队预期后,再逐步扩大使用范围。