-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Comments
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/ |
The question is more nuanced and not covered by the tutorial, so I'll reopen this. In my opinion you have 2 options:
|
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 contentI 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 HTMLFor 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 content = remark()
.use(recommended)
.use(remarkHtml)
.processSync(content).toString(); Now I am able to reinterpret content as HTML. Step 3: Adding content in markdownThere 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 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!! |
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. |
Would be great to have a naming convention, so that |
@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 |
Apologies for commenting on an already closed issue, but just wanted to share a snippet that I used in my own // 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;
}; |
So is it okay to do so without using |
@thorn0 better use |
@amitjindal @nshki It's working nicely but totally crash my production build process since I have installed the "react-flickity-component" library:
Trying to exclude library from Webpack not working (@see #7599) |
Hi David (@comxd), Sorry I was traveling. You seem to be using a loop in your gatsby-node.js file. |
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 |
@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! |
@DSchau Won't the Markdown parser actually be shipped down to to the user when the app is re-hydrated?
|
Do we have anything available to us to pull-in all of the remark plugins/configuration that we included within |
@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. |
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? |
@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. |
+1 what @skylarweaver said! |
@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. |
@nol13 See block scalars, it’s about newlines. |
How could I insert a table? This does not work
|
@qnguyen12 I'd try using a tool like https://jmalarcon.github.io/markdowntables/ to help you with the conversion. |
Yes, I mean it render as the source, not table
it generates: This is the actual content in MarkDown format.|Month|Savings|Spending| |--- |--- |--- | |January|$100|$900| |July|$750|$1000| |December|$250|$300| |April|$400|$700| |
@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 |
@omeid I don't have any plans no — this would be a great plugin for someone to create and share with the community! |
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 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. |
hi @WhiteAbeLincoln i tried to install and test: |
Sorry, I realized haven't published to npm yet. I'll publish it once I get off work and let you know.
— Abe White
… On Jun 17, 2019, at 22:53, broeker ***@***.***> wrote:
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
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@WhiteAbeLincoln I tried gatsby-transformer-remark-frontmatter but it gave me an error.
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. |
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: |
@aziaziazi How can I do the same thing but for a field nested in array?
I need to convert each |
@alexeychikk i guess you may look for 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
});
}
}; |
Using link: * gatsbyjs/gatsby#5021 * https://www.gatsbyjs.org/docs/adding-markdown-pages/ * https://www.gatsbyjs.org/docs/schema-gql-type/ * Copy About and Blog Page
I'm interested in creating a plugin to parse custom YAML tags to achieve the above without using |
👋 For those using MDX, I created a plugin to add frontmatter support https://www.gatsbyjs.org/packages/gatsby-plugin-mdx-frontmatter/ |
@zslabs, it's not often you see a solution posted "9 hours ago"! I'll give it a spin! Nice work. |
I've been struggling with this since I wanted to use a more complex data structure for one of my pages. 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)
} |
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 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")
} |
This doesn't quite work for me. First I get a error rejecting the
This I don't know how to solve. |
I get 'Invalid plugin options for "gatsby-transformer-remark":' if i try this method? |
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. [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
|
It appears they changed the options since I did that. Assume it would need to be done as a plugin now... |
How do I use this approach but load the HTML with normal spaces instead of non-breaking-spaces? |
How to get frontmatter children under my_section_id only?
|
I have been using a function to convert a remark string into html just as @amitjindal suggested:
That worked well with Gatsby 2. However, Gatsby 4 fails with Webpack errors:
Does anybody have an idea how to fix this? |
"uhhhh look it up on the internet? it's around there somewhere" |
Description
I want to read markdown content from frontmatter. For example:
I am using the following graphql:
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
npm list gatsby
): gatsby@^1.9.247gatsby --version
): 1.1.50The text was updated successfully, but these errors were encountered: