立即迁移到 Netlify

Netlify 宣布 Gatsby Cloud 的下一次迭代。 了解更多

联系我们注册
官方插件
在 GitHub 上查看插件

gatsby-source-graphql

⚠️ 警告

如果您的内容源已有源插件(例如 WordPress 的 gatsby-source-wordpress、Contentful 的 gatsby-source-contentful 等),则不建议使用此插件。此插件有已知限制,具体来说,它不支持增量构建、CMS 预览、图片优化,并且缺乏对 GraphQL 数据层的完整支持。请仅将其用于简单的概念验证,并且在您的数据源没有现有源插件的情况下使用。

描述

用于将任意 GraphQL API 连接到 Gatsby 的 GraphQL 的插件。通过声明一个包装远程 schema 查询类型的任意类型名称(下文的 typeName),并将远程 schema 放在 Gatsby GraphQL 查询的字段下(下文的 fieldName),即可将远程 schema 缝合在一起。

已知限制

  • ⚠️ **不支持**增量构建
    • 这可能导致严重的构建速度问题,特别是对于大型、内容丰富的网站
  • ⚠️ **不支持** CMS 预览 和内容/API 更新的实时预览
  • ⚠️ **对** GraphQL 数据层**不支持完整**,包括图片优化/图片 CDN 和指令支持

安装

npm install gatsby-source-graphql

如何使用

如果远程 GraphQL API 需要身份验证,您应该将环境变量传递给构建过程,以免凭据提交到源代码管理。我们推荐使用dotenv,它会公开环境变量。在此处阅读有关 dotenv 和使用环境变量的更多信息。然后我们可以通过 process.env *使用*这些环境变量并配置我们的插件。

// In your gatsby-config.js
module.exports = {
  plugins: [
    // Simple config, passing URL
    {
      resolve: "gatsby-source-graphql",
      options: {
        // Arbitrary name for the remote schema Query type
        typeName: "SWAPI",
        // Field under which the remote schema will be accessible. You'll use this in your Gatsby query
        fieldName: "swapi",
        // Url to query from
        url: "https://swapi-graphql.netlify.app/.netlify/functions/index",
      },
    },

    // Advanced config, passing parameters to apollo-link
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "GitHub",
        fieldName: "github",
        url: "https://api.github.com/graphql",
        // HTTP headers
        headers: {
          // Learn about environment variables: https://gatsby.dev/env-vars
          Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
        },
        // HTTP headers alternatively accepts a function (allows async)
        headers: async () => {
          return {
            Authorization: await getAuthorizationToken(),
          }
        },
        // Additional options to pass to node-fetch
        fetchOptions: {},
      },
    },

    // Advanced config, using a custom fetch function
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "GitHub",
        fieldName: "github",
        url: "https://api.github.com/graphql",
        // A `fetch`-compatible API to use when making requests.
        fetch: (uri, options = {}) =>
          fetch(uri, { ...options, headers: sign(options.headers) }),
      },
    },

    // Complex situations: creating arbitrary Apollo Link
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "GitHub",
        fieldName: "github",
        // Create Apollo Link manually. Can return a Promise.
        createLink: pluginOptions => {
          return createHttpLink({
            uri: "https://api.github.com/graphql",
            headers: {
              Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
            },
            fetch,
          })
        },
      },
    },
  ],
}

如何查询

{
  # This is the fieldName you've defined in the config
  swapi {
    allSpecies {
      name
    }
  }
  github {
    viewer {
      email
    }
  }
}

Schema 定义

默认情况下,schema 会从远程 schema 中进行内省。Schema 缓存在 .cache 目录中,刷新 schema 需要删除缓存(例如,通过重启 gatsby develop)。

为了控制 schema 的消耗,您可以选择通过传递 createSchema 回调来构建 schema 定义。这样,您就可以例如读取 schema SDL 或内省 JSON。当使用 createSchema 回调时,schema 不会被缓存。createSchema 可以返回一个 GraphQLSchema 实例,或者一个解析到该实例的 Promise。

const fs = require("fs")
const { buildSchema, buildClientSchema } = require("graphql")

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",

        createSchema: async () => {
          const json = JSON.parse(
            fs.readFileSync(`${__dirname}/introspection.json`)
          )
          return buildClientSchema(json.data)
        },
      },
    },
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",

        createSchema: async () => {
          const sdl = fs.readFileSync(`${__dirname}/schema.sdl`).toString()
          return buildSchema(sdl)
        },
      },
    },
  ],
}

网络请求可能会失败、返回错误或花费太长时间。使用 Apollo Link 为您的 GraphQL 请求添加重试、错误处理、日志记录等功能。

使用插件的 createLink 选项为您的 GraphQL 请求添加自定义 Apollo Link。

您可以组合不同类型的 links,具体取决于您想实现的功能。最常见的 links 是

  • @apollo/client/link/retry 用于重试失败或超时的查询
  • @apollo/client/link/error 用于错误处理
  • @apollo/client/link/http 用于在 HTTP 请求中发送查询(默认使用)

有关 Apollo Links 如何协同工作的更多解释,请查看这篇 Medium 文章:Productionizing Apollo Links

以下是使用 HTTP Link 并进行重试(使用 @apollo/client/link/retry)的示例

// gatsby-config.js
const { createHttpLink, from } = require(`@apollo/client`)
const { RetryLink } = require(`@apollo/client/link/retry`)

