首页 > 解决方案 > 如何在 Gatsby 中使用 createResovers 将 Markdown FIELD(不是文件)转换为 HTML

问题描述

在 Gatsby 中将 MD 转换为 HTML 的标准过程是针对本地系统上的完整文件。

我需要转换一个特定的字段,而不是一个文件。最相关的问题是这个问题,但正如您所见,它正在使用 Contentful,它现在提供了一个插件来解决它。

我正在使用的 API(Airtable)正在返回一个包含 Markdown 的字段。

推荐的解决方案是使用解析器进行转换......但我无法完全理解 Gatsby文档关于该主题的内容

我在构建时看到的错误是:

UNHANDLED REJECTION Airtable.FAQ provided incorrect OutputType:
 'Object({ resolve: [function resolve], extensions: Object({ createdFrom: "createResolvers" }) })'

我想我已经很接近了,但我不知道我是要创建一个新类型还是解析器实际上要返回什么......一个新字段?

有问题的字段是FAQ,您可以在 GraphQL 资源管理器中的查询示例中看到:

query MyQuery {
  allAirtableManufacturer(filter: {data: {Premium: {eq: true}}}) {
    edges {
      node {
        data {
          Premium
          Manufacturer
          Premium_Manufacturers {
            recordId
            data {
              FAQ
              Downloads_File_Name
              Is_Supplier
            }
            internal {
              type
            }
          }
        }
        recordId
        queryName
      }
    }
  }
}

我的理解是解析器可以/应该添加一个新字段,并将降价内容转换为 html。

所以这是我的解析器代码,您可以在其中看到我正在尝试向 Airtable 节点添加一个名为“FAQ_html”的字段:

  createResolvers({
    Airtable: {
      FAQ_html: {
        resolve(source: any, args: any, context: any, info: any) {
          return remark().use(html).processSync(source.data.FAQ).contents
        },
      },
    }
  })

我的 airtable 的 gatsby-config 是:

    resolve: `gatsby-source-airtable`,
      options: {
        apiKey: process.env.AIRTABLE_API_KEY,
        concurrency: 5,
        tables: [
          {
            baseId: `appP5vBdAitw6yyDH`,
            tableName: `Manufacturers`,
            queryName: `Manufacturer`,
            tableView: `AppView_Details_DONOTCHANGE`,
            tableLinks: [`Premium_Manufacturers`],
            separateNodeType: true,
            defaultValues: {
              Company_Description: '',
            },
          },
          {
            baseId: `appP5vBdAitw6yyDH`,
            tableName: 'Premium_Manufacturers',
            tableLinks: [`Manufacturers`],
          },

        ],

表 'Premium_Manufacturers' 显然作为子级链接到 'Manufacturers'。

然而,当我在 GraphQL 中探索时,我也看到它们显示为一个名为“Airtable”的顶级节点,这是我没想到的。你可以在这里看到:

allAirtable {
    edges {
      node {
        data {
          FAQ
          Downloads_File_Name
          Last_update
          Is_Supplier
          Section_Name
          Section_No
          Name
          Cell_Number
          Email
          Rep_Name
          Technical_Rep_Name
          Consolidated_Rep
        }
      }
    }
  }

这就是为什么我的解析器使用“Airtable”作为节点的名称,但显然它不起作用。

我还尝试更改配置以提供单独的节点:

          {
            baseId: `appP5vBdAitw6yyDH`,
            tableName: 'Premium_Manufacturers',
            queryName: 'Premium',
            separateNodeType: true,
            tableLinks: [`Manufacturers`],
          },

所以现在“allAirtable”变成了“allAirtablePremium”。

我尝试更改解析器以使用它:

  createResolvers({
    allAirtablePremium: {
      FAQ_html: {
        resolve(source: any, args: any, context: any, info: any) {
          return remark().use(html).processSync(source.data.FAQ).contents
        },
      },
    }
  })

但这会引发警告:

warn `createResolvers` passed resolvers for type `allAirtablePremium` that doesn't exist in the schema.

很明显它不喜欢“全部”,所以我将其更改为删除“全部”,如下所示:

  createResolvers({
    AirtablePremium: {
      FAQ_html: {
        resolve(source: any, args: any, context: any, info: any) {
          return remark().use(html).processSync(source.data.FAQ).contents
        },
      },
    }
  })

我又回到了最初的错误,这至少告诉我我试图返回的内容有问题(因为错误清楚地表明“错误的 OutputType”)。

那应该返回什么?

提前感谢您的帮助!

更新 1

代码现在可以编译,但我没有看到我的自定义字段。

这是模式自定义(只需将 FAQ_HTML 创建为空字符串即可):

import { GatsbyNode, CreateSchemaCustomizationArgs } from 'gatsby'

export const createSchemaCustomization: GatsbyNode['createSchemaCustomization'] = async ({
  actions,
}: CreateSchemaCustomizationArgs) => {

  const { createFieldExtension, createTypes } = actions
  createFieldExtension({
    name: "FAQ_HTML",
    extend() {
      return ''
    },
  })

  const typeDefs = `
    type airtablePremium implements Node {
      FAQ_HTML: String @FAQ_HTML
    }
`

  createTypes(typeDefs)
}

解析器现在是这样的:

  createResolvers({
    airtablePremium: {
      FAQ_HTML: {
        resolve(source: any, args: any, context: any, info: any) {
          console.log("SOURCE IS", source)
          const faqHtml = remark().use(html).processSync(source.FAQ).contents
          console.log("faqHtml IS", faqHtml)
          return faqHtml;
        },
      },
    },
  })

它可以编译,但该字段未显示在 GraphQL 资源管理器中。也没有控制台输出。

标签: graphqlgatsbyairtable

解决方案


在与@rmcshry 愉快交谈后,我们确认您需要先创建类型。

createTypes(`
  type AirtablePremium implements Node @infer {
    FAQ_HTML: String
  }
`)

最大的问题是类型名称。在代码中,它应该是AirtablePremiumvs airtablePremium。您可以通过单击左列中的字段名称或按住cmd并单击查询中的字段来查找 GraphiQL 中的类型名称。

您也可以使用类型名createResolvers

  createResolvers({
    AirtablePremium: {
      FAQ_HTML: {
        resolve(source: any, args: any, context: any, info: any) {
          ...
        },
      },
    },
  })

来自@rmcshry 的更新

在@Derek Nguyen 提供了非常有用的帮助后,我找到了一个更简单的替代解决方案。

如果您想避免创建类型的麻烦,您可以使用插件markdown-to-jsx使用更简单的解决方案。

然后你只需包装传入的降价字段:

<Markdown>{field}</Markdown>

它会即时创建一个 React JSX 组件。:)


推荐阅读