nuxt-gql-pulse

一个 Nuxt 3 模块,利用 Nuxt 的可组合项和 VueUse 的强大功能,轻松进行 GraphQL 请求。

Nuxt GQL Pulse logo

⚡ Nuxt GQL Pulse

npm versionnpm downloadsLicense: MITNuxt

一个 Nuxt 3/4 模块,可轻松进行 GraphQL 请求,利用 Nuxt 的可组合项来完成令人惊叹的事情。

✨ 特性

  • 🔌 支持多个 GraphQL 客户端
  • ⚡ 基于 Nuxt 的 useAsyncData 构建的可组合项
  • 🎯 简单 API,最少样板代码
  • 🧩 每个客户端和每个请求灵活的请求选项
  • 🔄 对 SSR 友好,支持 Nuxt payload 缓存
  • 🦾 强类型: 类型安全的客户端名称(通过全局 TGqlPulseClientKey 类型)
  • 🗂️ 缓存选项
    • sessionStorage (仅限 SPA) 用于持久化客户端缓存
    • Nuxt payload (对 SSR 友好) 用于服务器端水合
  • 🛠️ 集成 graphql-request (graffle 兼容)
  • 📦 适用于 Nuxt 3 和 Nuxt 4
  • 🧰 可组合项
    • useGqlPulseClient(clientName) — 访问原始客户端
    • useGqlPulseRequest(...) — 简单请求
    • useGqlPulseRawRequest(...) — 低级原始响应
    • useGqlPulseRequestWithCache(...) — sessionStorage 缓存 (SPA)
    • useAsyncGqlPulse(...) — 对 SSR 友好的异步数据
    • useAsyncGqlPulseWithCache(...) — 带有 sessionStorage 的 SPA 异步
    • useGqlPulseBatchRequests(...) — 批量处理多个查询
    • useAsyncGqlPulseBatch(...) — 带有可选 payload 缓存的异步批处理

🚀 快速设置

安装模块和对等依赖

npm install nuxt-gql-pulse graphql graphql-request

将其添加到您的 nuxt.config.ts:

export default defineNuxtConfig({
  modules: ['nuxt-gql-pulse'],

  gqlPulse: {
    clients: {
      rickandmortyapi: {
        endpoint: 'https://rickandmortyapi.com/graphql',
      },
    },
  },
})

就是这样!您现在可以在 Nuxt 应用程序中使用 Nuxt GQL Pulse 了 ✨

示例:从 Rick & Morty API 查询角色

<script setup lang="ts">
const query = /* GraphQL */ `
  query {
    characters(page: 1) {
      results {
        id
        name
        status
        species
      }
    }
  }
`

const { data } = await useAsyncGqlPulse<{
  characters: {
    results: { id: string; name: string; status: string; species: string }[]
  }
}>({
  client: 'rickandmortyapi',
  document: query,
})
</script>

<template>
  <div>
    <h2>Rick & Morty Characters</h2>
    <ul>
      <li v-for="character in data.characters.results" :key="character.id">
        {{ character.name }}{{ character.status }} ({{ character.species }})
      </li>
    </ul>
  </div>
</template>

🔄 比较 — 为什么选择 Nuxt GQL Pulse?

以下是与相关 Nuxt GraphQL 模块的实际比较(研究摘要)。这显示了功能重叠之处以及 nuxt-gql-pulse 的突出之处。

能力 / 模块nuxt-gql-pulsenuxt-graphql-requestnuxt-graphql-clientnuxt-graphql-middleware@nuxtjs/apollo / URQL
多个命名客户端✅ (内置)⚠️ (侧重服务器)
基于 useAsyncData 的可组合项✅ (已就绪)✅ (手动使用)✅ (代码生成)✅ (服务器封装)
sessionStorage 缓存 (客户端持久化)独特❌ (仅限内存/payload)❌ (使用规范化缓存)
Nuxt payload / SSR 水合缓存⚠️
graphql-request / graffle 集成⚠️ (可能使用不同的客户端/代码生成)⚠️ (服务器请求)❌ (Apollo/URQL)
支持原始响应 (rawRequest)⚠️⚠️✅ (客户端特定)
批量请求助手⚠️ (手动)⚠️⚠️✅ (取决于客户端)
Nuxt 3 / 4 支持
轻量级 / 最少运行时占用⚠️ (可能添加代码生成)⚠️❌ (Apollo 更大)

📄 文档

⚙️ 配置 (nuxt.config.ts)

