关于 nuxt
nuxt 是将 API 模拟器嵌入 Nuxt 应用、通过同源路由提供服务的适配器,适合预览部署和集成测试。它支持多个模拟器、可选状态持久化,并重写响应中的路由前缀。
主要功能
- 01在 Nuxt 服务路由中挂载模拟器
- 02通过同源路径提供多个服务
- 03支持可选状态持久化
- 04重写响应中的服务路径前缀
- 05兼容自定义模拟器定义
适用场景
- 01在预览部署中测试 OAuth 回调
- 02在 Nuxt 应用中运行 API 模拟器
- 03跨重启保留模拟器状态
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vercel-labs/ emulate --skill nuxt安装后在 Claude Code 中输入/nuxt确认已加载。
详细介绍
Nuxt 集成
@emulators/adapter-nuxt 包可将模拟器直接嵌入 Nuxt 应用,并在同一源上运行。这对于预览部署很有用,因为 OAuth 回调 URL 会随每次部署而变化。
安装
npm install @emulators/adapter-nuxt @emulators/github @emulators/google
只安装所需的模拟器。每个 @emulators/* 包都独立发布,以保持服务器 bundle 精简。
服务端路由
创建一个具名的全匹配路由,用于处理模拟器流量:
// server/routes/emulate/[...path].ts
import { createEmulateHandler } from '@emulators/adapter-nuxt'
import * as github from '@emulators/github'
import * as google from '@emulators/google'
export default defineEventHandler(createEmulateHandler({
services: {
github: {
emulator: github,
seed: {
users: [{ login: 'octocat', name: 'The Octocat' }],
repos: [{ owner: 'octocat', name: 'hello-world', auto_init: true }],
},
},
google: {
emulator: google,
seed: {
users: [{ email: '[email protected]', name: 'Test User' }],
},
},
},
}))
这会创建以下路由:
/emulate/github/**提供 GitHub 模拟器/emulate/google/**提供 Google 模拟器
GitHub 安装令牌元数据可在服务端通过 /emulate/github/_emulate/installation-tokens 获取。
Nuxt 配置
模拟器 UI 页面使用打包的字体。请包装 Nuxt 配置,以便 Nitro 将核心包资源追踪到生产构建中:
// nuxt.config.ts
import { withEmulate } from '@emulators/adapter-nuxt'
export default defineNuxtConfig(withEmulate({
// your normal Nuxt config
}))
OAuth 配置
将 OAuth 提供方指向同一源上的模拟器路径:
const baseUrl = process.env.NUXT_PUBLIC_SITE_URL ?? 'http://localhost:3000'
export const githubOAuth = {
clientId: 'any-value',
clientSecret: 'any-value',
authorizationUrl: `${baseUrl}/emulate/github/login/oauth/authorize`,
tokenUrl: `${baseUrl}/emulate/github/login/oauth/access_token`,
userInfoUrl: `${baseUrl}/emulate/github/user`,
}
无需预先植入 oauth_apps。未配置任何应用时,模拟器会跳过对 client_id、client_secret 和 redirect_uri 的验证。
持久化
默认情况下,模拟器状态存储在内存中,并在每次冷启动时重置。若要在重启后保留状态,请传入 persistence 适配器。
Nitro 存储
import { createEmulateHandler } from '@emulators/adapter-nuxt'
import * as github from '@emulators/github'
const storageAdapter = {
async load() { return await useStorage('emulate').getItem<string>('state') },
async save(data: string) { await useStorage('emulate').setItem('state', data) },
}
export default defineEventHandler(createEmulateHandler({
services: { github: { emulator: github } },
persistence: storageAdapter,
}))
文件持久化
对于本地开发,@emulators/core 提供了一个基于文件的适配器:
import { filePersistence } from '@emulators/core'
persistence: filePersistence('.emulate/state.json'),
GitHub App 种子数据可以省略 private_key。保留处理程序并调用仅限服务端使用的 generatedSecrets();显式密钥不会纳入其中。请妥善保管持久化快照,并以原子方式实现 initialize。
持久化的工作方式
- 冷启动:适配器从持久化适配器加载状态。如果找到状态,则恢复完整的 Store 和令牌映射;否则,根据配置植入种子数据并保存初始状态。
- 变更请求之后(POST、PUT、PATCH、DELETE):保存状态。保存操作通过内部队列串行执行,以防止竞争条件。
- 未配置持久化:回退到纯内存模式。种子数据会在每次冷启动时重新初始化。
工作原理
- 接收请求:
/emulate/github/login/oauth/authorize?client_id=... - 解析:service =
github,rest =/login/oauth/authorize - 移除前缀:创建一个路径已移除前缀的新
Request,并将其转发给 GitHub 服务应用 - 重写响应:为 HTML 的
action和href属性、CSS 的url()字体引用以及Location标头添加服务前缀 - 持久化:变更请求之后,通过持久化适配器保存状态
限制
- 需要兼容 Node 的 Nuxt 服务器运行时,因为模拟器使用 Node API
- 并发变更采用最后写入者胜出语义。生成的身份要求
initialize在多次冷启动之间以原子方式选择初始快照。
配置参考
createEmulateHandler(config, options?)
| 字段 | 类型 | 说明 |
|---|---|---|
services | Record<string, EmulatorEntry> | 服务名称到模拟器配置的映射 |
persistence? | PersistenceAdapter | 可选的持久化适配器,用于在冷启动之间保留状态 |
每个 EmulatorEntry:
| 字段 | 类型 | 说明 |
|---|---|---|
emulator | EmulatorModule | 模拟器包,例如 import * as github from '@emulators/github' |
seed? | Record<string, unknown> | 符合服务配置架构的种子数据 |
选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
param | string | "path" | 具名的全匹配路由参数 |
routePrefix | string | 检测所得 | 全匹配路由挂载的路径前缀 |
withEmulate(nuxtConfig)
包装 Nuxt 配置,将 @emulators/core 资源纳入 Nitro 的生产追踪。在 nuxt.config.ts 的 defineNuxtConfig 中调用。
PersistenceAdapter
interface PersistenceAdapter {
load(): Promise<string | null>
save(data: string): Promise<void>
initialize?(data: string): Promise<string>
}
initialize 必须以原子方式创建初始值,或返回另一个实例先创建的值。请使用具有比较并交换语义的方式实现,例如 Redis SET NX。@emulators/core 内置的 filePersistence(path) 可在本地开发中提供此行为。
自定义模拟器
该适配器接受由 emulate 中的 defineEmulator 创建的定义,并通过 services[name].emulator 配置。可在 CLI/测试中复用该定义;自定义检查器为可选项。相对于根目录的重定向位置仍位于服务挂载路径下,而自定义 HTML 正文则原样传递。请在测试清理时等待返回的处理程序的 close() 完成。部署定义时,请将 emulate 安装为运行时依赖项。有关种子、快照、持久化和生命周期规则,请参阅 https://emulate.dev/docs/custom-emulators。