Gatsby: 问题-如何从frontmatter读取Markdown

创建于 2018-04-17  ·  41评论  ·  资料来源: gatsbyjs/gatsby

描述

我想从frontmatter读取markdown内容。 例如:

 halfBlocks:
 -标题:这是第一个标题
 内容:>-
 ###这是** MarkDown **格式的实际内容。

 -这是第一行
 -这是第二排
 -这是第三排
 -标题:这是第二个标题
 内容:>-
 ###这是** MarkDown **格式的实际内容。

 -这是第一行
 -这是第二排
 -这是第三排

我正在使用以下graphql:

 halfBlocks {
 标题
 图片
 内容
 }

如何阅读转换为HTML或显示为HTML的内容?

预期结果

我希望能够从markdown文件中读取“ index.md”并将其呈现为HTML。

实际结果

Markdown按原样显示,没有任何解释。

环境

  • 盖茨比版本( npm list gatsby ):gatsby@^1.9.247
  • gatsby-cli版本( gatsby --version ):1.1.50
question or discussion

最有用的评论

这可能是完全不可行的,但您不能只创建如下所示的markdown组件,然后在需要将markdown转换为HTML的任何地方都可以在模板中使用它

import React from 'react'
import PropTypes from 'prop-types'
import showdown from 'showdown'

const converter = new showdown.Converter()

const MarkdownContent = ({ content, className }) => (
  <div className={className} dangerouslySetInnerHTML={{ __html: converter.makeHtml(content) }} />
)

MarkdownContent.propTypes = {
  content: PropTypes.string,
  className: PropTypes.string,
}


export default MarkdownContent

所有41条评论

本教程将详细介绍这一过程,特别是第5-7部分https://www.gatsbyjs.org/tutorial/

您可能还想从一个启动程序开始-其中许多已经设置了降价支持-https: //www.gatsbyjs.org/docs/gatsby-starters/

这个问题更加细微,本教程未涵盖,因此我将重新打开它。

我认为您有2种选择:

  1. 您可以将markdown内容分隔为单独的文件并使用路径链接:
Separate file - let's call it `someContent.md`
```md
### This is the actual content in **MarkDown** format.

- This is the first row
- This is second row
- This is third row
```
and reference that file in your main file (by relative path):
```md
halfBlocks:
  - title: This is first title
    content: "./someContent.md"
```
then in query you could
```
halfBlocks {
  content {
    childMarkdownRemark {
      html
    }
}
```
  1. 其他方法将以编程方式处理此问题-为您的frontmatter字段创建markdown节点,并通过createNodeField添加它们。 这涉及更多。 您可能需要浏览Contentful源插件,以了解如何创建MarkdownRemark节点。

@KyleAMathews谢谢您的建议。 我确实读过它们,但是对我来说很难完全理解如何去做。 我正在使用启动器,但这涉及更多。 使用的入门工具: https

@pieh非常感谢您的指导。 你是对的。 我认为我将有太多的小文件,所以我使用下面的代码来完成此工作。 我在这里对此进行记录,以便如果其他人有相同的问题,他们也可以看到。

步骤1:阅读内容

我通常通过Graphql阅读内容。 这给了我降价作为一个字符串。 我仍然需要转换。

步骤2:转换为HTML

为此,我决定让内容作为字符串,直到到达将要显示此内容的实际组件为止。 在那里,我将其转换为降价。

添加备注以编程方式执行此操作。 您也许可以忽略remark-preset-lint-recommended:

安装备注

yarn add remark remark-preset-lint-recommended remark-html

进口

import remark from 'remark';
import recommended from 'remark-preset-lint-recommended';
import remarkHtml from 'remark-html';

渲染
稍后在渲染部分中假设content是作为字符串读取的减价:

content = remark()
      .use(recommended)
      .use(remarkHtml)
      .processSync(content).toString();

现在,我可以将内容重新解释为HTML。

步骤3:在减价中添加内容

我遇到了另外一个陷阱。 当我在>-使用多行时,格式不正确:

content: >-
    ### This is the actual content in **MarkDown** format.
    - This is the first row
    - This is second row

但是使用管道符号|可以很好地工作。

content: |
    ### This is the actual content in **MarkDown** format.
    - This is the first row
    - This is second row

现在,我要关闭这个。 如果您愿意,请随时重新打开。

谢谢!!