const retryLink = new RetryLink({
  delay: {
    initial: 100,
    max: 2000,
    jitter: true,
  },
  attempts: {
    max: 5,
    retryIf: (error, operation) =>
      Boolean(error) && ![500, 400].includes(error.statusCode),
  },
})

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",

        // `pluginOptions`: all plugin options
        //   (i.e. in this example object with keys `typeName`, `fieldName`, `url`, `createLink`)
        createLink: pluginOptions =>
          from([retryLink, createHttpLink({ uri: pluginOptions.url })]),
      },
    },
  ],
}

自定义 schema 转换函数(高级)

可以通过 transformSchema 选项修改远程 schema,该选项用于自定义默认 schema 在被缝合过程合并到 Gatsby schema 之前的方式。

transformSchema 函数接收一个对象参数,该对象具有以下字段:

  • schema(内省的远程 schema)
  • link(默认 link)
  • resolver(默认 resolver)
  • defaultTransforms(一个包含默认转换的数组)
  • options(插件选项)

返回值应为用于缝合的最终 schema。

以下是一个使用默认实现的示例配置(等同于不使用 transformSchema 选项)

const { wrapSchema } = require(`@graphql-tools/wrap`)
const { linkToExecutor } = require(`@graphql-tools/links`)

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",
        transformSchema: ({
          schema,
          link,
          resolver,
          defaultTransforms,
          options,
        }) => {
          return wrapSchema(
            {
              schema,
              executor: linkToExecutor(link),
            },
            defaultTransforms
          )
        }
    },
  ]
}

有关详细信息,请参阅 https://www.graphql-tools.com/docs/schema-wrapping

可以在此 issue中看到此功能的一个用例。

重新获取数据

默认情况下,gatsby-source-graphql 只会在服务器重启后重新获取数据。还可以配置插件以定期重新获取数据。该选项称为 refetchInterval,以秒为单位指定超时时间。

module.exports = {
  plugins: [
    // Simple config, passing URL
    {
      resolve: "gatsby-source-graphql",
      options: {
        // Arbitrary name for the remote schema Query type
        typeName: "SWAPI",
        // Field under which the remote schema will be accessible. You'll use this in your Gatsby query
        fieldName: "swapi",
        // Url to query from
        url: "https://api.graphcms.com/simple/v1/swapi",

        // refetch interval in seconds
        refetchInterval: 60,
      },
    },
  ],
}

性能调优

默认情况下,gatsby-source-graphql 会在单独的网络请求中执行每个查询。但该插件也支持查询批处理以提高查询性能。

注意:批处理仅适用于大致同时开始的查询。换句话说,它受 Gatsby 执行的并行 GraphQL 查询数量的限制(默认值为 **4**)。

幸运的是,我们可以通过将环境变量 GATSBY_EXPERIMENTAL_QUERY_CONCURRENCY 设置为更高的值,并将插件的 batch 选项设置为 true 来增加并行执行的查询数量。

示例

cross-env GATSBY_EXPERIMENTAL_QUERY_CONCURRENCY=20 gatsby develop

通过插件配置

const fs = require("fs")
const { buildSchema, buildClientSchema } = require("graphql")

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",
        batch: true,
      },
    },
  ],
}

默认情况下,插件会批处理最多 5 个查询。您可以将 dataLoaderOptions 传递并设置 maxBatchSize 来覆盖此设置。

const fs = require("fs")
const { buildSchema, buildClientSchema } = require("graphql")

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "SWAPI",
        fieldName: "swapi",
        url: "https://api.graphcms.com/simple/v1/swapi",
        batch: true,
        // See https://github.com/graphql/dataloader#new-dataloaderbatchloadfn--options
        // for a full list of DataLoader options
        dataLoaderOptions: {
          maxBatchSize: 10,
        },
      },
    },
  ],
}

拥有 20 个并行查询,每个批次 5 个查询,意味着我们仍然并行运行 4 个批次。

每个项目都是独一无二的,因此请尝试调整这两个变量,看看哪种最适合您。我们发现某些设置的速度提升了 5-10 倍。

批处理工作原理

在底层,gatsby-source-graphql 使用 DataLoader 进行查询批处理。它将批次中的所有查询合并为一个查询,该查询在单个网络请求中发送到服务器。

考虑以下同时运行这两个查询的示例

{
  query: `query(id: Int!) {
    node(id: $id) {
      foo
    }
  }`,
  variables: { id: 1 },
}
{
  query: `query(id: Int!) {
    node(id: $id) {
      bar
    }
  }`,
  variables: { id: 2 },
}

它们将被合并为一个查询

{
  query: `
    query(
      $gatsby0_id: Int!
      $gatsby1_id: Int!
    ) {
      gatsby0_node: node(id: $gatsby0_id) {
        foo
      }
      gatsby1_node: node(id: $gatsby1_id) {
        bar
      }
    }
  `,
  variables: {
    gatsby0_id: 1,
    gatsby1_id: 2,
  }
}

然后 gatsby-source-graphql 将此单个查询的结果拆分为多个结果,并将其传递回 Gatsby,就好像它执行了多个查询一样。

{
  data: {
    gatsby0_node: { foo: `foo` },
    gatsby1_node: { bar: `bar` },
  },
}

被转换回

[
  { data { node: { foo: `foo` } } },
  { data { node: { bar: `bar` } } },
]

请注意,如果任何查询结果包含错误,整个批次将失败。

Apollo 风格批处理

如果您的服务器支持 Apollo 风格的查询批处理,您还可以尝试 HttpLinkDataLoader。通过 createLink 选项将其传递给 gatsby-source-graphql 插件。

这种策略通常比查询合并慢,但提供了更好的错误报告。

©2025Gatsby, Inc.