NodeJS Gatsby v5和GraphQL:'错误:架构必须包含唯一命名的类型,但包含多个名为“File”的类型,'

cnh2zyt3  于 2023-04-11  发布在  Node.js
关注(0)|答案(1)|浏览(87)

我正在使用Gatsby v5开发我的网站,我目前正在努力解决GraphQL问题。

问题

我使用静态GraphQL查询从一些GitHub存储库中提取 openGraphImageUrl,并在一个card组件中显示每个图像。为了对图像进行更多控制,我编写了一个解析器,它下载 openGraphImageUrl 后面的文件,并将它们作为 File 节点添加到GraphQL数据层,以便我可以使用它们与<GatsbyImage>组件。
这种方法通常是有效的,我可以构建网站,静态查询提供来自存储库的信息。解析器正确地添加了image节点和下载的文件,我可以像预期的那样使用<GatsbyImage>(请参阅下面的内容)
我面临的问题是下面的错误消息,它只发生在我对页面进行更改然后在**成功运行gatsby develop后保存它(例如 index.tsx)**时,但在修改不是页面的单个组件时不会发生(例如 code.tsx -见下文):
调用“building-schema”缺少onError处理程序,错误为“Error:架构必须包含唯一命名的类型,但包含多个名为“File”的类型。
building schema步骤再次运行时(通过将更改保存到页面来触发),这就是错误发生后构建过程卡住的地方。
我已经连续搜索了几个小时来解决这个问题,我也咨询了ChatGPT,但无济于事。我目前仍然是Gatsby,React和Typescript的初学者。
错误消息提示“File”类型被重新定义,我只是不明白为什么会发生这种情况,我做错了什么。我如何避免“File”类型在架构中被重新定义?我的设置如下所示。

设置

gatsby-config.ts

这是我设置访问GitHub的GraphQL API的地方:

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
});

import type { GatsbyConfig } from "gatsby";

const config: GatsbyConfig = {
graphqlTypegen: true,
  plugins: [
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "GitHub",
        fieldName: "github",
        url: "https://api.github.com/graphql",
        headers: {
          Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
        },        
        fetchOptions: {},
      },
    },
    //... skipping the rest
  ],
};

export default config;

gatsby-node.js

解析器的创建如下所示。在GitHub_Repository节点上,它添加一个File类型的image节点,并从存储库的 openGraphImageUrl 下载图像数据。然后将其保存为临时文件,将blob读入缓冲区,然后通过调用createFileNodeFromBuffer()从缓冲区创建实际节点。

const fs = require("fs");
const path = require("path");
const fetch = require("node-fetch");
const { createFileNodeFromBuffer } = require("gatsby-source-filesystem");

exports.createResolvers = async ({
  actions: { createNode },
  createNodeId,
  cache,
  store,
  createResolvers,
}) => {
  const resolvers = {
    GitHub_Repository: {
      image: {
        type: "File",
        resolve: async (source) => {
          const imageUrl = source.openGraphImageUrl;
          const imageNodeId = createNodeId(imageUrl);
          const response = await fetch(imageUrl);
          const buffer = await response.buffer();
          const dirPath = path.join(process.cwd(), "public", "tmp");
          if (!fs.existsSync(dirPath)) {
            fs.mkdirSync(dirPath, { recursive: true });
          }
          const filePath = path.join(
            dirPath,
            imageNodeId,
          );
          fs.writeFileSync(filePath, buffer);
          const fileNode = await createFileNodeFromBuffer({
            buffer,
            store,
            cache,
            createNode,
            createNodeId,
            name: imageNodeId,
          });
          return fileNode;
        },
      },
    },
  };
  createResolvers(resolvers);
};

code.tsx

这就是查询的样子:

function QueryGitHubRepositories(): Repository[] {
  const data: Data = useStaticQuery(graphql`
    {
      github {
        viewer {
          pinnedItems(first: 6, types: REPOSITORY) {
            nodes {
              ... on GitHub_Repository {
                id
                name
                url
                openGraphImageUrl
                image {
                  childImageSharp {
                    gatsbyImageData(layout: FIXED, width: 336, height: 168)
                  }
                }
              }
            }
          }
        }
      }
    }
  `);

  return data.github.viewer.pinnedItems.nodes.map((node) => node);
}

TL;DR

为了完整起见,下面是相关代码的其余部分。

code.tsx (续)

我为查询方法定义了以下类型(也在 code.tsx 中):

type Repository = {
  name?: string | null;
  url?: string | null;
  openGraphImageUrl?: string | null;
  image?: {
    childImageSharp: {
      gatsbyImageData?: any | null;
    };
  } | null;
};

