使用Gatsby在Markdown发布中使用特色图片的绝对路径

阿维亚尼

我遵循了Gatsby教程,教程在Markdown文章和Pages中使用图像,效果很好,但是我想要实现的是从静态位置获取图像,而不是使用图像的相对路径。

想参考这样的图像(在前)

featuredImage: img/IMG_20190621_112048_2.jpg

IMG_20190621_112048_2.jpg/src/data/img不是同一个目录下的文件降价/src/posts

我试图这样设置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/`,
  },
},

但是帖子模板中的graphQL查询失败:

export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
        featuredImage {
          childImageSharp {
            fluid(maxWidth: 800) {
              ...GatsbyImageSharpFluid
            }
          }
        }
      }
    }
  }

GraphQL错误字段“ featuredImage”必须没有选择,因为类型“ String”没有子字段。

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

德里克·阮

在Gatsby中实现此功能以前是很麻烦的,但是由于有了新的createSchemaCustomizationNode API文档(自Gatsby 2.5起),它相对容易。

这是一个演示,您可以在其中复制您的回购结构: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)
}

这个怎么运作:

分为两个部分:

  1. 扩展,markdownRemark.frontmatter.featureImage以便graphql通过以下方式解析为File节点而不是字符串createTypes
  2. 创建一个新的领域延伸@fileByDataPath通过createFieldExtension

createTypes

现在,盖茨比将其推断frontmatter.featureImage为字符串。我们将要求Gatsby通过修改其父类型来将featureImage读取为字符串:

  type Frontmatter {
    featureImage: File
  }

但是,这还不够,我们还需要将此Frontmatter类型传递给其父级:

  type Frontmatter {
    featureImage: File
  }

  type MarkdownRemark implements Node {
    frontmatter: Frontmatter
  }

我们还将添加@infer标记,让Gatsby知道它可以推断出这些类型的其他字段frontmatter.title,例如markdownRemark.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
      }
    }
  }
}

我们得到...

错误:无法为非空字段File.id返回null。

这是因为尽管盖茨比现在知道featureImage应该是“文件”节点,但是却不知道从何处获取该文件。

此时,我们可以使用createResolvers手动将字段解析为“文件”节点,或者createFileExtension执行相同的操作。createFileExtension之所以选择它,是因为它允许更多的代码重用(您可以扩展任何字段),而createResolvers在这种情况下,它对特定字段更有用。看到您只想从src/data目录中解析文件,我将其称为扩展名fieldByDataPath

createFileExtension

让我们看一下resolve属性。该函数具有以下功能:

  • 来源:父字段的数据(在本例中为frontmatter
  • args:featureImage在查询中传递给的参数我们不需要这个
  • context:contains nodeModel,我们将使用它从Gatsby节点存储中获取节点
  • info:有关此字段的元数据+整个架构

我们将从中找到原始路径(img/photo.jpgsrc.featureImage,然后将其粘贴src/data以获取完整的绝对路径。接下来,我们查询nodeModel以查找具有匹配的绝对路径的File节点。既然你已经指出gatsby-source-filesystemsrc/data,图像(photo.jpg)将在盖茨比节点商店。

如果我们找不到路径或匹配的节点,请返回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 // <---
  }
  ...
`

这样,您现在就可以使用src/data/frontmatter中的相对路径了。

额外

fileByDataPath实施方式仅适用于名为的字段featureImage这不是太有用,所以我们应该对其进行修改,以使其可以在名称以_data;结尾的任何字段上使用或至少接受要处理的字段名称列表。

Edit的时间很有限,所以我编写了一个插件来完成此任务,并为此写了博客

此后,“编辑2盖茨比”已实现runQuery异步(2020年7月),更新了答案以反映这一点。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

图片具有绝对路径-如何在LaravelMix中使用子目录URL

dotnet 使用绝对路径发布不尊重输出

在 Angular 2 + Electron 中使用绝对路径

在绝对路径中使用通配符创建文件

在Rails 6中使用绝对路径

Rails:在 Rails 6 中使用绝对路径

使用 Pathlib 确定绝对路径

无法使用绝对路径导入

对ClassLoader使用绝对路径getResourceAsStream()

Gatsby Link 绝对路径

在使用ParcelJS构建的Cypress测试中,如何在绝对路径中使用导入?

如何在 React 或 Next.js 中使用绝对路径而不是相对路径?

为什么在webpack的输出属性的入口点和绝对路径中使用相对路径?

强制 OpenWindow 使用绝对路径而不使用 http

如何在Spring MVC中使用绝对路径加载图像?

如何在 Katalon Studio 中使用 TestDataFactory 获取绝对路径

如何在Linux中使用'find'命令获取找到的文件的绝对路径?

在打字稿中使用绝对路径进行导入

在docker run命令中使用绝对路径不起作用

如何在WPF项目中使用具有绝对路径的Image?

如何在标记中使用绝对路径添加背景图像

如何在Java中使用正确的字符编码获取绝对路径?

如何在Expo和React Native中使用绝对路径导入?

如何在Windows File Explorer中使用绝对路径

如何在Windows中使用绝对路径形成FTP URL?

如何使用文件的绝对路径打开文件?

使用Process调用exe而没有绝对路径

使用'find'命令获取文件的绝对路径

如何使用绝对路径访问网络位置?