mcpField
N
nuxt

nuxt

github.com/vercel-labs開発2.0k78 回インストール2 日前に更新
リポジトリ

nuxt について

nuxtはAPIエミュレーターをNuxtアプリに組み込み、同一オリジンのルートで提供するアダプターです。プレビュー環境や統合テスト向けに、複数エミュレーター、任意の状態永続化、レスポンス内のパス書き換えに対応します。

主な機能

  1. 01Nuxtサーバールートにエミュレーターをマウント
  2. 02同一オリジンのパスで複数サービスを提供
  3. 03任意の状態永続化に対応
  4. 04レスポンス内のサービスパスを置換
  5. 05カスタムエミュレーター定義を受け入れ

活用シーン

  1. 01プレビュー環境でOAuthコールバックをテスト
  2. 02Nuxtアプリ内でAPIエミュレーターを実行
  3. 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/* パッケージは個別に公開されるため、サーバーバンドルを小さく保てます。

サーバールート

エミュレーターへのトラフィックを処理する名前付きキャッチオールルートを作成します。

// 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 Storage
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):状態が保存されます。競合状態を防ぐため、保存処理は内部キューを介して直列化されます。
  • 永続化が設定されていない場合:純粋なメモリ内処理にフォールバックします。シードデータはコールドスタートのたびに再初期化されます。

動作の仕組み

  1. 受信リクエスト:/emulate/github/login/oauth/authorize?client_id=...
  2. 解析:service = github、rest = /login/oauth/authorize
  3. プレフィックスの除去:除去後のパスを持つ新しい Request が作成され、GitHub サービスアプリに転送されます
  4. レスポンスの書き換え:HTML の action と href 属性、CSS の url() フォント参照、Location ヘッダーにサービスプレフィックスが付加されます
  5. 永続化:変更を伴うリクエストの後、永続化アダプターを介して状態が保存されます

制限事項

  • エミュレーターは Node API を使用するため、Node 互換の Nuxt サーバーランタイムが必要です
  • 同時に行われる変更は、後勝ちのセマンティクスを使用します。生成された ID については、コールドスタートをまたいで初期スナップショットをアトミックに選択するため、initialize が必要です。

設定リファレンス

createEmulateHandler(config, options?)
フィールド型説明
servicesRecord<string, EmulatorEntry>サービス名とエミュレーター設定のマップ
persistence?PersistenceAdapterコールドスタートをまたいで状態を保持するための任意の永続化アダプター

各 EmulatorEntry:

フィールド型説明
emulatorEmulatorModuleエミュレーターパッケージ。例:import * as github from '@emulators/github'
seed?Record<string, unknown>サービスの設定スキーマに一致するシードデータ

オプション:

オプション型デフォルト説明
paramstring"path"名前付きキャッチオールルートのパラメーター
routePrefixstringdetectedキャッチオールルートがマウントされるパスプレフィックス
withEmulate(nuxtConfig)

Nitro の本番トレースに @emulators/core のアセットを含めるよう、Nuxt 設定をラップします。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 のような compare-and-set セマンティクスで実装してください。@emulators/core の組み込み filePersistence(path) は、ローカル開発向けにこの動作を提供します。

カスタムエミュレーター

アダプターは、services[name].emulator 内の emulate の defineEmulator で作成された定義を受け付けます。CLI/テストから定義を再利用してください。カスタムインスペクターはオプトインです。ルート相対のリダイレクト先はサービスのマウント配下に留まりますが、カスタム HTML ボディはそのまま通過します。テストの終了処理では、返されたハンドラーの close() を待機してください。デプロイされる定義では、emulate をランタイム依存関係としてインストールしてください。シード、スナップショット、永続化、ライフサイクルのルールについては https://emulate.dev/docs/custom-emulators を参照してください。

コメント