使用 Gatsby 的 Markdown 帖子中的特色图像的绝对路径
Posted
技术标签:
【中文标题】使用 Gatsby 的 Markdown 帖子中的特色图像的绝对路径【英文标题】:Use absolute path for featured image in markdown post with Gatsby 【发布时间】:2019-11-30 19:39:55 【问题描述】:我遵循了 Working With Images in Markdown Posts and Pages 的 Gatsby 教程,它运行良好,但我想要实现的是从静态位置获取图像,而不是使用图像的相对路径。
想参考这样的图片(在frontmatter中)
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 错误字段“featuredImage”不能有选择,因为 “String”类型没有子字段。
知道如何从与降价后目录不同的位置获取图像吗?
【问题讨论】:
【参考方案1】:过去在 Gatsby 中实现这一点相当麻烦,但感谢新的 createSchemaCustomization
Node API docs(自 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)
工作原理:
这有两个部分:
-
扩展
markdownRemark.frontmatter.featureImage
,以便graphql 通过createTypes
解析为文件节点而不是字符串
通过createFieldExtension
创建一个新的字段扩展@fileByDataPath
创建类型
现在 Gatsby 将 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。
这是因为虽然 Gatsby 现在知道 featureImage
应该是一个文件节点,但它不知道从哪里获取该文件。
此时,我们既可以使用createResolvers
手动将字段解析为文件节点,也可以使用createFileExtension
来做同样的事情。我选择createFileExtension
是因为它允许更多代码重用(您可以扩展任何字段),而在这种情况下,createResolvers
对于特定字段更有用。看到你想要的只是从src/data
目录解析一个文件,我将这个扩展称为fieldByDataPath
。
创建文件扩展
让我们看看 resolve 属性。它是一个接受以下内容的函数:
来源:父字段的数据(本例为frontmatter
)
args:在查询中传递给featureImage
的参数。我们不需要这个
context:包含nodeModel
,我们将使用它从 Gatsby 节点存储中获取节点
信息:关于此字段的元数据 + 整个架构
我们会从src.featureImage
中找到原始路径(img/photo.jpg
),然后将其粘到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。
编辑 2 此后,Gatsby 使 runQuery
异步(2020 年 7 月),更新了答案以反映这一点。
【讨论】:
我不认为这是帖子作者提到的错误日志的确切解决方案 像一个魅力一样工作,我不得不将 featureImage 重命名为 featuresImage 以使其与我的 frontmatter 标题一起使用......并且可以用于其他方式!!! 有什么方法可以获取markdown的相对路径?我有“./pic.jpb”,但我不知道markdown文件的绝对路径。【参考方案2】:除了允许在任何地方使用任何类型的资产(声音、视频、gpx...)的 Derek Answer 之外,如果只为图像寻找解决方案,可以使用:
https://www.gatsbyjs.org/packages/gatsby-remark-relative-images/
【讨论】:
很好,我不知道 gatsby-remark-relative-images 也可以处理 frontmatter 中的路径,整洁!【参考方案3】:在您的服务器模式中,您可能已将 featuresImage 变量声明为字符串,而在您的客户端 graphql 查询中,您试图调用 featuresImage 变量的子对象并且该子对象不存在。
您可能需要检查 graphql 架构定义并将查询与架构定义对齐
你当前的架构可能是这样的
featuredImage: String
您需要根据服务器端的要求声明适当的类型来更改它。
有关 graphql 类型的更多信息。请参考这个网址 - https://graphql.org/learn/schema/#object-types-and-fields
谢谢
瑞金预兆
【讨论】:
以上是关于使用 Gatsby 的 Markdown 帖子中的特色图像的绝对路径的主要内容,如果未能解决你的问题,请参考以下文章
博客文章中的 Gatsby-js 客户端 javascript 内联
如何处理 GatsbyJS 中 markdown 帖子之间的父/子关系
尝试使用 Contentful 将帖子列表添加到我的主页而不是 Gatsby 中的单独页面