export default defineNuxtConfig({
  modules: ['nuxt-gql-pulse'],

  gqlPulse: {
    /**
     * Define your GraphQL clients
     */
    clients: {
      // 'rickandmortyapi' was used in examples above instead of 'default'
      default: {
        /**
         * The client endpoint URL
         */
        endpoint: 'https://rickandmortyapi.com/graphql',

        /**
         * Per-client request configuration
         * Docs: https://github.com/graffle-js/graffle/blob/graphql-request/examples/configuration-fetch-options.ts
         */
        options: {
          method?: 'GET' | 'POST';
          headers?: Headers | string[][] | Record<string, string> | (() => Headers | string[][] | Record<string, string>);
          cache?: 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload';
          credentials?: 'include' | 'omit' | 'same-origin';
          integrity?: string;
          keepalive?: boolean;
          mode?: 'same-origin' | 'cors' | 'navigate' | 'no-cors';
          priority?: 'auto' | 'high' | 'low';
          redirect?: 'error' | 'follow' | 'manual';
          referrer?: string;
          referrerPolicy?: '' | 'same-origin' | 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
          errorPolicy?: 'none' | 'ignore' | 'all';
        }
      },
      secondClient: {
        // ... another client config
      },
    },

    /**
     * Global options applied to all clients
     */
    options: {
      // same structure as per-client `options`
    },

    /**
     * Optional
     * By default, all composables are auto-imported.
     *
     * You can exclude some if you only use one or two.
     *
     * Available auto-import composables:
     * [
     *  'useGqlPulseRequest',
     *  'useGqlPulseRequestWithCache',
     *  'useGqlPulseBatchRequests',
     *  'useGqlPulseRawRequest',
     *  'useAsyncGqlPulse',
     *  'useAsyncGqlPulseWithCache',
     *  'useAsyncGqlPulseBatch',
     * ]
     *
     * ⚠️ `useGqlPulseClient` is **always** imported by default
     * and cannot be excluded.
     */
    excludeComposables: [],
  },
})

🔑 类型声明 (index.d.ts)

如果您希望在项目中拥有类型安全的客户端名称,您可以在项目中全局声明 TGqlPulseClientKey 类型。通常这会在构建期间在 .nuxt/types/gql-pulse.d.ts 中自动生成,但您也可以在项目中手动声明以获得更好的开发体验。

declare global {
  type TGqlPulseClientKey = 'rickandmortyapi'
}

export {}

🧩 可组合项概览

🔧 API 快速参考 (签名)

  • useGqlPulseClient(clientName: string | "default"): GraphQLClient — 获取原始客户端
  • useGqlPulseRequest(opts): Promiseopts = { document, client?, variables? }
  • useGqlPulseRawRequest(opts): Promise<{ status, headers, data, errors?, extensions? }>
  • useGqlPulseRequestWithCache(opts): Promise<RemovableRef> — sessionStorage 缓存 (SPA)
  • useAsyncGqlPulse(opts): AsyncDataReturn — 对 SSR 友好的 useAsyncData 封装器
  • useAsyncGqlPulseWithCache(opts): AsyncDataReturn — SPA sessionStorage 缓存变体
  • useGqlPulseBatchRequests(opts): Promise— 一次批量处理多个查询
  • useAsyncGqlPulseBatch(opts): AsyncDataReturn — 带有可选 payload 缓存的批量 useAsyncData

🔁 缓存:SSR vs SPA

  • withPayloadCache / useAsyncGqlPulse → 对 SSR 友好,数据存储在 Nuxt payload 中并在客户端水合期间重用(无重复获取)。
  • *WithCache 变体 & useGqlPulseRequestWithCache → 仅限 SPA(通过 @vueuse/core 使用 sessionStorage)。这些用于跨重新加载的客户端持久缓存;不适用于仅限 SSR 的页面。

🔧 API 详情

useGqlPulseRequest

// Make standard GraphQL requests.
const data = await useGqlPulseRequest({
  document, // string | DocumentNode
  client: string, // defaults to first client
  variables: TVariables,
})

useGqlPulseRawRequest

// Low-level request returning headers, status, and errors.
const res = await useGqlPulseRawRequest({
  document: string,
  client: string,
  variables: TVariables,
}) // { status, headers, data, extensions, errors? }

useGqlPulseClient

// Access the underlying GraphQLClient instance.
// Always auto-imported and cannot be excluded.
const client = useGqlPulseClient('default')

useAsyncGqlPulse

// Nuxt-friendly async data fetching with optional payload cache. (SSR Friendly)
const { data, pending, error } = await useAsyncGqlPulse({
  key: 'characters',
  document,
  variables,
  client: 'default',
  withPayloadCache: true,
})

useAsyncGqlPulseWithCache

// SPA-only sessionStorage caching.
const data = await useAsyncGqlPulseWithCache({
  key: 'characters',
  document,
  variables,
})

