news 2026/9/29 5:53:17

在 Vue 3 中调用 Midway 函数式 API:@midwayjs/vue 桥接插件与组合式 API 实践指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 Vue 3 中调用 Midway 函数式 API:@midwayjs/vue 桥接插件与组合式 API 实践指南
  • 后端
  • 微服务
  • 云原生

【免费下载链接】midway

🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈

项目地址:https://gitcode.com/gh_mirrors/mi/midway
点击查看免费下载

导读

@midwayjs/vue是 Midway 框架为 Vue 3 前端提供的一套“函数式 API 桥接”集成包,它让 Vue 应用可以直接复用后端 Midway 项目中通过defineApi声明的 API 定义,以api.user.getUser({ params: { id } })这样类型安全、语义化的方式发起请求。本文基于该包源码与仓库内可运行的 samples/vue-functional-api 示例,讲解从安装、注册插件到组合式调用、Provider 注入的完整链路,并深入src/index.ts揭示其基于 Vue 3provide/inject的底层实现原理。

背景:什么是 Midway 函数式 API 桥接

Midway 的函数式 API(Functional API)允许开发者用defineApi在服务端集中声明路由,并自动生成可供前端直接调用的“API 客户端”结构。@midwayjs/vue与@midwayjs/react、@midwayjs/api-bridge、@midwayjs/web-bridge同属于这一桥接家族:

  • @midwayjs/web-bridge是运行时依赖,负责提供createClient等核心客户端能力(其 src/index.ts 直接export * from '@midwayjs/api-bridge');
  • @midwayjs/vue在其之上补齐 Vue 专属的插件与组合式 API,让 Vue 组件可以用最“Vue 化”的方式消费客户端。

从 package.json 可以看到,@midwayjs/vue将@midwayjs/web-bridge作为依赖,并将vue声明为peerDependencies(要求vue >= 3),因此它天然面向 Vue 3 组合式 API 生态。

安装与依赖

npm i @midwayjs/vue @midwayjs/web-bridge

对应的package.json依赖声明为:

{ "dependencies": { "@midwayjs/vue": "^4.0.0-beta.11", "@midwayjs/web-bridge": "^4.0.0-beta.11" } }

要点说明:

  • vue无需显式安装为依赖,但运行时版本需满足>= 3(peerDependencies 约束),否则插件注入与组合式函数将不可用;
  • @midwayjs/web-bridge提供客户端核心(createClient),@midwayjs/vue提供 Vue 集成层,二者需成对安装;
  • 当前仓库中该包版本为4.2.3,engines要求node >= 20,构建产物同时提供 CommonJS(dist/index.js)与 ESM(dist/index.mjs)双格式,并通过exports字段区分require与import入口(见 packages/vue/package.json)。

基本用法:插件注册 + 组合式调用

1. 创建 Vue 应用并注册插件

import { createApp } from 'vue'; import { createMidwayApiPlugin } from '@midwayjs/vue'; import { api } from './api/client'; import App from './App.vue'; createApp(App).use(createMidwayApiPlugin(api)).mount('#root');

createMidwayApiPlugin(client)返回一个标准的 Vue 3 插件对象(Plugin),其内部通过app.provide(InjectionKey, client)将客户端实例注入到整个应用上下文(见 src/index.ts),此后任意组件树中都能取到同一个客户端实例。

2. 在组件中调用 API

import { useMidwayApiOperation } from '@midwayjs/vue'; const callGetUser = useMidwayApiOperation<{ params: { id: string } }, { id: string }>('user.getUser'); await callGetUser({ params: { id: '1' } });

useMidwayApiOperation是一个组合式函数(Composable),它接收operationId(如'user.getUser',格式为模块名.路由名),返回一个绑定好该操作 ID 的调用函数。泛型参数<TInput, TOutput>分别约束入参与返回值类型,从而在编译期获得完整的类型提示。

客户端创建:从服务端 API 定义到api.user.getUser

配合仓库内的可运行示例 samples/vue-functional-api,完整的链路如下。

服务端:声明 API 定义

