如何为Gatsby提供GraphQL架构

时间:2018-06-09 01:47:22

标签: javascript reactjs graphql gatsby

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

  

Where does Gatsby’s GraphQL schema come from?   使用Gatsby,我们使用从不同来源获取数据的插件。然后,我们使用该数据自动推断GraphQL架构。

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

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

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

Gatsby config:

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

3 个答案:

答案 0 :(得分:3)

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

我有一堆.md,其前题如下:

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

...content...

如果盖茨比首先以空白图片进入.md,即使该字段应该为String,也会错误地将该字段推断为File。使用新的API,我可以将gatsby-node.js中的图片字段告诉Gatsby:

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

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

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

一些注意事项:

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

答案 1 :(得分:0)

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

我的网站使用Gatsby-source-Wordpress插件以及Sharp库以及Bluebird来返回承诺等。 在Post.js或Page.js上定义ImageURL。当将源URL加载到我的媒体库中时,会产生源URL,但由于我的WordPress网站是“以编程方式”构建的,因此已被卸载到S3存储桶中。 源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.使用图片网址查询退货。 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
                }
            }
        }
    }

`

希望这可以随时向我发送消息。

答案 2 :(得分:0)

有一个插件,很棒。我专门将其与Wordpress源插件一起使用。

请注意,您可能还需要在根目录中添加一个graphql.config.json文件,以使IDE能够正确拾取它:

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