我也想将markdown用作前题(确切地说是标题和摘录),我认为默认情况下应该支持它。

拥有一个命名约定会很棒,这样gatsby-transformer-remark可以理解例如title.md是一个markdown字段。

@omeid @ thorn0这可能是我们在gatsby-transformer-remark中直接支持的内容,但与此同时,您可以创建一个为您执行此操作的插件,例如https://github.com/gatsbyjs/gatsby/issues/5729#issuecomment -395701042和createNodeField

很抱歉在已经结束的问题上发表评论,但是只想分享我在自己引用的gatsby-node.js中使用的摘要,请参考大家引用的内容:

// Need to `yarn add remark remark-html`, then include the following code in
// gatsby-node.js.
const remark = require('remark');
const remarkHTML = require('remark-html');

exports.onCreateNode = ({ node }) => {
  // Conditionals, etc. can be used here, but I omitted those just for example's sake.
  const markdown = node.frontmatter.my_field;
  node.frontmatter.my_field = remark()
    .use(remarkHTML)
    .processSync(markdown)
    .toString();
  return node;
};

因此,不使用createNodeField可以这样做吗? 我很困惑。

@ thorn0最好使用createNodeField代替node.frontmatter.my_field =因为突变node可能导致难以调试的错误

@amitjindal @nshki运行良好,但是由于我安装了“ react-flickity-component”库,因此完全使我的生产构建过程崩溃:

success delete html and css files from previous builds — 0.626 s
success open and validate gatsby-config — 0.018 s
success copy gatsby files — 0.075 s
success onPreBootstrap — 2.782 s
error UNHANDLED EXCEPTION


  TypeError: Cannot set property 'Compiler' of null

  - index.js:16 plugin
    [blog]/[remark-html]/index.js:16:17

  - index.js:271 Function.use
    [blog]/[unified]/index.js:271:25

  - gatsby-node.js:63 exports.onCreateNode.postscriptumsMarkdown.forEach.postscr    iptum
    /home/projects/blog/gatsby-node.js:63:12

  - Array.forEach

  - gatsby-node.js:61 Object.exports.onCreateNode
    /home/projects/blog/gatsby-node.js:61:29

  - api-runner-node.js:110 runAPI
    [blog]/[gatsby]/dist/utils/api-runner-node.js:110:36

  - api-runner-node.js:187 
    [blog]/[gatsby]/dist/utils/api-runner-node.js:187:33

  - map.js:27 
    [blog]/[async]/internal/map.js:27:9

  - eachOfLimit.js:66 replenish
    [blog]/[async]/internal/eachOfLimit.js:66:17

  - eachOfLimit.js:50 iterateeCallback
    [blog]/[async]/internal/eachOfLimit.js:50:17

  - onlyOnce.js:12 module.exports
    [blog]/[async]/internal/onlyOnce.js:12:16

  - map.js:29 
    [blog]/[async]/internal/map.js:29:13

  - util.js:16 tryCatcher
    [blog]/[bluebird]/js/release/util.js:16:23

  - nodeify.js:23 Promise.successAdapter
    [blog]/[bluebird]/js/release/nodeify.js:23:30

  - promise.js:566 Promise.module.exports.Promise._settlePromise
    [blog]/[bluebird]/js/release/promise.js:566:21

  - promise.js:606 Promise.module.exports.Promise._settlePromiseCtx
    [blog]/[bluebird]/js/release/promise.js:606:10


Waiting for the debugger to disconnect...

Process finished with exit code 130 (interrupted by signal 2: SIGINT)

