繁体   English   中英

如何为Gatsby提供GraphQL架构

[英]How to give Gatsby a GraphQL schema

我们从Wordpress后端引入一些帖子,有些有图片(在ACF字段中),有些则没有。 问题是盖茨比根据它收到的第一个节点推断出架构。 如果它收到没有图片的节点,那么架构是错误的。

Gatsby的GraphQL架构来自哪里? 使用Gatsby,我们使用从不同来源获取数据的插件。 然后,我们使用该数据自动推断GraphQL架构。

我们怎样才能为GraphQL / Gatsby指定一个总是包含图片的模式,如果它是空白的话,将'null'作为默认值?

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

在上面的例子中,有时候“照片”不存在,它会破坏一切......

盖茨比配置:

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',
  ],
}

自从这篇文章发布以来已经有一段时间了,但是从版本2.2开始, Gatsby已经添加了一个新的API ,它将使定制架构变得更加容易。 这不是wordpress的例子,而是gatsby的gatsby-transformer-remark ,但我确信它是适用的。

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

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

...content...

如果Gatsby首先使用空图像到达.md ,它将错误地将该字段推断为String ,即使它应该是File 使用新的API,我可以告诉盖茨比关于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
  • 一个节点可以实现多个接口
  • 你必须“按照自己的方式”进入相关领域。 在此示例中,我必须声明MarkdownRemarkFrontmatter类型,然后将其传递给MarkdownRemark节点中的frontmatter字段。
  • 如果没有指定,Gatsby将推断其余的字段。 在上面的示例中,由于我没有在MarkdownRemarkFrontmatter指定category字段,因此Gatsby将像以前一样推断出它。
  • 找到这些类型( MarkdownRemarkMarkdownRemarkFrontmatter )最有用的方法是在graphiql中查找它们(默认为localhost:8000/___graphql

首先是你使用Gatsby-plugin-sharp,Gatsby-transform-sharp和Gatsby-source-WordPress插件?

我的网站使用Gatsby-source-Wordpress插件加上尖锐的库以及Bluebird来返回承诺等。在Post.js或Page.js上定义ImageURL。 源URL在我的媒体库中加载时生成,但是被卸载到S3存储桶,因为我的WordPress网站是“以编程方式”构建的。 源URL通常由您定义,并且在构建页面模板的帖子时可以在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
          }
        }
      }
    }
  } 

每个帖子类型都必须按照确切的顺序查询数据,否则GraphQL将无法正确返回方案,这将产生错误。 虽然听起来很简单并且重复,但有时会有两种不同的GraphQL方案和两种post.js示例post1.js和post2.js文件定义不同的帖子类别。 1.使用图像URL返回的查询。 2.没有图像的返回查询。 等于null或不存在这是GraphQL的垮台,它期望接收X,当Y发生时,它会变得不快乐并失败。

当你收到图像时,你也可以尝试使用sharp将其转换为href =并将其从https转换为接收时的大小。但在你的情况下,它将为null。 我们这样做是为了从旧的WordPress网站返回的员工生物页面。

/**
     * 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
                }
            }
        }
    }

`

希望这有助于随时给我发消息。

有一个插件,它很棒。 我特意将它与Wordpress源插件一起使用。

请注意,您可能还需要将graphql.config.json文件添加到根目录,以便IDE正确选择它:

{
  "schema": {
    "file": "schema.json"
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM