如何为 Gatsby 提供 GraphQL 模式

How to give Gatsby a GraphQL schema

我们从 Wordpress 后端引入了一些帖子,有些有图片(在 ACF 字段中),有些没有。问题是 Gatsby 根据它接收到的第一个节点来推断模式。如果它收到一个没有图片的节点,那么schema是错误的。

Where does Gatsby’s GraphQL schema come from? With Gatsby, we use plugins which fetch data from different sources. We then use that data to automatically infer a GraphQL schema.

我们如何为 GraphQL/Gatsby 指定一个始终包含图片的架构,如果它是空白的,则将 'null' 作为默认值?

{
  allWordpressWpTestimonial {
    edges {
      node {
        id
        title
        acf {
          photo_fields {
            photo {
              id
              localFile {
                childImageSharp {
                  sizes {
                    src
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

在上面的示例中,有时 'photo' 不存在并且它破坏了一切...

盖茨比配置:

const innertext = require('innertext')
const url = require('url')

module.exports = {
  siteMetadata: {
    title: 'Test',
    googleMapsAPIKey: 'xxxxxx',
    adminBaseUrl: '123.123.123',
    adminProtocol: 'http',
  },
  pathPrefix: '/web/beta',
  plugins: [
    'gatsby-plugin-react-next',
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sharp',
    'gatsby-plugin-svgr',
    {
      resolve: 'gatsby-plugin-google-analytics',
      options: {
        trackingId: 'GOOGLE_ANALYTICS_TRACKING_ID',
      },
    },
    {
      resolve: 'gatsby-plugin-bugherd',
      options: {
        key: 'xxxxxx',
        showInProduction: true,
      },
    },
    {
      resolve: '@andrew-codes/gatsby-plugin-elasticlunr-search',
      options: {
        fields: ['title', 'url', 'textContent', 'urlSearchable'],
        resolvers: {
          wordpress__PAGE: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => url.parse(node.link).path,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
          wordpress__POST: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => `/news/${node.slug}`,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
          wordpress__wp_industry: {
            title: node => node.title,
            textContent: node => innertext(node.content),
            url: node => `/business/industries/${node.slug}`,
            urlSearchable: node =>
              url
                .parse(node.link)
                .path.split('/')
                .join(' '),
          },
        },
      },
    },
    {
      resolve: 'gatsby-source-wordpress',
      options: {
        baseUrl: 'xxxxxx',
        protocol: 'http',
        hostingWPCOM: false,
        useACF: true,
        auth: {
          htaccess_user: 'admin',
          htaccess_pass: 'xxxxxx',
          htaccess_sendImmediately: false,
        },
        verboseOutput: false,
      },
    },
    'gatsby-transformer-sharp',
  ],
}

首先,您使用的是 Gatsby-plugin-sharp、Gatsby-transform-sharp 和 Gatsby-source-WordPress 插件吗?

我的网站使用 Gatsby-source-Wordpress 插件加上 sharp 库以及 Bluebird 来实现 returning promises 等。 在 Post.js 或 Page.js 上定义图像 URL。源文件 URL 是在我的媒体库中加载时生成的,但由于我的 WordPress 网站已构建 "programmatically" 而被卸载到 S3 存储桶。 来源 URL 通常由您定义,可以在构建 post 页面模板时在 ACF 字段类型中选择。

export const pageQuery = graphql`
  query homePageQuery {
    site {
      siteMetadata {
        title
        subtitle
        description
      }
    }

    allWordpressPost(sort: { fields: [date] }) {
      edges {
        node {
          title
          excerpt
          slug
          type
          _image{
            source_url
          }
          categories {
            slug
            name
          }
        }
      }
    }
  } 

对于每个 post 类型,必须以准确的顺序查询数据,否则 GraphQL 将不会 return 正确的方案,这将产生错误。 听起来很简单且重复,有时必须有两种不同的 GraphQL 方案和两个 post.js 示例 post1.js 和 post2.js 文件定义不同的 post 类别。 1.Query 对于 return 和图像 URL。 2.Query 对于没有图像的 return。等于 null 或不存在 这是 GraphQL 的缺点,它期望收到 X,当 Y 发生时,它变得不高兴并失败。

当您收到图像时,您也可以尝试此操作,将其使用 sharp 转换为 href=,并将其从 https 转换为在 receiving.But 上调整大小,在您的情况下,方案为 null。 我们为来自旧 WordPress 网站的 return 的员工简历页面执行此操作。

/**
     * Transform internal absolute link to relative.
     * 
     * @param {string} string The HTML to run link replacemnt on
     */
    linkReplace(string) {
        // console.log(string)
        const formatted = string.replace(
            /(href="https?:\/\/dev-your-image-api\.pantheonsite\.io\/)/g,
            `href="/`
        )

        return formatted
    }

    render() {
        const post = { ...this.props.data.wordpressPost }
        const headshot = { ...this.props.data.file.childImageSharp.resolutions }
        const { percentScrolled } = { ...this.state }
        const contentFormatted = this.linkReplace(post.content)

        return (
            <div ref={el => (this.post = el)}>
                <div className={styles.progressBarWrapper}>
                    <div
                        style={{ width: `${percentScrolled}%` }}
                        className={styles.progressBar}
                    />
                </div>

                <div className={styles.post}>
                    <h1
                        className={styles.title}
                        dangerouslySetInnerHTML={{ __html: post.title }}
                    />

                    <div
                        className={styles.content}
                        dangerouslySetInnerHTML={{ __html: contentFormatted }}
                    />

                    <Bio headshot={headshot} horizontal={true} />
                </div>
            </div>
        )
    }
}

Post.propTypes = {
    data: PropTypes.object.isRequired,
}

export default Post

export const postQuery = graphql`
    query currentPostQuery($id: String!) {
        wordpressPost(id: { eq: $id }) {
            wordpress_id
            title
            content
            slug
        }
        file(relativePath: { eq: "your-image-headshot.jpg" }) {
            childImageSharp {
                resolutions(width: 300, height: 300) {
                    ...GatsbyImageSharpResolutions
                }
            }
        }
    }

`

希望这对您有所帮助,请随时给我发消息。

这个 post 已经有一段时间了,但是从 2.2 版 Gatsby has added a new API 开始,这将使自定义架构变得更加容易。这不是 wordpress 的示例,而是 gatsby 的 gatsby-transformer-remark,但我确定它是适用的。

我有一堆 .md 的 frontmatter 看起来像这样:

---
title: "Screen title"
image: "./hero-image.png"  <--- sometimes it's an empty string, ""
category: "Cat"
---

...content...

如果 Gatsby 先到达带有空图像的 .md,它会错误地将那个字段推断为 String,即使它应该是 File。使用新的 API,我可以告诉 Gatsby 关于 gatsby-node.js 中的图像字段:

exports.sourceNodes = ({ actions, schema }) => {
  const { createTypes } = actions
  createTypes(`
    type MarkdownRemarkFrontmatter {
      image: File
    }

    type MarkdownRemark implements Node {
      frontmatter: MarkdownRemarkFrontmatter
    }
  `)
}

这将保证 image 字段始终为文件类型,否则将为 null

一些注意事项:

  • MarkdownRemark 这样的根节点必须实现 Node
  • 一个节点可以实现多个接口
  • 您必须 'work your way' 到相关字段。在此示例中,我必须声明 MarkdownRemarkFrontmatter 类型,然后将其传递给 MarkdownRemark 节点中的 frontmatter 字段。
  • 如果未指定,Gatsby 将推断其余字段。在上面的示例中,由于我没有在 MarkdownRemarkFrontmatter 中指定 category 字段,所以它会像以前一样由 Gatsby 推断。
  • 查找这些类型(MarkdownRemarkMarkdownRemarkFrontmatter)最有用的方法是在 graphiql 中查找它们(默认为 localhost:8000/___graphql