试图从Webpack中排除库不起作用( @see https://github.com/gatsbyjs/gatsby/issues/7599)

嗨,大卫(@comxd),对不起,我在旅行。
不幸的是我对此没有见识。 我试图检查代码。 null上的编译器似乎来自注释库。

您似乎在gatsby-node.js文件中使用了循环。
它可能与某些不是降价或更糟的空内容有关,您正在尝试对其进行处理。 尝试在其中添加一些console.log语句,看看是否找到一种模式,其中某种原因导致了此问题。

这可能是完全不可行的,但您不能只创建如下所示的markdown组件,然后在需要将markdown转换为HTML的任何地方都可以在模板中使用它

import React from 'react'
import PropTypes from 'prop-types'
import showdown from 'showdown'

const converter = new showdown.Converter()

const MarkdownContent = ({ content, className }) => (
  <div className={className} dangerouslySetInnerHTML={{ __html: converter.makeHtml(content) }} />
)

MarkdownContent.propTypes = {
  content: PropTypes.string,
  className: PropTypes.string,
}


export default MarkdownContent

@blakenoll绝对不会完全关闭! 这是一个合理的方法。

就是说,Gatsby的一大好处是您可以在构建时进行这些操作,这很不错,因为这样我们就不必向最终用户购买Markdown解析器了!

@DSchau当应用重新

@blakenoll喜欢开箱即用的想法!

我们是否有任何可用的东西来插入我们包含在gatsby-config.js中的所有备注插件/配置,所以我们不需要复制幕后完成的所有功能Gatsby的备注实现为我们提供了? 这将使生成节点字段变得容易一些。 但是当您想到嵌套的,可重复的字段以及每页内容的变化时,就显得非常麻烦。

@blakenoll非常感谢您的摊牌提示。 超级有帮助,做了我需要在前端使用HTML的内容。 也就是说,使用Markdown创建网页的方法似乎很笨拙,该网页需要将不同的内容传递到页面的不同部分。

有什么方法可以在graphQL查询的frontmatter部分中应用某种markdownParser函数(类似于我们可以操作图像的方式),该函数将在frontmatter中解析传入的markdown字符串并将其转换为HTML? 不是graphQL专家...只是想想而已。

如果一个人将Gatsby与Netifly CMS一起使用,这是IMO b / c的一个重要问题,Netifly提供了使各种前题字段接受Markdown作为值的选项。 但是,当查询这些字段时,它们将作为markdown以字符串形式返回,而不是解析为HTML。 @amitjindal@blakenoll的解决方案有效,但是正如@DSchau所提到的,如果我们可以避免将markdown解析传递给用户,则不是最好的选择。 有谁比我更熟悉Gatbsy?

@skylarweaver我绝对和你在同一页面上。 虽然我确实了解创建可以解析此信息的节点字段的本质,但对于CMS数据来说可能有点笨拙,而CMS数据可能具有可重复的字段以及大量的字段名称变体以供筛选。 当时还没有明确的方法来重新使用任何/所有Gatsby Remark插件。

+1 @skylarweaver说的!

@amitjindal也许是愚蠢的问题,但是“>-”还能做什么? 使用netlify cms启动程序,无论我有>,>-,|还是什么都没有,似乎对生成的输出没有任何影响。

@ nol13参见块标量,关于换行符。

如何插入表格? 这行不通

content: |
        |   |   |   |   |   |
        |---|---|---|---|---|
        |   |   |   |   |   |
        |   |   |   |   |   |
        |   |   |   |   |   |

@ qnguyen12我会尝试使用https://jmalarcon.github.io/markdowntables/之类的工具来帮助您进行转换。

是的,我是说它是作为源而不是表呈现的
例如:

text: |
        test   
        ### This is the actual content in **MarkDown** format.  
        |Month|Savings|Spending|
        |--- |--- |--- |
        |January|$100|$900|
        |July|$750|$1000|
        |December|$250|$300|
        |April|$400|$700|

它产生:
测试

这是MarkDown格式的实际内容。

|每月|节省|支出| | --- | --- | --- | |一月| $ 100 | $ 900 | | 7月| $ 750 | $ 1000 | | 12月| $ 250 | $ 300 | |四月| $ 400 | $ 700 |

@KyleAMathews谢谢您的工作,但是显然您需要回复备注插件配置和插件,否则您将获得不同的结果。 有什么计划支持降价活动吗? 也许frontmattermd字段与原始frontmatter

@omeid我没有任何计划,这对某人来说是一个很棒的插件,可以与社区创建和共享!

我创建了一个应该执行此操作的插件: gatsby-transformer-remark-frontmatter 。 从我的测试看来,它似乎是行得通的,并且我正计划在为客户做的项目中使用它,但是如果您能看一下并告诉我是否有任何看起来不正确的东西,我将不胜感激,因为这是我第一次编写gatsby插件。 它采用@omeid建议的路线,并将frontmattermd字段添加到MarkdownRemark节点。

最初,在我意识到可以创建新的markdown文件节点供gatsby-transformer-remark使用之前,我想出了一个非常棘手的解决方案,涉及调用由gatsby-transformer-remark的setFieldsOnGraphQLNodeType函数导出的解析器,并传入一个新的在另一个解析器中创建的markdown节点。 这允许使用字段枚举查询MarkdownRemark节点上的任何字段,该枚举用于组函数,这是我真正喜欢的,但实际上很多东西都想借用。 我将其保存在这里供后代使用。

@WhiteAbeLincoln,我尝试安装并测试:
npm i gatsby-transformer-remark-frontmatter npm ERR! code ENOVERSIONS npm ERR! No valid versions available for gatsby-transformer-remark-frontmatter

抱歉,我意识到还没有发布到npm。 下班后我会发布它,并通知您。

—安倍·怀特

2019年6月17日,22:53,broeker [email protected]写道:

@WhiteAbeLincoln,我尝试安装并测试:
npm我gatsby-transformer-remark-frontmatter npm错误! 代码ENOVERSIONS npm ERR! 没有适用于gatsby-transformer-remark-frontmatter的有效版本

-
您收到此邮件是因为有人提到您。
直接回复此电子邮件,在GitHub上查看,或使该线程静音。

@WhiteAbeLincoln我尝试了gatsby-transformer-remark-frontmatter,但它给了我一个错误。

错误#11325

您网站的“ gatsby-node.js”创建了一个页面,该页面包含不存在的组件。

你得到这个错误吗?

它最初是由@obeid在您的存储库的问题日志中报告的。

也许我只是没有正确使用它。 因此,一些帮助表示赞赏。

建立在@nshki答案之上,并带有@pieh来评论节点突变。 这完全对我有用:

const remark = require("remark");
const remarkHTML = require("remark-html");

exports.onCreateNode = ({ node, actions: { createNodeField } }) => {
  const my_field = node.frontmatter.my_field;

  if (my_field) {
    const value = remark()
      .use(remarkHTML)
      .processSync(my_field)
      .toString();

    // new node at:
    // fields {
    //   my_field_html
    // }
    createNodeField({
      name: `my_field_html`,
      node,
      value
    });
  }
};

编辑: my_field => my_field_html

@aziaziazi除了嵌套在数组中的字段外,我该如何做同样的事情?

---
pressEventsList:
  - body: >-
      *My md content...*
    image: 'https://res.cloudinary.com/press/01.jpg'
  - body: >-
      *My md content...*
    image: 'https://res.cloudinary.com/press/02.jpg'
---

我需要转换每个pressEventsList[i].body

@alexeychikk我想您可能会寻找pressEventList ,然后映射内容以创建结果数组:

const remark = require("remark");
const remarkHTML = require("remark-html");

exports.onCreateNode = ({ node, actions: { createNodeField } }) => {
const pressEventList = node.frontmatter.pressEventList;

if (pressEventList) {
  const value = pressEventList.map(event =>
     remark()
    .use(remarkHTML)
    .processSync(event.body)
    .toString()
  )

  createNodeField({
    name: `pressEventList`,
    node,
    value
  });
}
};

我有兴趣创建一个插件来解析自定义YAML标签以实现上述功能,而无需使用createNodeField (与清晰解析图像URL相同的方式)。
谁能指出我解析图像URL的代码,以查看当前如何使用sharp进行处理的示例?

👋对于使用MDX的用户,我创建了一个插件来添加frontmatter支持https://www.gatsbyjs.org/packages/gatsby-plugin-mdx-frontmatter/

@zslabs ,您通常不会看到“ 9小时前”发布的解决方案! 我会旋转一下! 辛苦了

我一直在为此苦苦挣扎,因为我想为自己的页面之一使用更复杂的数据结构。
在前题中,我有一系列部分,其中有一些字段,例如标题和特色图片,然后在每个字段上,我都用markdown制作了一个主体。
使用createNodeField并不是对我有用,因为我无法逻辑地链接它们,因为它们是在自己的字段中创建的,而不是附加到现有的frontmatter结构中。
我最终使用了createFieldExtension,以便查询我的section.body时,它以HTML返回。
如果这不是一个好的解决方案,请有人纠正我,这似乎对我有用,但我有na的感觉,这是错误的解决方法。

我的前题结构看起来像这样:

templateKey: project-entry
date: 2020-06-22T13:16:57.702Z
featuredproject: true
title: Project title
description: Description for listing the project on other pages
featuredimage: Image for listing the project on other pages
featuredpost: false
sections:
  - heading: Section heading
    standout: false
    intro: >-
      Introduction to be displayed separately to body
    body: >-
       ## section title
       * bullet point
       * bullet point
       Some other text here

还有我在gatsby-node.js中使用的代码

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

  createFieldExtension({
    name: 'toHTML',
    extend:() => ({
        resolve(source) {
          return remark().use(remarkHTML).processSync(source.body).toString()
        }
      })
  })
  const typeDefs = `
  type MarkdownRemark implements Node {
    frontmatter: Frontmatter
  }
  type Frontmatter <strong i="14">@infer</strong> {
    sections: [section]
  }
  type section <strong i="15">@infer</strong> {
    body: String <strong i="16">@toHTML</strong>
  }
  `
  createTypes(typeDefs)
}

