Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question - How to read Markdown from frontmatter #5021

Closed
amitjindal opened this issue Apr 17, 2018 · 47 comments
Closed

Question - How to read Markdown from frontmatter #5021

amitjindal opened this issue Apr 17, 2018 · 47 comments
Labels
type: question or discussion Issue discussing or asking a question about Gatsby

Comments

@amitjindal
Copy link

Description

I want to read markdown content from frontmatter. For example:

halfBlocks:
  - title: This is first title
    content: >-
        ### This is the actual content in **MarkDown** format.

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

        - This is the first row
        - This is second row
        - This is third row

I am using the following graphql:

halfBlocks {
          title
          image
          content
  }

How do I read content converted to HTML or display as HTML?

Expected result

I expect to be able to read this from a markdown file say 'index.md' and render this as HTML.

Actual result

Markdown is displayed as is without interpretation.

Environment

  • Gatsby version (npm list gatsby): gatsby@^1.9.247
  • gatsby-cli version (gatsby --version): 1.1.50
@KyleAMathews
Copy link
Contributor

The tutorial walks through this, particularly parts 5-7 https://www.gatsbyjs.org/tutorial/

You might also want to start with one of the starters — many of which have markdown support already setup — https://www.gatsbyjs.org/docs/gatsby-starters/

@pieh
Copy link
Contributor

pieh commented Apr 17, 2018

The question is more nuanced and not covered by the tutorial, so I'll reopen this.

In my opinion you have 2 options:

  1. You can separate your markdown content to separate files and use path links:

    Separate file - let's call it someContent.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):

    halfBlocks:
      - title: This is first title
        content: "./someContent.md"

    then in query you could

    halfBlocks {
      content {
        childMarkdownRemark {
          html
        }
    }
    
  2. Other approach would be handling this programatically - creating markdown nodes for your frontmatter fields and adding them via createNodeField. This is more involved. You would probably need to browse the Contentful source plugin do see how to create MarkdownRemark node.

@pieh pieh reopened this Apr 17, 2018
@m-allanson m-allanson added the type: question or discussion Issue discussing or asking a question about Gatsby label Apr 18, 2018
@amitjindal
Copy link
Author

Hi @KyleAMathews thank you for your suggestion. I did read them but it was hard for me to completely understand how to go about this. I am using a starter but this was more involved. Starter used: https://github.com/v4iv/gatsby-starter-business

@pieh Thank you so much for guiding me. You are right. I figured I will have too many small files so I got this working with the code below. I am documenting this here so that if someone else has the same problem they can also see this.

Step 1: Reading content

I am reading the content normally via Graphql. This gives me the markdown as a string. I still need to convert that.

Step 2: Converting to HTML

For this I decided to let the content from as string till we reach the actual component that is going to display this. There I convert it to markdown.

Add remark for doing this programmatically. You may be able to ignore remark-preset-lint-recommended:

Install Remark

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

Import

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

Render
Later in the render part assuming content is the markdown that was read as string:

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

Now I am able to reinterpret content as HTML.

Step 3: Adding content in markdown

There is one more gotcha I came across. The formatting was not proper when I was using multiline with >-:

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

But with pipe symbol | it works great.

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

For now I am closing this. Please feel free to reopen if you would like.

Thanks!!

@omeid
Copy link

omeid commented Apr 22, 2018

I would like to use markdown for the frontmatter (title, and excerpt to be exact) as well, and I think it should be supported by default.

@thorn0
Copy link
Contributor

thorn0 commented Jul 4, 2018

Would be great to have a naming convention, so that gatsby-transformer-remark could understand that e.g. title.md is a markdown field.

@KyleAMathews
Copy link
Contributor

@omeid @thorn0 this might be something we support directly in gatsby-transformer-remark but in the meantime, you can create a plugin which does this for you e.g. #5729 (comment) and createNodeField

@nshki
Copy link

nshki commented Sep 5, 2018

Apologies for commenting on an already closed issue, but just wanted to share a snippet that I used in my own gatsby-node.js that worked for me, following what you all have referenced:

// 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;
};

@thorn0
Copy link
Contributor

thorn0 commented Sep 5, 2018

So is it okay to do so without using createNodeField? I'm confused.

@pieh
Copy link
Contributor

pieh commented Sep 5, 2018

@thorn0 better use createNodeField instead of node.frontmatter.my_field = because mutating node may results in hard to debug bugs

@comxd
Copy link

comxd commented Sep 10, 2018

@amitjindal @nshki It's working nicely but totally crash my production build process since I have installed the "react-flickity-component" library:

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)

