pnpm 搭建 monorepo ,前后端项目共享类型安全的 Hono.js RPC 客户端

在 Hono.js 后端项目中导出类型,通过 pnpm 搭建 monorepo workspace ,即可在前后端项目间共享类型,实现类型安全的 RPC 客户端。

在这里,只有一个很简单的场景,就是在前端项目拿到共享类型,构建 RPC 客户端,所以只需要非常简单的设置即可完成。

创建项目主目录

创建 pnpm 项目:

pnpm init

创建 pnpm-workspace.yaml 文件,定义 apps 目录下的项目为子项目。

packages:
  - apps/*

创建 .gitignore 文件,忽略 node_modules 目录。

在目录下创建配置文件,设置 VSCode 使用 pnpm 管理:

{
    "npm.packageManager": "pnpm"
}

了解 monorepo 依赖管理命令

  • 安装公共依赖 pnpm install hono -w ,开发依赖加 -D ,参数改为 -wD
  • 给子项目安装依赖: pnpm add axios --filter vue-app ,开发依赖加参数 -D

创建 Hono.js 项目

创建一个新项目,放到 apps 下,不安装依赖。

npm create hono@latest apps/server

在根目录通过 pnpm 安装依赖。

pnpm install

安装 hono 文档 RPC 章节所述创建 authors 、 books 两套拆分路由,并导出 AppType 类型:

const app = new Hono().basePath('/api')

const routes = app.route('/authors', authors).route('/books', books)

export default app
export type AppType = typeof routes

在主项目安装 hono 公共依赖

因为需要在各个前端项目使用 hono RPC,需要安装 hono 这个包。公共安装,可免得每个窗口逐一安装。

pnpm add -w hono

再把 hono 从 server 目录去掉,重新更新依赖。

创建前端项目

创建一个 TS 的前端项目,之前都是根 React 搭配使用,这里试试 Vue 项目。

npm create vite@latest apps/vue-app -- --template vue-ts

配置一下 Vite 代理,方便调用后端接口:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vite.dev/config/
export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
      },
    },
  },
})

前端项目引用后端代码仓依赖

类型是在后端代名仓定义,前端想要使用,就要像安装依赖一样,先把后端代名仓引用过来。

pnpm workspace 提供了项目间引用的方式,在前端项目的 package.json 里增加依赖:

"dependencies": {
  "server": "workspace:*",
},

到根目录下,重新更新依赖。前端项目就可以引用了。

前端项目通过 RPC 发起请求

将 RPC 客户端封装一个文件里导出:

import { hc } from 'hono/client'
import { AppType } from 'server/src/index'
export const client = hc<AppType>('')

在 vue 文件中,就可以引用进行使用了:

<script setup lang="ts">
import { ref } from 'vue';
import { client } from './client';
const text = ref('')
client.api.authors.$get().then(res => res.json()).then(data => {
  text.value = data
})
</script>

<template>
  <div>
    {{ text }}
  </div>
</template>

整体都是类型安全的,使用起来很丝滑。