useGqlPulseBatchRequests

// Batch multiple queries into one request.
const result = await useGqlPulseBatchRequests({
  documents: [
    { document: query1, variables: { id: 1 } },
    { document: query2, variables: { id: 2 } },
  ],
  client: 'default',
})

useAsyncGqlPulseBatch

// Nuxt-friendly async data fetching for batched requests with optional payload cache. (SSR Friendly)
const { data, pending, error } = await useAsyncGqlPulseBatch({
  key: 'batch-1',
  documents: [
    { document: query1, variables: { id: 1 } },
    { document: query2, variables: { id: 2 } },
  ],
  client: 'default',
  withPayloadCache: true,
})

useGqlPulseRequestWithCache

// SPA-only sessionStorage caching for single requests.
const result = await useGqlPulseRequestWithCache({
  key: 'character-1',
  document,
  variables,
})

🔌 客户端自定义配置 (plugins/gqlPulse.ts)

您还可以通过 Nuxt 插件为客户端提供自定义配置

export default defineNuxtPlugin(() => {
  const client = useGqlPulseClient('rickandmortyapi')
  const secondClient = useGqlPulseClient('secondClient')

  /**
   * Request middleware
   * Runs before every GraphQL request.
   * You can modify headers, body, or any request config here.
   */
  const requestMiddleware = async (
    request: RequestExtendedInit<Variables>
  ) => ({
    ...request,
    headers: {
      ...request.headers,
      Authorization: `Bearer token`,
    },
  })

  /**
   * Response middleware
   * Runs after every GraphQL response.
   * Perfect for custom logging or error handling.
   */
  const responseMiddleware = async (
    response: GraphQLClientResponse<unknown> | Error
  ) => {
    if (response instanceof Error) {
      console.error('❌ GraphQL error:', response.message)
    } else {
      console.log('✅ Response received:', response)
    }
  }

  // Apply middlewares to both clients
  for (const c of [client, secondClient]) {
    c.requestConfig.requestMiddleware = requestMiddleware
    c.requestConfig.responseMiddleware = responseMiddleware
  }

  /**
   * Optional: override other requestConfig options
   */
  // client.requestConfig.jsonSerializer = JSON
  // client.requestConfig.body = JSON.stringify({ query: "{ characters { name } }" })
  // client.requestConfig.signal = AbortSignal.timeout(5000)
  // client.requestConfig.window = null
})

👮🏽‍♂️ 认证

您还可以通过不同方式提供认证头

  1. nuxt.config.ts 中设置静态头
export default defineNuxtConfig({
  gqlPulse: {
    clients: {
      default: {
        endpoint: 'https://default.com/graphql',
        options: {
          headers: {
            authorization: 'Bearer TOKEN_HERE',
          },
        },
      },
    },
  },
})
  1. plugins/gqlPulse.ts 中使用 requestMiddleware 设置动态头
const client = useGqlPulseClient('default')

const requestMiddleware = async (request: RequestExtendedInit<Variables>) => {
  const token = await getAuthTokenSomehow()
  return {
    ...request,
    headers: {
      ...request.headers,
      authorization: `Bearer ${token}`,
    },
  }
}

client.requestConfig.requestMiddleware = requestMiddleware
  1. useGqlPulseRequest 选项中设置每个请求的头
const data = await useGqlPulseRequest({
  document,
  client: 'default',
  variables,
  requestOptions: {
    headers: {
      authorization: `Bearer ${token}`,
    },
  },
})
  1. 使用 useGqlPulseClient() 中的 setHeaders()setHeader()
const client = useGqlPulseClient('rickandmortyapi')

// Replace all existing headers
client.setHeaders({
  Authorization: 'Bearer my-secret-token',
  'Content-Type': 'application/json',
})

// Set one header without touching the rest
client.setHeader('x-custom-header', 'my-value')

// Point the client to a different GraphQL endpoint
client.setEndpoint('https://custom-api.example.com/graphql')

🧑‍💻 使用示例

请参阅示例目录以获取更多使用示例

⚙️ 配置详情

gqlPulse.clientsclientName.options 反映了 graffle/graphql-request 中可用的请求选项(headers、method、requestMiddleware、responseMiddleware 等)。有关高级选项和中间件,请参阅 graffle 示例。有关高级请求配置和中间件示例,请参阅 graphql-request / graffle

📑 许可与致谢

本项目建立在并整合了 GraphQL 社区的杰出工作

  • graffle / graphql-request – 内部使用的轻量级 GraphQL 客户端。
    请参阅其仓库以获取许可详情(MIT 兼容)。

本软件包本身根据 MIT 许可证发布。