Trying to exclude library from Webpack not working (@see #7599)

@amitjindal
Copy link
Author

Hi David (@comxd), Sorry I was traveling.
Unfortunately I have no insight into this. I tried to check in the code. The Compiler on null seems be coming from the remark library.

You seem to be using a loop in your gatsby-node.js file.
It might be related to some content coming in that is not markdown or worse empty and you are trying to process it. Try putting some console.log statements in that and see if you find a pattern where something empty is causing this.

@blakenoll
Copy link
Contributor

This could be totally off but couldn't you just create a markdown component like below that you could then use in your templates anywhere markdown is needed to be converted to 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

@DSchau
Copy link
Contributor

DSchau commented Oct 3, 2018

@blakenoll definitely not totally off! It's a reasonable approach.

That said, one of the big benefits of Gatsby is that you do those operations at build time, which is nice because then we don't need to shop a Markdown parser to the end user!

@dovidweisz
Copy link

dovidweisz commented Jan 1, 2019

@DSchau Won't the Markdown parser actually be shipped down to to the user when the app is re-hydrated?

@blakenoll Love the out-of-the-box thinking!

@zslabs
Copy link
Contributor

zslabs commented Feb 1, 2019

Do we have anything available to us to pull-in all of the remark plugins/configuration that we included within gatsby-config.js so we don't need to duplicate all the functionality done behind the scenes Gatsby's implementation of remark is providing us? That would make generating the node fields a bit easier; but incredibly cumbersome when you think about nested, repeatable fields and the variation of content per page.

@iantbarker
Copy link

@blakenoll Thanks so much for your showdown tip. Super helpful and did what I needed to use HTML in frontmatter. That said, seems a clunky approach to using Markdown to create a web page that needs to pass different pieces of content to different parts of the page.

@skylarweaver
Copy link

skylarweaver commented Apr 22, 2019

Is there any way we can apply some sort of markdownParser function within the frontmatter section of our graphQL query (similar to the way we can manipulate images) that will parse the incoming markdown string in the frontmatter and convert it to HTML? Not a graphQL expert...just trying to think.

This is an important issue IMO b/c if one is using Gatsby with Netifly CMS, Netifly provides the option to have various frontmatter fields accept Markdown as values. But when querying those fields, they are returned as markdown in a string instead of parsed to HTML. @amitjindal and @blakenoll's solutions work, but as @DSchau mentioned, it's not preferable to ship a markdown parse to the user if we can avoid it. Any thoughts from someone who's more familiar with Gatbsy than I?

@zslabs
Copy link
Contributor

zslabs commented Apr 22, 2019

@skylarweaver I'm definitely on the same page with ya. While I do understand the nature of creating a node field that can have this information parsed, it also becomes a bit unwieldy with CMS data that may have repeatable fields and a large amount of variations of field names to sift through; on-top of not having a clear way of re-using any/all Gatsby Remark plugins at that time.

@mrlubos
Copy link

mrlubos commented Apr 23, 2019

+1 what @skylarweaver said!

@nol13
Copy link

nol13 commented May 2, 2019

@amitjindal Maybe stupid question but what does the ">-" even do? Using the netlify cms starter and seems to make absolutely no difference in the generated output whether I have >, >-, |, or nothing at all.

@mrlubos
Copy link

mrlubos commented May 2, 2019

@nol13 See block scalars, it’s about newlines.

@qnguyen12
Copy link

qnguyen12 commented May 10, 2019

How could I insert a table? This does not work

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

@zslabs
Copy link
Contributor

zslabs commented May 10, 2019

@qnguyen12 I'd try using a tool like https://jmalarcon.github.io/markdowntables/ to help you with the conversion.

@qnguyen12
Copy link

Yes, I mean it render as the source, not table
For example:

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|

it generates:
test

This is the actual content in MarkDown format.

|Month|Savings|Spending| |--- |--- |--- | |January|$100|$900| |July|$750|$1000| |December|$250|$300| |April|$400|$700|

@omeid
Copy link

omeid commented May 21, 2019

@KyleAMathews Thanks, that sort of work, but obviously you either need to reply the remark plugin config and plugins or you get different results. Any plans to support markdown frontmatter? Perhaps a frontmattermd field along with the raw frontmatter?

@KyleAMathews
Copy link
Contributor

@omeid I don't have any plans no — this would be a great plugin for someone to create and share with the community!

@WhiteAbeLincoln
Copy link

I created a plugin that should do this: gatsby-transformer-remark-frontmatter. It seems to work from my testing, and I'm planning on using it in a project that I'm doing for a client, but I'd appreciate it if you guys would take a look and tell me if there's anything that looks incorrect, as it's my first time writing a gatsby plugin. It takes the route suggested by @omeid and adds a frontmattermd field to the MarkdownRemark node.

Initially, before I realized that I could just create new markdown file nodes for gatsby-transformer-remark to consume, I came up with a really hacky solution involving calling the resolvers exported by gatsby-transformer-remark's setFieldsOnGraphQLNodeType function, and passing in a new markdown node created within another resolver. This allowed querying any field on the MarkdownRemark node using a field enum like is used for the group function, which I really liked, but it felt like to much of a hack to actually use for anything. I've saved it here for posterity.

@broeker
Copy link

broeker commented Jun 18, 2019

hi @WhiteAbeLincoln i tried to install and test:
npm i gatsby-transformer-remark-frontmatter npm ERR! code ENOVERSIONS npm ERR! No valid versions available for gatsby-transformer-remark-frontmatter

@WhiteAbeLincoln
Copy link

WhiteAbeLincoln commented Jun 18, 2019 via email

@LincMitch
Copy link

LincMitch commented Sep 12, 2019

@WhiteAbeLincoln I tried gatsby-transformer-remark-frontmatter but it gave me an error.

ERROR #11325

Your site's "gatsby-node.js" created a page with a component that doesn't exist.

Do you get this error?

It was originally reported by @obeid on your repo's issue log.

Maybe I just ain't using it correctly. So some help appreciated.

@aziaziazi
Copy link

aziaziazi commented Dec 2, 2019

Building on top of @nshki answer and with @pieh comment about node mutation. This totally works for me:

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
    });
  }
};