对于其他感兴趣的人,我使用自定义的YAML类型解决了该问题,以允许将任意字段解析为markdown,如下所示:

---
title: My Page
inline: !md Some **bold** and _italic_ text
block: !md |
  ## I'm a H2 title
  [I'm an inline-style link](https://www.google.com)
---

为此,创建一个自定义类型,然后重写grey-matter的YAML解析器:

// custom-yaml.js
const yaml = require('js-yaml')
const remark = require('remark')
const remarkHTML = require('remark-html')

const MarkdownYamlType = new yaml.Type('!md', {
  kind: 'scalar',
  construct: data => remark().use(remarkHTML).processSync(data).toString(),
})

const MARKDOWN_SCHEMA = yaml.Schema.create(MarkdownYamlType)

module.exports = doc => yaml.safeLoad(doc, { schema: MARKDOWN_SCHEMA })
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        engines: { yaml: require("path/to/custom-yaml.js") },
      },
    }
  ]
}

我解决了这个问题。 我创建了一个名为@md的字段扩展,并将其用于frontmatter类型定义中,并与字段重命名结合使用,从而可以实现所需的抽象。

exports.createSchemaCustomization = ({ actions }) => {
  actions.createFieldExtension({
    name: "md",
    args: {
      from: {
        type: "String!",
        defaultValue: true,
      },
    },

    extend() {
      return {
        args: {
          from: "String!",
        },
        resolve(source, args) {
          const fieldValue = source[args.from]
          return convertToHTML(fieldValue)
        },
      }
    },
  })
  const typeDefs = `
    type MarkdownRemark implements Node <strong i="7">@infer</strong> {
      frontmatter: Frontmatter
    }
    type Frontmatter {
      markdownField: String! <strong i="8">@md</strong>
    }
  `
  actions.createTypes(typeDefs)
}

