gpt4 book ai didi

graphql - 使用 Gatsby 在 Markdown 帖子中为特色图像使用绝对路径

转载 作者:行者123 更新时间:2023-12-04 01:41:45 25 4
gpt4 key购买 nike

我已经关注了 Working With Images in Markdown Posts and Pages 的 Gatsby 教程这运行良好,但我想要实现的是从静态位置获取图像,而不是使用图像的相对路径。

想引用这样的图像(在前面)

featuredImage: img/IMG_20190621_112048_2.jpg

哪里 IMG_20190621_112048_2.jpg /src/data/img而不是与 /src/posts 下的 markdown 文件相同的目录

我试过设置 gatsby-source-filesystem像这样 :
{
resolve: `gatsby-source-filesystem`,
options: {
name: `posts`,
path: `${__dirname}/src/posts`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `data`,
path: `${__dirname}/src/data/`,
},
},

但 post 模板中的 graphQL 查询失败:
export const query = graphql`
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
html
frontmatter {
title
featuredImage {
childImageSharp {
fluid(maxWidth: 800) {
...GatsbyImageSharpFluid
}
}
}
}
}
}

GraphQL Error Field "featuredImage" must not have a selection since type "String" has no subfields.



知道如何从与 post markdown 目录不同的位置获取图像吗?

最佳答案

在 Gatsby 中实现这一点曾经非常麻烦,但多亏了新的 createSchemaCustomization Node API docs(自 Gatsby 2.5 以来),这相对容易。
这是我复制您的 repo 结构的演示:github
这是相关代码所在的位置:github
这是使其工作的代码:

// gatsby-node.js

const path = require('path')

exports.createSchemaCustomization = ({ actions }) => {
const { createFieldExtension, createTypes } = actions

createFieldExtension({
name: 'fileByDataPath',
extend: () => ({
resolve: function (src, args, context, info) {
const partialPath = src.featureImage
if (!partialPath) {
return null
}

const filePath = path.join(__dirname, 'src/data', partialPath)
const fileNode = context.nodeModel.runQuery({
firstOnly: true,
type: 'File',
query: {
filter: {
absolutePath: {
eq: filePath
}
}
}
})

if (!fileNode) {
return null
}

return fileNode
}
})
})

const typeDefs = `
type Frontmatter @infer {
featureImage: File @fileByDataPath
}

type MarkdownRemark implements Node @infer {
frontmatter: Frontmatter
}
`

createTypes(typeDefs)
}
这个怎么运作:
这有两个部分:
  • 扩展 markdownRemark.frontmatter.featureImage 因此 graphql 通过 createTypes
  • 解析为文件节点而不是字符串
  • 通过 @fileByDataPath
  • 创建新的字段扩展 createFieldExtension
    创建类型
    现在 Gatsby 将 frontmatter.featureImage 推断为字符串。我们将要求 Gatsby 将 featureImage 作为字符串读取,通过修改其父类型:
      type Frontmatter {
    featureImage: File
    }
    然而,这还不够,我们还需要将此 Frontmatter 类型传递给其父类型:
      type Frontmatter {
    featureImage: File
    }

    type MarkdownRemark implements Node {
    frontmatter: Frontmatter
    }
    我们还将添加 @infer 标签,它让 Gatsby 知道它可以推断这些类型的其他字段,即 frontmatter.titlemarkdownRemark.html 等。
    然后将这些自定义类型传递给 createTypes :
    exports.createSchemaCustomization = ({ actions }) => {
    const { createTypes } = actions

    const typeDefs = `
    type Frontmatter @infer {
    featureImage: File
    }

    type MarkdownRemark implements Node @infer {
    frontmatter: Frontmatter
    }
    `

    createTypes(typeDefs)
    }
    现在,我们可以启动 localhost:8000/___graphql 并尝试查询图像
    query Post {
    markdownRemark {
    frontmatter {
    featureImage {
    id
    }
    }
    }
    }
    我们得到...

    Error: Cannot return null for non-nullable field File.id.


    这是因为虽然 Gatsby 现在知道 featureImage 应该是一个 File 节点,但它不知道从哪里获取该文件。
    此时,我们可以使用 createResolvers 手动将字段解析为 File 节点,或者使用 createFileExtension 来做同样的事情。我选择 createFileExtension 是因为它允许更多的代码重用(您可以扩展任何字段),而在这种情况下, createResolvers 对特定字段更有用。看到您想要的只是解析 src/data 目录中的文件,我将此扩展名为 fieldByDataPath
    创建文件扩展名
    让我们看看解析属性。它是一个接受以下内容的函数:
  • 来源:父字段的数据(本例中为 frontmatter )
  • args:在查询中传递给 featureImage 的参数。我们不需要这个
  • 上下文:包含 nodeModel ,我们将使用它从 Gatsby 节点存储
  • 获取节点
  • 信息:关于该字段的元数据 + 整个架构

  • 我们将从 img/photo.jpg 找到原始路径( src.featureImage ),然后将其粘贴到 src/data 以获得完整的绝对路径。接下来,我们查询 nodeModel 以找到具有匹配绝对路径的 File 节点。由于您已经将 gatsby-source-filesystem 指向 src/data ,因此图像 (photo.jpg) 将位于 Gatsby 节点存储中。
    如果我们找不到路径或匹配的节点,请返回 null
      resolve: async function (src, args, context) {
    // look up original string, i.e img/photo.jpg
    const partialPath = src.featureImage
    if (!partialPath) {
    return null
    }

    // get the absolute path of the image file in the filesystem
    const filePath = path.join(__dirname, 'src/data', partialPath)

    // look for a node with matching path
    const fileNode = await context.nodeModel.runQuery({
    firstOnly: true,
    type: 'File',
    query: {
    filter: {
    absolutePath: {
    eq: filePath
    }
    }
    }
    })

    // no node? return
    if (!fileNode) {
    return null
    }

    // else return the node
    return fileNode
    }
    我们已经完成了 99% 的工作。最后要做的是将其移动以将此解析函数传递给 createFieldExtension ;以及将新扩展添加到 createTypes
    createFieldExtension({
    name: 'fileByDataPath' // we'll use it in createTypes as `@fileByDataPath`
    extend: () => ({
    resolve, // the resolve function above
    })
    })

    const typeDef = `
    type Frontmatter @infer {
    featureImage: File @fileByDataPath // <---
    }
    ...
    `
    有了这个,您现在可以在 frontmatter 中使用来自 src/data/ 的相对路径。
    额外的 fileByDataPath 的实现方式,它只适用于名为 featureImage 的字段。这不是很有用,所以我们应该修改它,使其适用于任何名称以 _data 结尾的字段;或者至少接受要处理的字段名称列表。
    编辑 有一点时间在我手上,所以我 wrote a plugin 这样做了,还有 wrote a blog on it
    Edit 2 Gatsby 此后使 runQuery 异步(2020 年 7 月),更新了答案以反射(reflect)这一点。

    关于graphql - 使用 Gatsby 在 Markdown 帖子中为特色图像使用绝对路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57152625/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com