type Data = {
  github: {
    viewer: {
      pinnedItems: {
        nodes: Repository[];
      };
    };
  };
};

这里使用查询数据来构建带有存储库卡的代码部分(也在 code.tsx 中):

import * as React from "react";
import { graphql, useStaticQuery } from "gatsby";
import { GatsbyImage } from "gatsby-plugin-image";

//skipping type definitions and query here, since they're already shown above

const RepositoryCard = ({ repository }: { repository: Repository }) => {
  const imageItem = repository.image?.childImageSharp.gatsbyImageData ?? "";
  const altText = repository.name ?? "repository";

  return (
    <div>
      <a href={repository.url ?? ""} target="_blank">
        <div className="flex h-fit flex-col">
          <GatsbyImage image={imageItem} alt={altText} />
        </div>
      </a>
    </div>
  );
};

const CodeSection = () => {
  const repositories: Repository[] = QueryGitHubRepositories();

  return (
    <div className="w-full">        
      <div className="flex flex-col">
        {repositories.map((repository) => (
          <RepositoryCard key={repository.name} repository={repository} />
        ))}
      </div>
    </div>
  );
};

export default CodeSection;

更新

我也尝试了不同的实现,我看了Paul Scanlon的两篇关于adding data to Gatsby's GraphQL data layermodifying Gatsby's GraphQL data types using createSchemaCustomization的博客文章。然而,我无法正常工作,可能是因为在他的博客文章中,节点是在没有任何源插件的情况下添加的,而我使用的是gatsby-plugin-graphql
欢迎提出替代实现的建议。

nhaq1z21

nhaq1z211#

我找到了一个可行的解决方案。我只需要将gatsby-source-graphql替换为gatsby-source-github-api,因为前者显然不支持增量构建:

gatsby-config.ts

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
});

import type { GatsbyConfig } from "gatsby";

const config: GatsbyConfig = {
graphqlTypegen: true,
  plugins: [
    {
      resolve: `gatsby-source-github-api`,
      options: {
        url: "https://api.github.com/graphql",      
        token: `${process.env.GITHUB_TOKEN}`,
        graphQLQuery: `
          query{
            user(login: "someUserName") {
              pinnedItems(first: 6, types: [REPOSITORY]) {
                edges {
                  node {
                    ... on Repository {
                      name
                      openGraphImageUrl
                    }
                  }
                }
              }
            }
          }`
      }
    },
    //... skipping the rest
  ],
};

export default config;

gatsby-node.js

const fs = require("fs");
const path = require("path");
const fetch = require("node-fetch");
const { createFileNodeFromBuffer } = require("gatsby-source-filesystem");

exports.createResolvers = async ({
  actions: { createNode },
  createNodeId,
  cache,
  store,
  createResolvers,
}) => {
  const resolvers = {
    GithubDataDataUserPinnedItemsEdgesNode: {
      image: {
        type: "File",
        resolve: async (source) => {
          const imageUrl = source.openGraphImageUrl;
          const imageNodeId = createNodeId(imageUrl);
          const response = await fetch(imageUrl);
          const buffer = await response.buffer();
          const dirPath = path.join(process.cwd(), "public", "tmp");
          if (!fs.existsSync(dirPath)) {
            fs.mkdirSync(dirPath, { recursive: true });
          }
          const filePath = path.join(
            dirPath,
            imageNodeId,
          );
          fs.writeFileSync(filePath, buffer);
          const fileNode = await createFileNodeFromBuffer({
            buffer,
            store,
            cache,
            createNode,
            createNodeId,
            name: imageNodeId,
          });
          return fileNode;
        },
      },
    },
  };
  createResolvers(resolvers);
};

code.tsx

类型定义

type Repository = {
  openGraphImageUrl?: string | null;
  image?: {
    childImageSharp?: {
      gatsbyImageData?: any | null;
    } | null;
  } | null;
};

type Data = {
  githubData: {
    data: {
      user: {
        pinnedItems: {
          edges: {
            node: Repository;
          }[];
        };
      };
    };
  };
};

查询

function QueryGitHubRepositories(): Repository[] {
  const data: Data = useStaticQuery(graphql`
    {
      githubData {
        data {
          user {
            pinnedItems {
              edges {
                node {
                  openGraphImageUrl
                  image {
                    childImageSharp {
                      gatsbyImageData
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  `);

  const repos = data.githubData.data.user.pinnedItems.edges.map(
    (edge) => edge.node
  );

  return repos;
}

相关问题