edit: my_field => my_field_html

@alexeychikk
Copy link

@aziaziazi How can I do the same thing but for a field nested in array?

---
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'
---

I need to convert each pressEventsList[i].body.

@aziaziazi
Copy link

aziaziazi commented Dec 5, 2019

@alexeychikk i guess you may look for pressEventList and then map through the content to create an array of results:

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
  });
}
};

jaider pushed a commit to jaider/gatsby-netlify-cms-colindustria that referenced this issue Mar 15, 2020
@abemedia
Copy link

I'm interested in creating a plugin to parse custom YAML tags to achieve the above without using createNodeField (the same way sharp parses image URLs).
Can anyone point me to the code where image URLs are parsed to see an example of how this is currently done with sharp?

@zslabs
Copy link
Contributor

zslabs commented Jun 20, 2020

👋 For those using MDX, I created a plugin to add frontmatter support https://www.gatsbyjs.org/packages/gatsby-plugin-mdx-frontmatter/

@rockitweb
Copy link

@zslabs, it's not often you see a solution posted "9 hours ago"! I'll give it a spin! Nice work.

@Olipear
Copy link
Contributor

Olipear commented Jun 29, 2020

I've been struggling with this since I wanted to use a more complex data structure for one of my pages.
In frontmatter I had an array of sections, with a few fields like title and featured image, and then on each I had a body made with markdown.
Using createNodeField wasn't doing it for me because I had trouble linking them logically since they are created in their own field, not appended to the existing frontmatter structure.
I ended up using createFieldExtension so that when my section.body is queried, it's returned in HTML.
Please someone correct me if this isn't a good solution, it seems to work for me but I have that nagging feeling it's the wrong way of going about this.

my frontmatter structure looks like this:

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

And the code I used in 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 @infer {
    sections: [section]
  }
  type section @infer {
    body: String @toHTML
  }
  `
  createTypes(typeDefs)
}

@abemedia
Copy link

For anyone else that's interested I solved it using a custom YAML type to allow parsing any arbitrary field as markdown like so:

---
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)
---

To do so create a custom type and then override grey-matter's YAML parser:

// 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") },
      },
    }
  ]
}

@gimoteco
Copy link

gimoteco commented Sep 9, 2020

I resolved this a little different. I created a field extension called @md and used it in the frontmatter type definition combinated with the field renaming we could achieve the desired abstraction.

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 @infer {
      frontmatter: Frontmatter
    }
    type Frontmatter {
      markdownField: String! @md
    }
  `
  actions.createTypes(typeDefs)
}

here is an example usage:

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

@wu-lee
Copy link

wu-lee commented Nov 6, 2020

I resolved this a little different.

This doesn't quite work for me. First I get a error rejecting the defaultValue: true for the argument from - it must be a string. Changing that to defaultValue: '', I then get this error:

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

  1 |
  2 |     type MarkdownRemark implements Node @infer {
  3 |       frontmatter: Frontmatter
  4 |     }
  5 |     type Frontmatter {
> 6 |       markdownField: String! @md
    |                              ^
  7 |     }

This I don't know how to solve.

@cordial
Copy link

cordial commented Dec 7, 2020

For anyone else that's interested I solved it using a custom YAML type to allow parsing any arbitrary field as markdown like so:

---
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)
---

To do so create a custom type and then override grey-matter's YAML parser:

// 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") },
      },
    }
  ]
}

I get 'Invalid plugin options for "gatsby-transformer-remark":' if i try this method?

@wu-lee
Copy link

wu-lee commented Jan 2, 2021

Ok, so the suggestion above by @gimoteco didn't work for me, but it looks like an adaptation of code in the Gatsby documentation here, which works without errors.

Specifically, what I used was as follows. I include the type definition, which can safely just define one field out of many (i.e. summary) without disturbing Gatsby's inference. The documentation talks about the frontmatter type being Frontmatter, but this doesn't seem to be the case - using Graphiql to query the type field of the frontmatter object (__typename) it appears need to be MarkdownRemarkFrontmatter, as below.

[Aside: Later, I added definitions for many of the other fields, just because Gatsby's inference can go rather wrong when the fields are optional and not always present identically. However, I never discovered how to define File fields for images or other documents adequately, and they continue to be a pain point for me]

const remark = require(`remark`)
const html = require(`remark-html`)

exports.createSchemaCustomization = ({ actions }) => {
  // Define the @md tag to mark a field which should be interpreted as markdown
  // and converted to HTML
  actions.createFieldExtension({
    name: "md",
    args: {
      sanitize: {
        type: "Boolean!",
        defaultValue: true,
      },
    },
    // The extension `args` (above) are passed to `extend` as
    // the first argument (`options` below)
    extend(options, prevFieldConfig) {
      return {
        args: {
          sanitize: "Boolean",
        },
        resolve(source, args, context, info) {
          const fieldValue = context.defaultFieldResolver(
            source,
            args,
            context,
            info
          )
          const shouldSanitize =
            args.sanitize != null ? args.sanitize : options.sanitize
          const processor = remark().use(html, { sanitize: shouldSanitize })
          return processor.processSync(fieldValue).contents
        },
      }
    },
  })


  // Add a type definition for this field which marks
  // `summary` as a markdown field.
  actions.createTypes(`
    type MarkdownRemarkFrontmatter {
      summary: String @md
    }
  `)
}

@abemedia
Copy link

gatsby-transformer-remark

It appears they changed the options since I did that. Assume it would need to be done as a plugin now...

@anxiousextrovert
Copy link

anxiousextrovert commented Mar 30, 2021

Hi @KyleAMathews thank you for your suggestion. I did read them but it was hard for me to completely understand how to go about this. I am using a starter but this was more involved. Starter used: https://github.com/v4iv/gatsby-starter-business

@pieh Thank you so much for guiding me. You are right. I figured I will have too many small files so I got this working with the code below. I am documenting this here so that if someone else has the same problem they can also see this.

Step 1: Reading content

I am reading the content normally via Graphql. This gives me the markdown as a string. I still need to convert that.

Step 2: Converting to HTML

For this I decided to let the content from as string till we reach the actual component that is going to display this. There I convert it to markdown.

Add remark for doing this programmatically. You may be able to ignore remark-preset-lint-recommended:

Install Remark

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

Import

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

Render
Later in the render part assuming content is the markdown that was read as string:

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

Now I am able to reinterpret content as HTML.

Step 3: Adding content in markdown

There is one more gotcha I came across. The formatting was not proper when I was using multiline with >-:

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

But with pipe symbol | it works great.

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

For now I am closing this. Please feel free to reopen if you would like.

Thanks!!

How do I use this approach but load the HTML with normal spaces instead of non-breaking-spaces?

@mrterenz23
Copy link

How to get frontmatter children under my_section_id only?

---
sections:
  - section_id: my_section_id
    type: section_name
    title: Section title
    image: images/5.jpg
    content: >-
      This is my sample content...
  - section_id: my_second_section_id
---

@webmaster-safebreach
Copy link

webmaster-safebreach commented Nov 5, 2021

I have been using a function to convert a remark string into html just as @amitjindal suggested:

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

function mdStringToHTML(mdString) {
  return remark()
    .use(recommended)
    .use(remarkHtml)
    .processSync(mdString)
    .toString();
}

export default mdStringToHTML;

That worked well with Gatsby 2. However, Gatsby 4 fails with Webpack errors:

ERROR in ./node_modules/remark/node_modules/vfile/core.js 3:11-26
Module not found: Error: Can't resolve 'path' in '/Users/.../node_modules/remark/node_modules/vfile'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

Does anybody have an idea how to fix this?

@ecupaio
Copy link

ecupaio commented Jul 21, 2022

Contributor

"uhhhh look it up on the internet? it's around there somewhere"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question or discussion Issue discussing or asking a question about Gatsby
Projects
None yet
Development

No branches or pull requests