这是一个示例用法:

...
frontmatter {
        title: markdownField(from: "title")
        subtitle: markdownField(from: "subtitle")
}

我解决了这个问题。

这对我来说不太有效。 首先,我收到一个错误,拒绝参数fromdefaultValue: true from -它必须是一个字符串。 将其更改为defaultValue: '' ,然后出现此错误:

Encountered an error parsing the provided GraphQL type definitions:
Argument "from" of required type "String!" was not provided.

  1 |
  2 |     type MarkdownRemark implements Node <strong i="11">@infer</strong> {
  3 |       frontmatter: Frontmatter
  4 |     }
  5 |     type Frontmatter {
> 6 |       markdownField: String! <strong i="12">@md</strong>
    |                              ^
  7 |     }

我不知道该怎么解决。

对于其他感兴趣的人,我使用自定义的YAML类型解决了该问题,以允许将任意字段解析为markdown,如下所示:

---
title: My Page
inline: !md Some **bold** and _italic_ text
block: !md |
  ## I'm a H2 title
  [I'm an inline-style link](https://www.google.com)
---

为此,创建一个自定义类型,然后重写grey-matter的YAML解析器:

// custom-yaml.js
const yaml = require('js-yaml')
const remark = require('remark')
const remarkHTML = require('remark-html')

const MarkdownYamlType = new yaml.Type('!md', {
  kind: 'scalar',
  construct: data => remark().use(remarkHTML).processSync(data).toString(),
})

const MARKDOWN_SCHEMA = yaml.Schema.create(MarkdownYamlType)

module.exports = doc => yaml.safeLoad(doc, { schema: MARKDOWN_SCHEMA })
// gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        engines: { yaml: require("path/to/custom-yaml.js") },
      },
    }
  ]
}

我尝试使用“ gatsby-transformer-remark”无效的插件选项吗?

此页面是否有帮助?
0 / 5 - 0 等级