// samples/vue-functional-api/src/server/api/user.api.ts import { defineApi } from '@midwayjs/core/functional'; export const userApi = defineApi('/users', api => ({ getUser: api .get('/:id') .meta({ routerName: 'getUser' }) .handle(async ({ input }) => { return { id: input.params?.['id'], name: 'harry', }; }), }));

前端:创建命名空间客户端

// samples/vue-functional-api/src/web/api/client.ts import { createClient } from '@midwayjs/vue'; import { userApi } from '../../server/api/user.api.js'; export const api = createClient( { user: userApi, }, { basePath: { browser: '/api', server: 'http://127.0.0.1:7001/api', }, } );

createClient的键(user)会成为调用前缀,最终形成api.user.getUser(...)的链式调用风格。basePath支持browser/server双配置,便于同构(CSR/SSR)场景下区分浏览器相对路径与服务器绝对路径。

核心链路:createClient 如何工作

测试用例 test/index.test.ts 精确验证了这一行为:传入带__midwayApiMeta.prefix与路由元信息的 API 定义后,api.user.getUser({ params: { id: 'u-1' } })会按get + '/users/:id'解析并调用底层的adapter,最终返回{ id: 'u-1' }。也就是说,createClient负责把声明式的路由元数据(method、path、routerName)转换为真实请求,并通过可替换的adapter决定实际网络发送方式。

核心 API 与底层实现(源码级解析)

@midwayjs/vue的全部导出集中在 src/index.ts,除createClient(来自 web-bridge)外共提供 4 个 Vue 专属能力,其实现全部建立在 Vue 3 的依赖注入机制之上。

客户端类型约定

interface MidwayApiClientLike { call(operationId: string, input: unknown): Promise<unknown>; has(operationId: string): Promise<boolean> | boolean; operationIds(): Promise<string[]> | string[]; }

这是桥接层的“最小客户端契约”:call执行调用、has判断某操作是否存在、operationIds枚举全部操作 ID。只要对象满足该形状(例如由createClient生成的真实客户端,或测试中的 mock),即可被注入与消费。

注入键与 Provider 组件

const MidwayApiClientInjectionKey: InjectionKey<MidwayApiClientLike> = Symbol('MidwayApiClient');
  • 注入键是Symbol('MidwayApiClient'),配合 TypeScript 的InjectionKey<T>泛型,保证注入/取用时类型一致;
  • 除插件方式外,包内还提供了声明式组件MidwayApiProvider(defineComponent),通过props.client接收客户端并在setup中provide给子树,适合“局部注入”而非全局注册的场景(见 src/index.ts)。

插件与组合式函数

export function createMidwayApiPlugin(client: MidwayApiClientLike): Plugin { return { install(app) { app.provide(MidwayApiClientInjectionKey, client); }, }; }

插件本质是对app.provide的一次封装;而组合式函数则通过inject反向获取:

export function useMidwayApiClient<TInput = unknown, TOutput = unknown>() { const client = inject(MidwayApiClientInjectionKey, null); if (!client) { throw new Error( 'useMidwayApiClient must be used inside app.use(createMidwayApiPlugin(client)) or <MidwayApiProvider>' ); } // ... } export function useMidwayApiOperation<TInput = unknown, TOutput = unknown>( operationId: string ) { const client = useMidwayApiClient<TInput, TOutput>(); return (input: TInput) => client.call(operationId, input); }

由此形成清晰的依赖链:

createApp(App).use(createMidwayApiPlugin(api)) // 全局注入 ↓ provide(Symbol('MidwayApiClient'), api) useMidwayApiClient() // inject 取回客户端 ↓ useMidwayApiOperation('user.getUser') // 绑定 operationId ↓ await callGetUser({ params: { id: '1' } }) // client.call('user.getUser', input)

错误保护:未注入时的显式报错

useMidwayApiClient在取不到客户端时抛出异常,提示必须通过app.use(createMidwayApiPlugin(client))或<MidwayApiProvider>注入。对应测试 test/index.test.ts 明确断言了该错误信息,帮助开发者快速定位“组合式函数用在了 Provider 之外”的常见误用。

测试验证与 ESM 产物检查

仓库为该包提供了两层测试保障:

  1. 单元测试(test/index.test.ts):覆盖客户端命名空间调用、插件install的provide调用次数与注入键(expect.any(Symbol))、未注入时报错三组关键行为;
  2. ESM 产物冒烟测试(test/esm-dist.test.mjs):直接import构建产物dist/index.mjs,断言createClient、createMidwayApiPlugin、MidwayApiProvider、useMidwayApiClient、useMidwayApiOperation均已正确导出且可运行,并使用自定义adapter验证createClient的operationId与input传递。

这一“单测 + dist 冒烟”的组合,既验证了源码逻辑,也保证了发布后双格式产物(CJS/ESM)的可用性。

仓库内可运行的完整示例

若希望端到端体验,仓库内置了 Vue + Midway 函数式 API 的可运行示例 samples/vue-functional-api:

# 在仓库根目录 pnpm install # 启动:内置 Vite 开发服务器 + 内嵌 Midway HTTP 运行时 pnpm -C samples/vue-functional-api dev

该示例的关键配置:

  • src/server/api/user.api.ts:用defineApi('/users', ...)声明getUser、createUser两个操作;
  • src/web/api/client.ts:createClient({ user: userApi }),并配置浏览器端/api、服务端http://127.0.0.1:7001/api双 basePath;
  • src/main.ts:createApp(App).use(createMidwayApiPlugin(api)).mount('#root'),与本文核心用法完全一致;
  • 后端为真实 Midway Koa 应用(imports: [koa]),/api/*请求由真实路由处理;
  • 构建时可通过pnpm -C samples/vue-functional-api build:server与build:web拆分产出,分别输出dist/server与dist/web。

小结

@midwayjs/vue将 Midway 的函数式 API 桥接能力“翻译”成了 Vue 3 开发者熟悉的表达方式:

  • 插件式注册:createMidwayApiPlugin(api)全局注入客户端,一行代码完成初始化;
  • 组合式调用:useMidwayApiOperation/useMidwayApiClient让组件内调用与 Vue 响应式生命周期自然融合;
  • Provider 局部注入:MidwayApiProvider提供按子树注入的灵活性;
  • 类型安全:InjectionKey+ 泛型约束贯穿注入、取用与调用全过程。

其底层实现极简而可靠:一个Symbol注入键 +provide/inject机制 + 最小客户端契约(call/has/operationIds)。理解这层实现后,无论是接入现有 Vue 项目、排查“组合式函数未注入”报错,还是基于同一契约实现自定义桥接层,都会更加得心应手。

  • 后端
  • 微服务
  • 云原生

【免费下载链接】midway

🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈

项目地址:https://gitcode.com/gh_mirrors/mi/midway
点击查看免费下载
上一篇:R3nzSkin国服换肤工具:如何安全实现英雄联盟皮肤自定义?
下一篇:终极免费实时屏幕翻译指南:5分钟上手Translumo,打破游戏与视频语言障碍

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 5:53:14

AI Agent从零搭建实战:核心架构、工具设计与DevOps落地

1. 为什么现在聊 AI Agent 正是时候过去一年我断断续续做了四五个 Agent 相关的项目&#xff0c;有给内部用的运维助手&#xff0c;也有面向业务侧的流程自动化工具。踩过的坑从“模型死活不按格式输出”到“工具调用循环把自己绕死”&#xff0c;基本把能犯的错都犯了一遍。所…

作者头像 李华
网站建设 2026/9/29 5:50:12

Selenium UI自动化测试框架工程化搭建指南

1. 为什么现在还要花时间搭一个 Selenium 测试框架&#xff1f;——不是为了“会用”&#xff0c;而是为了“能控”你搜“selenium测试框架快速搭建”&#xff0c;点开十篇教程&#xff0c;八篇在教你怎么 pip install selenium、怎么写 driver.get()、怎么用 find_element(By.…

作者头像 李华
网站建设 2026/9/29 5:48:06

AgentScope多智能体框架实战:从单Agent到协作编排的进阶指南

1. 为什么我要花时间聊 AgentScope 这个系统第一次看到 AgentScope 这个名字&#xff0c;是在一个做多智能体协作的群里。当时有人丢了一句“这玩意儿把 Agent 编排的门槛拉低了一个数量级”&#xff0c;我半信半疑地去翻了一圈资料&#xff0c;结果一上手就停不下来。简单说&a…

作者头像 李华