使用 gatsby-transformer-sharp 时将空字符串作为图像路径处理
Handle empty strings as image paths when using gatsby-transformer-sharp
我正在将 Gatsby 与 Netlify CMS 结合使用。我使用 gatsby-transformer-sharp 进行各种图像处理。
在Netlify CMS中,如果用户删除图片,frontmatter值变为空字符串,例如:
我的博客-post.md:
---
image: ''
---
当我查询 Graphql 时,这会导致 gatsby-transformer-sharp 出错:
Error Field "image" must not have a selection since type "String" has no subfields.
这似乎是因为 Gatsby/Graphql 已将图像字段推断为字符串。
所以我创建了一个 schema.md
文件,因此总会有至少一个条目包含有效图像:
_schema.md:
---
image: /some-dummy-image.jpg
---
这似乎部分解决了问题 - 构建只是偶尔失败。但是确实还是失败了。我认为它必须从它遇到的第一个降价文件中推断出它的模式——有时它首先找到 _schema.md
,有时它首先找到 my-blog-post.md
。
有人设法解决这个问题吗?
最后我设法解决了这个问题。我没有意识到在推断模式之前直接从 frontmatter 中删除这些空字段实际上很容易。
我制作了一个小的自定义插件,它会递归地遍历 frontmatter 字段,并删除任何具有空字符串的字段。我也只允许它删除具有特定名称的字段(例如:image
),因此它不会在其他地方引起意外更改。
src/plugins/remove-empty-fields/gatsby-node.js:
let fieldsToRemove = [];
const deleteFieldsRecursive = (node) => {
fieldsToRemove.forEach(fieldToRemove => {
if (node[fieldToRemove] === '') {
delete node[fieldToRemove];
}
});
if (typeof node === 'object') {
Object.values(node).forEach(subNode => {
deleteFieldsRecursive(subNode);
})
}
};
exports.onCreateNode = ({ node }, configOptions) => {
fieldsToRemove = configOptions.fieldsToRemove;
if (node.internal.type === 'MarkdownRemark') {
if (!node.frontmatter) {
return;
}
deleteFieldsRecursive(node);
}
};
然后将其添加到 gatsby-config.js
的插件列表中
{
resolve: 'remove-empty-fields',
options: {
fieldsToRemove: [
'image',
'bgImage',
],
},
},
更新
从 Gatsby@^2.2.0 开始,处理这个错误的最好方法是使用 Gatsby hook createSchemaCustomization
。我们需要告诉 Gatsby,image
字段肯定会是一个文件。
exports.createSchemaCustomization = ({ actions }) => {
actions.createType(`
type RemarkFrontmatter @infer {
image: File
}
type MarkdownRemark implements Node @infer {
frontmatter: RemarkFrontmatter
}
`)
}
旧答案
我最近了解到,您甚至可以在其 MarkdownRemark
节点创建之前直接修改 markdown 的 frontmatter,并返回这里分享。
gatsby-transformer-remark
使用 graymatter
解析 frontmatter 并允许用户传入自定义解析器。在内部,灰质使用 js-yaml
.
const yaml = require('js-yaml');
const customParser = (str) => {
const result = yaml.safeLoad(str);
// remove image (non recursively, as an example)
const { image, ...withoutImage } = result;
return withoutImage;
}
并将其传递给gatsby-transformer-remark
{
resolve: `gatsby-transformer-remark`,
options: {
engines: {
yaml: customParser,
},
}
从句法上讲,我更喜欢你这样做的方式——当空字段由插件处理时,它会更清楚。只想添加另一个选项!
我正在将 Gatsby 与 Netlify CMS 结合使用。我使用 gatsby-transformer-sharp 进行各种图像处理。
在Netlify CMS中,如果用户删除图片,frontmatter值变为空字符串,例如:
我的博客-post.md:
---
image: ''
---
当我查询 Graphql 时,这会导致 gatsby-transformer-sharp 出错:
Error Field "image" must not have a selection since type "String" has no subfields.
这似乎是因为 Gatsby/Graphql 已将图像字段推断为字符串。
所以我创建了一个 schema.md
文件,因此总会有至少一个条目包含有效图像:
_schema.md:
---
image: /some-dummy-image.jpg
---
这似乎部分解决了问题 - 构建只是偶尔失败。但是确实还是失败了。我认为它必须从它遇到的第一个降价文件中推断出它的模式——有时它首先找到 _schema.md
,有时它首先找到 my-blog-post.md
。
有人设法解决这个问题吗?
最后我设法解决了这个问题。我没有意识到在推断模式之前直接从 frontmatter 中删除这些空字段实际上很容易。
我制作了一个小的自定义插件,它会递归地遍历 frontmatter 字段,并删除任何具有空字符串的字段。我也只允许它删除具有特定名称的字段(例如:image
),因此它不会在其他地方引起意外更改。
src/plugins/remove-empty-fields/gatsby-node.js:
let fieldsToRemove = [];
const deleteFieldsRecursive = (node) => {
fieldsToRemove.forEach(fieldToRemove => {
if (node[fieldToRemove] === '') {
delete node[fieldToRemove];
}
});
if (typeof node === 'object') {
Object.values(node).forEach(subNode => {
deleteFieldsRecursive(subNode);
})
}
};
exports.onCreateNode = ({ node }, configOptions) => {
fieldsToRemove = configOptions.fieldsToRemove;
if (node.internal.type === 'MarkdownRemark') {
if (!node.frontmatter) {
return;
}
deleteFieldsRecursive(node);
}
};
然后将其添加到 gatsby-config.js
{
resolve: 'remove-empty-fields',
options: {
fieldsToRemove: [
'image',
'bgImage',
],
},
},
更新
从 Gatsby@^2.2.0 开始,处理这个错误的最好方法是使用 Gatsby hook createSchemaCustomization
。我们需要告诉 Gatsby,image
字段肯定会是一个文件。
exports.createSchemaCustomization = ({ actions }) => {
actions.createType(`
type RemarkFrontmatter @infer {
image: File
}
type MarkdownRemark implements Node @infer {
frontmatter: RemarkFrontmatter
}
`)
}
旧答案
我最近了解到,您甚至可以在其 MarkdownRemark
节点创建之前直接修改 markdown 的 frontmatter,并返回这里分享。
gatsby-transformer-remark
使用 graymatter
解析 frontmatter 并允许用户传入自定义解析器。在内部,灰质使用 js-yaml
.
const yaml = require('js-yaml');
const customParser = (str) => {
const result = yaml.safeLoad(str);
// remove image (non recursively, as an example)
const { image, ...withoutImage } = result;
return withoutImage;
}
并将其传递给gatsby-transformer-remark
{
resolve: `gatsby-transformer-remark`,
options: {
engines: {
yaml: customParser,
},
}
从句法上讲,我更喜欢你这样做的方式——当空字段由插件处理时,它会更清楚。只想添加另一个选项!