Giter VIP home page Giter VIP logo

frontmatter-markdown-loader's Introduction

frontmatter-markdown-loader

npm GitHub Workflow Status

Webpack Loader for Front Matter files (.md) which returns:

This FrontMatter markdown file something.md:

---
subject: Hello
tags:
  - tag1
  - tag2
---
# Title

message

is loadable as:

import fm from "something.md"

fm.attributes // FrontMatter attributes => { subject: "Hello", tags: ["tag1", "tag2"] }
fm.html // Compiled markdown as HTML => "<h1>Title</h1>\n<p>message</p>\n"
fm.react // Component function for React which renders compiled markdown (Disabled as default)
fm.vue.component // Extendable component object for Vue which renders compiled markdown (Disabled as default)

📚 See the documentation for the further detail.

🔰 You have trouble with missing object?

The loader got the breaking changes in the latest major update. The article which you referred might premise on the old version. Check the installed version, if that says 1.x.y, see this guide.

Samples

Inspired/Referred

License

frontmatter-markdown-loader's People

Contributors

aubaugh avatar christianrank avatar danielroe avatar dependabot[bot] avatar guillett avatar hmsk avatar koharakazuya avatar raisiqueira avatar renovate-bot avatar selbekk avatar shanrauf avatar vnznznz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

frontmatter-markdown-loader's Issues

optionalDependencies expects unintentional installation

The current optionalDependencies:

"@babel/core": "^7.6.0",
"@babel/preset-react": "^7.6.0",
"@vue/component-compiler-utils": "^3.0.0",
"vue-template-compiler": "^2.5.0"

are installed in any project which installs frontmatter-markdown-loader unintentionally. I meant those are completely optional in the user's end, but npm behaves differently.

peerDependencies also shows unnecessary warnings if the project doesn't use react/vue features. So, remove optionalDependencies and throw if those are required by mode at all.

MD Vue Component with Nuxt asyncData

<template>
  <div>
    <h1>Hello</h1>

    <client-only>
      <component :is="dynamicComponent" />
    </client-only>
  </div>
</template>

<script>
export default {
  name: 'PostPage',
  async asyncData({ params }) {
    const file = await import(`~/blog/${params.post}.md`)

    return {
      text: file.attributes.text,
      dynamicComponent: file.vue.component
    }
  }
}
</script>

causes a problem:

RangeError
Maximum call stack size exceeded

Terminal:
WARN Cannot stringify a function data
WARN Cannot stringify a function render
WARN Cannot stringify a function created
WARN Cannot stringify a function VueComponent

Are there any restrictions with Nuxt asyncData?

Add `markdown-it` options option

As a user, I'd love to add options to the default options of markdown-it. This way, I don't have to set up my very own markdown formatter instead.

I think we can override the markdown option - if it's an object, pass it to the markdown-it initializers.

Vue Component doesn't work for me in NuxtJS

I follow the Instruction to use Vue Components in my .md files, but it doesn't work.

my nuxt.config.js looks like this:

const md = require('markdown-it')({ 
  html: true,
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return '<pre class="hljs"><code>' +
        hljs.highlight(lang, str, true).value +
        '</code></pre>';
      } catch (__) {}
    }
    return '<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
  } 
})

config.module.rules.push({
        test: /\.md$/,
        loader: 'frontmatter-markdown-loader',
        include: path.resolve(__dirname, 'content'),
        options: {
          markdown: (body) => {
            return md.render(body)
          },  
          vue: true
        }
})

my markdown-file looks like this

---
title: Example
subtitle: Example Markdown File with Vue Component
---
# Heading 1
This is an Paragraph

<ImageViewer>  //renders to -> <imageviewer></imageviewer>

my page.vue looks like this:

<template>
     <div class="mt-8" v-html="body" />
</template>

<script>
import ImageViewer from '../../components/media/imageViewer'
import content from '../content/static/test.md'

export default {
    extends: content.vue.component,
    layout: 'static',
    components: {
        Page, ImageViewer
    },
    data() {
        return {
            body: content.html,
            title: content.attributes.title
        }
    },
}

Where is my mistake? I not get any issues in the dev console...

Another quick question. How can i get all .md files with all attributes, so i can create a dynamic blog home page with previews from all blog posts and links to each blog post? How can i do this easily in nuxtjs without a middleware or server?

"[WARN] Cannot stringify a function render" after upgrade to 3.x

I've been building a static blog with Nuxt.js, and I'm using frontmatter-markdown-loader with [Mode.VUE_RENDER_FUNCTIONS] to render Markdown pages and posts which contain Vue components. This was working great on v2.3.0, but after upgrading to v3.1.0, I cannot properly render Markdown files which are loaded dynamically using Nuxt's asyncData function.

Here's my dynamic render component:

<!-- components/DynamicMarkdown.vue -->

<script>
export default {
  props: {
    renderFn: {
      type: Function,
      required: true,
    },
    staticRenderFns: {
      type: Array,
      required: true,
    },
  },
  data() {
    return {
      templateRender: null,
    };
  },
  created() {
    this.templateRender = this.renderFn;
    this.$options.staticRenderFns = this.staticRenderFns;
  },

  render(createElement) {
    return this.templateRender ? this.templateRender() : createElement('div', 'Rendering...');
  },
};
</script>

And here is the page component for individual blog posts:

<!-- pages/blog/_slug.vue -->

<template>
  <DynamicMarkdown
    :render-fn="renderFn"
    :static-render-fns="staticRenderFns"
  />
</template>

<script>
import DynamicMarkdown from '~/components/DynamicMarkdown.vue';

export default {
  components: {
    DynamicMarkdown,
  },
  async asyncData({ params }) {
    const article = await import(`~/content/articles/${params.slug}.md`);
    return {
      renderFn: article.vue.render,
      staticRenderFns: article.vue.staticRenderFns,
    };
  },
};
</script>

This works if I link to a blog post from somewhere else in the app (ie, the post is rendered client-side). However, if I reload the page, or if I visit the permalink directly, the page crashes and I see several errors. In the browser console, I get TypeError: this.templateRender is not a function.

Screenshot 2019-11-09 12 37 26

And in the terminal I see two warnings: WARN Cannot stringify a function render and WARN Cannot stringify a function.

Screenshot 2019-11-09 12 37 52

With FML version 2.3.0, this approach worked fine, both with client-side and server-side rendering.

Another releveant bit of information is that if I first load a Markdown file at the top of my <script> section using regular ES6 module syntax, everything works fine.

The following code allows the page to be loaded either client-side or server-side:

<!-- pages/blog/_slug.vue -->

<template>
  <DynamicMarkdown
    :render-fn="renderFn"
    :static-render-fns="staticRenderFns"
  />
</template>

<script>
import DynamicMarkdown from '~/components/DynamicMarkdown.vue';
import article from '~/content/articles/2019-10-14-my-post.md';

export default {
  components: {
    DynamicMarkdown,
  },
  data() {
    return {
      fm: null,
      renderFn: null,
      staticRenderFns: null,
    };
  },
  created() {
    this.fm = article.attributes;
    this.renderFn = article.vue.render;
    this.staticRenderFns = article.vue.staticRenderFns;
  },
};
</script>

Obviously, the previous code example is not practical since blog posts must be loaded dynamically by extracting the file name from params. Hence the need for asyncData imports.

In summary, if I import a Markdown file using ES6 module syntax, everything works. But if I import it inside asyncData it breaks.

If it helps to see a complete app that demonstrates this issue, please have a look at nuxt-markdown-blog-starter by @marinaaisa. I referenced her code a lot when building my own blog (thank you, @marinaaisa!), and after she recently upgraded FML to v3.0.0, her app manifests the exact problem I have described above.

I am aware that FML v3.0.0 introduced breaking changes, and as best I can tell the root issue is that vue.render and vue.staticRenderFns now return functions instead of strings. I've looked at your source code to try and find a workaround, but I'm afraid my understanding of Vue render functions is too rudimentary.

Thank you for all your work on frontmatter-markdown-loader. I really love this project since it enables Vue components to be embedded in Markdown files. This is a huge win for blogging, and I really hope a solution can be found to allow for asyncData file imports. I would appreciate any help or advice you can offer on this issue!

Using markdown-it plugin breaks the subcomponents inside the markdown file in nuxt

I'm having an issue rendering vue components within the markdown files when trying to use the highlightjs or prism to highlight code. I'm using Nuxt.

When my configuration is:

{
  test: /\.md$/,
  loader: 'frontmatter-markdown-loader',
  options: {
          mode: [Mode.VUE_COMPONENT]
  }

The components inside the markdown are rendered correctly, but then my code is not highlighted.

When I change the configuration to look like this:

{
  test: /\.md$/,
  loader: 'frontmatter-markdown-loader',
  options: {
          mode: [Mode.VUE_COMPONENT],
          markdownIt:{
            html: true
          }          
  }

Everything works ok too, which is expected as this is the default configuration.

However, if I try to use a markdownIt renderer or to extend for use with a highlighting plugin everything breaks.

const markdownIt = require('markdown-it');
const markdownItPrism = require('markdown-it-prism');

{
  test: /\.md$/,
  loader: 'frontmatter-markdown-loader',
  options: {
          mode: [Mode.VUE_COMPONENT],
          markdownIt: markdownIt({ html: true })
  }

or with the plugin

const markdownIt = require('markdown-it');
const markdownItPrism = require('markdown-it-prism');

{
  test: /\.md$/,
  loader: 'frontmatter-markdown-loader',
  options: {
          mode: [Mode.VUE_COMPONENT],
          markdownIt: markdownIt({ html: true }).use(markdownItPrism)
  }

The html (although html:true is there) is just rendered as normal text and the code is not highlighted either.

Am I missing something or is just that this functionality is not there? If the latter, is there any suggested workaround?

At this point I'm stuck either being able to highlight code if the Mode is Mode.html but this doesn't render the components within the markdown, or to render the components with Mode.VUE_COMPONENT but then the code is not highlighted.

Any help with this is appreciated. Thank you.

Cannot stringify POJOs with symbolic keys Symbol(Symbol.toStringTag)

Hi,
I keep getting the Cannot stringify POJOs with symbolic keys Symbol(Symbol.toStringTag) error when trying to do the following with Nuxt.js:

  async asyncData({ params, error, payload }) {
    const data = await import(`~/content/articles/${params.slug}.md`)
    return { article: data }
   }
  }```

Then in my template:

```html
<component class="markdown" :is="article.vue.component" />

Is it a know issue?

Nested components?

If my markdown includes a component, then that component is rendered fine.
But, if that component itself includes a child component, then that child component is not rendered (just looks like a custom tag in the HTML).
Should this work? If it should work, I'll try to provide a repro.
Thanks for this component, it's awesome!

How to use within a nuxt payload dynamic route

Is it possible to integrate this within a Nuxt payload dynamic route generator?

https://nuxtjs.org/api/configuration-generate/#speeding-up-dynamic-route-generation-with-code-payload-code-

I had something like this but I can only receive the slug and not the page data

function dynamicRoutes() {
  return [].concat(
    ...basePath.map(mdPath => {
      return glob
        .sync(`${mdPath}/*.md`, { cwd: 'content' })
        .map(filepath => {
            return {
                route: `${mdPath}/${path.basename(filepath, '.md')}`,
                payload: `${filepath}`
            }
        })
    })
  )
}

Multiple documents in the same file

We are using frontmatter-markdown-loader for defining the layout of our website and separate design from content. One of the things we need is being able to be able of filling different sections with custom HTML coming from Markdown sources. If relying on multiple documents, maintainement is a mess. Instead, we are working of adding support to this loader for several documents in the same file:
https://github.com/delapuente/frontmatter-markdown-loader/blob/multiple/docs/options.md#multiple-mode

I'd want to know how feasible would be to merge both projects or if you prefer we keep a separated version.

You can check the code at:
https://github.com/delapuente/frontmatter-markdown-loader/tree/multiple

The credit for the separator inspiration goes for:
https://github.com/jonschlinkert/section-matter

Output HTML is raw?

Hi

I'm currently try to understand the loader and want to start with a
very basic example. It works but the html output is raw.

<template>
    <div>
        <h1 style="font-size:30px;">{{ post.attributes.title }}</h1>
        <div class="content">
            {{ post.html }}
        </div>
    </div>
</template>
<script>
  import post from "~/content/mypost.md";
  
  export default {
    asyncData() {
      return {
        post
      }
    }
  }
</script>
Yo see my first blog post!
<p>... it's going to <strong>happen</strong>!</p>

Any way of using dynamic data from database for vue components?

In cases where you have some md strings(not files that you require) loaded from the databases for example

{
name,
description, // description is an md formated text
}

And I would like to render that md text, simlier to how you can do it with markdown-it-vue

How can we enable code highlighting for markdown ?

Just got stuck on implementing code higlighting .Can I use hightlight.js for code highlighting if so How ?

I tried adding highlight to nuxt.config.js for the markdownIt key but still it is not working

Dynamic attribute.permalink possible?

Hi instead of adding the url manually to frontmatter header is it possible to add the url (mostly the filename) to the attributes array?

<nuxt-link to="post.attributes.permalink">{{ post.attributes.title }}</nuxt-link>

Vue is undefined in 2.0.0

I've been trying to debug an issue with loading Markdown files in Nuxt, and have finally narrowed it down to a versioning issue for this loader.

You can test here: https://codesandbox.io/s/nuxt-markdown-blog-starter-g83c5

File attributes are successfully loaded in /pages/index.vue and /pages/blog/_slug.vue, but in the latter, .vue is undefined.

This seems to have broken in 2.0.0 If you change to 1.8.0 and restart the server, that fixes the problem.

vue: Unknown custom element from .md

Hi, I'm not sure what I'm doing wrong, but my vue-component doesn't get render from .md file

<template>
  <vHeading lvl="1">Nice to see you.</vHeading> // <- get's rendered
  <component :is="getMarkdownComponent(section)" />
<script>
  import vHeading from '@primitives/heading/heading.vue'
  import mdHeading from '@primitives/heading/docu.md'

  export default {
    extends: mdHeading.vue.component,
    components: {
      vHeading
    },
    methods: {
      getMarkdownComponent(section) {
        const md = require(`@primitives/${section}/docu.md`)
        return md.vue.component
      },

my markdown file

---
subject: Hello
tags:
  - tag1
  - tag2
---
# Title
## Title

<vHeading lvl="1">Nice to see you.</vHeading> // <- doesn't get rendered

message

The content gets displayed, only my vue-component doesn't get rendered. I get only this error

"Unknown custom element: vHeading"

inline-code is missing from `vue.render` in child component

Bug report

  • version: 1.5.2
  • nuxt: 2.3.4

steps to reproduce

  1. clone this project https://github.com/sammyne/nuxt-playground
  2. cd nuxt-playground
  3. yarn
  4. yarn dev
  5. open the browser and navigate to localhost:3000/todo/todo

expectation

a page with content as

Hello Todo
func main() {
  fmt.Println("hello world")
}
hello world more 111-hello world-222


<h1>Hello Todo</h1> <pre><code class="language-go">func main() { fmt.Println(&quot;hello world&quot;) } </code></pre> <p>hello world more 111-<code>hello world</code>-222</p>

but got

Hello Todo
func main() {
  fmt.Println("hello world")
}
hello world more 111-


<h1>Hello Todo</h1> <pre><code class="language-go">func main() { fmt.Println(&quot;hello world&quot;) } </code></pre> <p>hello world more 111-<code>hello world</code>-222</p>

Comment

as seen, the inline code block hello world and the -222 after it has been truncated, but what's produced in the md.html properties is correct in the parent component _slug.vue

Needs somebody's kind help~

How can i parse elements from parsed html?

My parsed html looks like this:

<h1 id="heading1">Heading 1></h1>
<p>This is an paragraph</p>
<h1 id="heading2">Heading 2></h1>
<p>This is an paragraph</p>
<h1 id="heading3">Heading 3></h1>
<p>This is an paragraph</p>

How can i get all headings to create a navigation for each markdown file, so i can do this:?

<nav>
     <li v-for="(index, heading) in headings" :key="index">
         <a href="# + {{ heading.id }}">{{ heading.title }}</a>
     </li>
</nav>

Can i use DOMParser to parse headings from html string?

Render and staticRenderFns in SSR

In version 1.8.0, we can set the render and staticRenderFns to data via asyncData since it was a string, but in the current version, I think we can't do that. Is there any workaround for that?

Possible to have vue-loader process images?

I'm using this in a Nuxt project and I was kind of hoping it would just work with assets but it doesn't.

![GitHub Logo](~/img/github.png)
![GitHub Logo](~assets/img/github.png)
<img src="~assets/img/github.png" />
<img src="~/img/github.png" />

None of these render the image, the URL is never processed.

A workaround is using the static folder instead of assets but I'd rather get assets working with this if possible!

Any thoughts or ideas?

Vue component appears to be parsing mustache tags within code snippets

When using frontmatter-markdown-loader in Vue component mode, code examples from the markdown file that are in handlebars seem to be getting parsed out. For example:

<h1>{{ title }}</h1>

The header will show up blank. And in another case:

<template>
  <div>
    writing index
    <section>
      <ol>
        <li v-for="post in posts" :key="post.attributes.title">
          <nuxt-link :to="post.path">
            {{ post.attributes.title }}
          </nuxt-link>
        </li>
      </ol>
    </section>
  </div>
</template>

The component is failing to render, saying that "attributes is undefined."

You can see my current setup at https://github.com/henryjin3/henryjin-dev/tree/vuemarkdown.

Edit: forgot to mention, this only happens when I switch to Vue component mode, and using standard HTML mode with markdown-it works just fine.

Array in frontmatter is not correctly parsed

Imagine I have the following frontmatter:

---
- 1
- 2
- 3
---
# Markdown content

These attributes should be parsed as an array but due to the recently addition of the _meta field to the attributes object in 2dd5cca, this is no longer possible. Is this intended? Would it be possible to add the _meta field to the top structure? In the same way we do:

md = import('something.md')
md.html
md.attributes
md.meta

Pure date gets parsed into UTC timestamp

I'm having an issue where my frontmatter contains an attribute that's a pure date, for example:

date: 2019-08-31T12:00:00-06:00
last_update: 2020-04-04

Here date is converted OK, as expected, into an ISO8601 timestamp, but the last_update date, instead of being converted into an ISO8601 date it gets converted into a full timestamp.

date: "2019-08-31T18:00:00.000Z"
last_update: "2020-04-04T00:00:00.000Z"

Is there anyway to tweak this behavior?
Ideally the output I'd be looking for is to have this:

date: "2019-08-31T18:00:00.000Z"
last_update: "2020-04-04"

Given a timestamp, receive a timestamp.
Given a pure date, receive a pure date.

(I know I can define last_update as "2020-04-04" but I'd like to avoid having to put quotes around the date in the frontmatter.)

Is it possible to render markdown and a component within the markdown?

I'm confused about the 'Mode' settings.

If I have a markdown file test.md like this:

---
title: my title
---

This is some sample markdown.

## Header 1

This is more sample markdown

<displayDate></displayDate>

How do I configure the loader so that (a) I get the title, body, and Vue component displayDate?

In other words, I want to embed Vue components within my markdown file and then render everything together. Sort of like how VuePress does it -- the markdown and the components.

Does frontmatter-markdown-loader do this? I've looked at the Vue CLI sample project, and I'm confused.

Access attributes etc

I'm having trouble accessing any of the properties after importing md files.

Here's my code:
nuxt.config.js

{
  test: /\.md$/,
  loader: 'frontmatter-markdown-loader'
}

component.vue

import md from '~/content/events/my-markdown-file.md'

In this case md is the correctly rendered markup from the md file but md.attributes, md.body and md.html are all undefined.

What am I doing wrong?

Cannot stringify POJOs with symbolic keys Symbol(Symbol.toStringTag)

Hi,

First of all thanks for your work, I make a project width fml and I getting this error:

annot stringify POJOs with symbolic keys Symbol(Symbol.toStringTag)

Despite my research, I can't solve my problem, please can you help me ?

That's my vuex store:

export const state = () => ({
  contact: [],
  header: [],
  profile: [],
  portfolio: [],
  experience: [],
  diploma: [],
  skillz: []
})

export const getters = {
  getContact(state) {
    return formatMd(state.contact)
  },

  getHeader(state) {
    return formatMd(state.header)
  },

  getProfile(state) {
    return formatMd(state.profile)
  },

  getPortfolio(state) {
    return formatMd(state.portfolio)
  },

  getExperience(state) {
    return formatMd(state.experience)
  },

  getDiploma(state) {
    return formatMd(state.diploma)
  },

  getSkillz(state) {
    return formatMd(state.skillz)
  },

  getLanguages(state) {
    return formatMd(state.languages)
  }
}

export const mutations = {
  setContact(state, contact) {
    state.contact = contact
  },

  setHeader(state, header) {
    state.header = header
  },

  setProfile(state, profile) {
    state.profile = profile
  },

  setPortfolio(state, portfolio) {
    state.portfolio = portfolio
  },

  setExperience(state, experience) {
    state.experience = experience
  },

  setDiploma(state, diploma) {
    state.diploma = diploma
  },

  setSkillz(state, skillz) {
    state.skillz = skillz
  }
}

export const actions = {
  async nuxtServerInit({ dispatch }) {
    await dispatch('fetchContact')
    await dispatch('fetchHeader')
    await dispatch('fetchDiploma')
    await dispatch('fetchProfile')
    await dispatch('fetchPortfolio')
    await dispatch('fetchExperience')
    await dispatch('fetchSkillz')
  },

  async fetchContact({ commit }) {
    try {
      const contact = await import(`~/assets/content/contact.md`)
      await commit('setContact', contact)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchHeader({ commit }) {
    try {
      const header = await import(`~/assets/content/header.md`)
      await commit('setHeader', header)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchProfile({ commit }) {
    try {
      const profile = await import(`~/assets/content/profile.md`)
      await commit('setProfile', profile)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchPortfolio({ commit }) {
    try {
      const portfolio = await import(`~/assets/content/portfolio.md`)
      await commit('setPortfolio', portfolio)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchExperience({ commit }) {
    try {
      const experience = await import(`~/assets/content/experience.md`)
      await commit('setExperience', experience)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchDiploma({ commit }) {
    try {
      const diploma = await import(`~/assets/content/diploma.md`)
      await commit('setDiploma', diploma)
    } catch (error) {
      console.error(error)
    }
  },

  async fetchSkillz({ commit }) {
    try {
      const skillz = await import(`~/assets/content/skillz.md`)
      await commit('setSkillz', skillz)
    } catch (error) {
      console.error(error)
    }
  }
}

function formatMd(mdObj) {
  return { attributes: mdObj.attributes, html: mdObj.html }
}

React version can't handle images

Markdown like this:

![Natural Healing Team](/static/Natural-Healing-team.jpg "Natural Healing Team")

Will result in this error:

./content/about-us.md
SyntaxError: unknown: Expected corresponding JSX closing tag for <img> (5:103)

  3 |           <div>
  4 |             <h1>About Us</h1>
> 5 | <p><img src="/static/Natural-Healing-team.jpg" alt="Natural Healing Team" title="Natural Healing Team"></p>

The code looks like it drops the HTML output of frontmatter directly into a react component, so I'm not sure how it's even possible to work around this (except for directly using HTML for images). I guess you'd have to go through the generated HTML and fix all the unclosed tags before letting React interpret it? :(

Need more html attributes than just body

For my project i need more parsed markdown attributes than just body. In my markdown file, i have mulitple footnotes. At the moment, a footnote consists entirely of text:

---
footnotes:
     - { id: note1, title: Note 1, description: This is a new footnote }
---

But i need more flexibility to add html content like links, images etc. The Problem is, that i want to render the footnotes in a different place than the body.

I know that i can use the DOMParser for that to split the html string, but there is no other solution that has a similar handle than the attributes?

Thanks for your help

How to use render function directly

Hey, I've been trying to create a reusable component for all my markdown files. I have gone through https://github.com/hmsk/frontmatter-markdown-loader-vue-sample but it explains how to create a component out of a single md file. What I would like to build is something like (note this is nuxt app btw):

// ~/pages/entries/_slug/index.vue
<template>
  <div>
  <h1>{{ entry.attributes.title }}</h1>
  <MarkdownPage :entry="entry"/>
  </div>
</template>
<script>
import page1 from "~/md/page1.md"
import page2 from "~/md/page2.md"


const MarkdownPage = {
  props: ["entry"],
  created() {
    this.render = new Function(this.entry.vue.render)()
    this.$options.staticRenderFns = new Function(this.entry.vue.staticRenderFns)()
  },
}


const entries = {
  'page-1': page1,
  'page-2': page2,
}

export default {
  components: { MarkdownPage },
  async asyncData({ params }) {
    const entry = entries[params.slug]
    return {
      entry,
    }
  }
}
</script>

And when I try to open that page I get an error:

render function or template not defined in component: MarkdownContent

So I tried to define render function:

render(createElement) {
  return this.entry.vue.component.render(createElement)
}

but I'm getting another error: this.entry.vue.component.render is not a function so I tried one more time after taking a look into the code but I failed at this point (not sure how should I use those entry.vue.render and entry.vue. staticRenderFns things).

Would appreciate some help here!

Compiling Vue component fails when markdown includes invalid Vue syntax

Hi! Thanks for making this brilliant tool, I'm currently using it in a Nuxt.js project.

I've found a bug, though. If my markdown includes code examples which are considered invalid Vue syntax an error is thrown.

For example:

```html<div>{{test->()}}</div>```

This will crash the compiler.

The thing is, that code is not Vue syntax, it's Laravel Blade syntax, but I think the compiler is confused and thinks it is maybe??? This only happens when vue is set to true in options.

Is there anyway to fix this or perhaps provide a way to escape the code so the compiler doesn't crash?

Support selective import

From: https://twitter.com/hmsk/status/1148660394463920128

Currently, html, body, vue.render (optional), vue.component (optional) are including the content which is based on markdown. In most of the use-case, the user wants just one of them and the whole build gets bigger unintentionally. So, the loader should support disabling specific member of importing. Probably, loader's option is the appropriate point to configure that.

default (vue is not enabled)

options: {
  mode: ["html", "body"]
}

Instead of vue: true (Everything is enabled)

options: {
  mode: ["html", "body", "vue-render", "vue-component"]
}

This will introduce the breaking change (remove vue: true)

If uses only vue.component

options: {
  mode: ["vue-component"]
}

Quasar

How would i be able to use quasar components inside md files using this loader?

When i try to use mode render:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: "TypeError: Cannot read property '_c' of undefined"

When using mode component:
q-dialog is not found

I hope someone can help :)

Possible to pass in props/data?

Basically what I want to do is make it so that you can do e.g. {{ foo }} in the markdown file and then I want to pass that down as a prop or as data somehow.

But vue.render and vue.render.staticRenderFns are strings so there's no real way to manipulate them.

Potential solution

Since the e.g. vue.render string looks like this:

return function render() {
  var _vm = this;
  var _h = _vm.$createElement;
  var _c = _vm._self._c || _h;
  return _c(
    'div'
    {staticClass: "comes from options.vue.root"},
    [...]
  );
}

...then it would be feasible to make that function take some props before you stringify it and pass it along to us:

return function render(props) {
  var _vm = this;
  var _h = _vm.$createElement;
  var _c = _vm._self._c || _h;
  return _c(
    'div'
    {
      props: props || {} // <-- here
    },
    [...]
  );
}

...then we would be able to do this:

  render (createElement) {
    return this.templateRender ? this.templateRender() : createElement("div", "Rendering");
  },

  created () {
    this.templateRender = new Function(fm.vue.render)({
      foo: "foo",
      bar: "bar"
    );
    // ^ here
    this.$options.staticRenderFns = new Function(fm.vue.staticRenderFns)();
  }

But I don't think that is the entire problem solved and that isn't going to magically make {{ foo }} and {{ bar }} work? Probably more needs to be done.

I just don't know enough about render functions to figure it out.

Update the README.md file

Maybe add the new way to configure Webpack to have a Vue component passed down.

I was going crazy because all the tutorials show it like this:

  build: {
    /*
    ** You can extend webpack config here
    */
    extend (config, ctx) {
      config.module.rules.push({
        test: /\.md$/,
        loader: 'frontmatter-markdown-loader',
        options: {
          vue: true
        }
      })
    }
  }

When with version 2, it's like this:

import Mode from 'frontmatter-markdown-loader/mode'
// ...

  build: {
    /*
    ** You can extend webpack config here
    */
    extend (config, ctx) {
      config.module.rules.push({
        test: /\.md$/,
        loader: 'frontmatter-markdown-loader',
        // include: path.resolve(__dirname, 'content'),
        options: {
          mode: [Mode.VUE_COMPONENT]
        }
      })
    }
  }

I think a little example on the README.md can help to quickly identify the new way of doing it.

Manipulation the resulting node tree

Substitute thread for @Strahinja on #83 (comment)

Current Mode.VUE_RENDER_FUNCTIONS allows manipulations on the resulting node tree, for example to highlight a search term. Is that possible with Mode.VUE_COMPONENT?

Of course. Here's the applyHighlight method I made:

    applyHighlight(node, h)
    {
        if (this.highlight.length>0 && node)
        {
            if (node.text)
            {
                if (node.text.length >= this.highlight.length)
                {
                    let result = [];
                    let i = 0;
                    let textSoFar = '';
                    while (i < node.text.length)
                    {
                        if (node.text.substring(
                            i,
                            i+this.highlight.length
                        )==this.highlight)
                        {
                            result.push(this._v(String(textSoFar)));
                            result.push(h('span', {
                                class: 'highlight'
                            }, this.highlight));
                            textSoFar = '';
                            i += this.highlight.length;
                        }
                        else
                        {
                            textSoFar += node.text.substring(i, i+1);
                            i++;
                        }
                    }
                    if (textSoFar.length>0)
                    {
                        result.push(this._v(String(textSoFar)));
                    }
                    return result;
                }
            }

            if (node.children && node.children.length>0)
            {
                let children = [];

                node.children.forEach(child =>
                {
                    const result = this.applyHighlight(child, h);
                    if (Array.isArray(result))
                    {
                        children = children.concat(result);
                    }
                    else
                    {
                        children.push(result);
                    }
                });
                node.children = children;
            }
        }
        return node;
    }
},

node is the resulting VNode, h is the function
to create them. I then just

render (createElement)
{
    return this.templateRender ? this.applyHighlight(this.templateRender(),
                                                     createElement) :
        createElement('div', 'Rendering...');
}

Where would I search for the highlighted text with Mode.VUE_COMPONENT? md.vue.component.$el?

Missing line breaks in code snippet

Many thanks for your loader 🙏!

I tried to add code snippets into some on my .md documents in a NextJS project and statically exported site. These snippets are not properly rendered. More precisely line breaks are, somehow removed and the full content get displayed on a single line.

I tried to dig into your loader and markdownIt but I got lost.
Have you ever heard about similar issue with NextJs and code snippets?
Would you have insights to share and helpp me troubleshoot that limitation?

Many thanks,

Working example:
File:
https://github.com/mes-aides/simulateur/blob/demo-break-code/contribuer/content/home.md

Render:
https://deploy-preview-48--mes-aides.netlify.app/

Project root:
https://github.com/mes-aides/simulateur/tree/demo-break-code/contribuer

(Another file:
https://github.com/mes-aides/simulateur/blob/demo-break-code/contribuer/content/tasks/ajouter-une-aide.md#v%C3%A9rifier-que-votre-environnement-est-fonctionnel---12-minutes-max

Render:
https://deploy-preview-48--mes-aides.netlify.app/tasks/ajouter-une-aide
In H2 « Préparer l'environnement de travail - 10 minutes max », H3 « Vérifier que votre environnement est fonctionnel - 12 minutes max »
)

(Plus I have a React warning, Warning: Invalid DOM property class. Did you mean className? but that's may be unrelated).

Passing data from frontmatter to component inside markdown

Hello,

I'm trying to access frontmatter attributes in a component rendered inside a Markdown page, but I'm having no luck so far. The setup I have is as follows:

nuxt.config.js

      config.module.rules.push({
        test: /\.md$/,
        include: resolve(__dirname, 'content'),
        loader: 'frontmatter-markdown-loader',
        options: {
          mode: [Mode.HTML, Mode.VUE_COMPONENT],
          vue: {
            root: 'dynamicMarkdown'
          }
        }
      });

contents/posts/post-1.md

---
images: [/blog/detail-1.jpg, /blog/detail-2.jpg]

---

This is a demo post with markdown.

<ImageGallery :images="images" /> // These should be the images from the frontmatter above but they don't show.

This is more content.

components/DynamicMarkdown.vue

<template>
  <div>
    <div v-html="content"></div>
  </div>
</template>

<script>
export default {
  name: 'DynamicMarkdown',
  props: {
    content: {
      type: String,
      default() {}
    },
    images: {
      type: Array,
      default() {}
    }
  }
};
</script>

components/ImageGallery.vue

<template>
  <v-container>
    <v-row>
      <v-col v-for="image in images" :key="image" :md="mdCols" cols="12" sm="6">
        <img
          :data-src="require('assets/images' + image)"
          :data-srcset="require('assets/images' + image).srcSet"
          alt="Image"
          sizes="(max-width: 600) 576px, (min-width: 601) and (max-width: 1263) 426px, (min-width: 1264) 272.25px"
          class="lazyload page-image"
        />
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  name: 'ImageGallery',
  props: {
    images: {
      type: Array,
      default() {}
    }
  },
  computed: {
    mdCols() {
      switch (this.props.images.length) {
        case 2:
          return 6;
        case 3:
          return 4;
        case 4:
          return 3;
        default:
          return 12;
      }
    }
  }
};
</script>

<style scoped></style>

pages/_slug.vue

<template>
  <div>
    <v-container>
      <v-row>
        <v-col>
            <DynamicMarkdown :content="contentHtml" :images="images" />
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>
<script>
import DynamicMarkdown from '~/components/DynamicMarkdown';

export default {
  name: 'BlogArticle',
  components: {
    DynamicMarkdown
  },
  async asyncData({ params }) {
    try {
      const post = await import(`~/content/posts/${params.slug}.md`);
      return {
        title: post.attributes.title,
        contentDate: post.attributes.date,
        images: post.attributes.images,
        contentHtml: post.html
      };
    } catch (err) {
      return false;
    }
  }
};
</script>

Would you be able to tell me how to achieve this?

Using the dynamic example B, I am unable to render local components in markdown

<template>
  <div>
    <h1>{{ title }}</h1>
    <component :is="dynamicComponent" />
  </div>
</template>

<script>
import NpmOrYarn from "./NpmOrYarn.vue";

  export default {
    props: {
      filename: {
        type: String,
      },
    },
    components: {
      NpmOrYarn,
    },
    data () {
      return {
        title: null,
        dynamicComponent: null,
      }
    },
    created () {
      const markdown = require(`../md/${this.filename}`);
      this.title = markdown.attributes.title
      this.dynamicComponent = markdown.vue.component
    },
  }
</script>

image

The local component isn't found by the dynamic component. In example C, the markdown component is extended to import the local components. How can the dynamic component be extended to import a component array?

Cannot stringify a function render ...etc with nuxtServerInit Vuex

Hi,

First thanks for FML !

I created an ecomerce PWA and i use FMT for load some content from md files.

Everything work fine but when I use nuxt un dev mode, at the moment of the app started my console log this warn:

 WARN  Cannot stringify a function data                                                                                                                      12:46:02  


 WARN  Cannot stringify a function render                                                                                                                    12:46:02  


 WARN  Cannot stringify a function created     

I was wrong ?

My vuex store

export const actions = {
 async nuxtServerInit({ dispatch }) {
    await dispatch('getProducts')
  },

async getProducts({ commit }) {
    const files = await require.context(
      '~/assets/content/prestations/',
      false,
      /\.md$/
    )

    const products = files.keys().map((key) => {
      const res = files(key)
      res.slug = key.slice(2, -3)
      return res
    })

    await commit('setProducts', products)
  },
}

export const mutations = {
setProducts(state, products) {
    state.products = products
  },
}

Shop list component

<template>
  <base-container>
    <v-row justify="start">
      <v-col cols="12">
        <base-small-header
          id="particuliers"
          class="text-md-left"
          subtitle="Mes prestations de coaching en réel et digital à la carte"
          title="Les prestations de coaching"
        />
      </v-col>
      <v-col
        v-for="(product, index) in productsList"
        :key="product + index"
        cols="6"
        xs="6"
        sm="6"
        md="3"
        lg="3"
        xl="3"
        :order="product.attributes.order"
      >
        <cj-product-card
          :image="product.attributes.image"
          :title="product.attributes.title"
          :price="product.attributes"
          :slug="product.slug"
          :no-stock="product.attributes.noStock"
          :reduc="product.attributes.reduc"
        />
      </v-col>
    </v-row>
  </base-container>
</template>

<script>
export default {
  data: () => ({
    productsList: []
  }),

  async created() {
    const productsList = await this.$store.state.products.filter(
      (products) => products.attributes.category === 'Coaching'
    )

    this.productsList = productsList
  }
}
</script>

Shop _slug page

<template>
  <article style="padding-top: 45px;">
    <base-container v-if="productMeta.category">
      <div v-if="productMeta.category !== 'Cartes cadeaux'">
        <pricing-item
          :product="productMeta"
          :average-ratings="averageRatings"
        />
      </div>
      <v-row>
        <v-col cols="12">
          <base-small-header
            class="text-left"
            title="Détail de la prestation"
          />
        </v-col>
        <v-col cols="12">
          <section class="markdown-content">
            <component :is="productBody" />
          </section>
        </v-col>
        <v-col
          v-if="productMeta.category === 'Cartes cadeaux'"
          cols="12"
          class="text-center"
        >
          <base-button aria-label="s'inscrire">
            offrir la carte cadeau
          </base-button>
        </v-col>
      </v-row>
      <v-row v-if="averageRatings > 0">
        <v-col cols="12">
          <base-small-header title="Ils racontent leurs expériences" />
        </v-col>
        <v-col
          v-for="(testimony, index) in productMeta.testimonials"
          :key="index"
          cols="12"
          xs="12"
          sm="6"
          md="4"
          lg="4"
          xl="4"
        >
          <cj-testimony
            :title="testimony.title"
            :author="testimony.author"
            :rating="testimony.rating"
            :content="testimony.content"
          />
        </v-col>
      </v-row>
    </base-container>
  </article>
</template>

<script>
import { mdiArrowLeft } from '@mdi/js'

export default {
  data: () => ({
    mdiArrowLeft,
    productMeta: {},
    productBody: null,
    averageRatings: 0
  }),

  async created() {
    const markdown = await import(
      `~/assets/content/prestations/${this.$route.params.slug}.md`
    )
    this.productMeta = markdown.attributes
    this.productBody = markdown.vue.component
  },
}
</script>

Nuxt config

config.module.rules.push({
        test: /\.md$/,
        include: path.resolve(__dirname, 'assets/content'),
        loader: 'frontmatter-markdown-loader',
        options: {
          mode: [Mode.VUE_COMPONENT, Mode.BODY],
          vue: {
            root: 'markdown-body'
          }
        }
      })

Use HTML tags within markdown files?

This package is helping me solve the same problem you seem to have ran into, thanks so much for publishing!

I am having a bit of trouble figuring out how to use HTML tags within the markdown files. My main use case is links that contain target="\_blank" rel="nofollow". I'm trying to use markdown-it as the markdown compiler and have imported with their html: true option, but am still seeing the full <a> tag being rendered in plaintext rather than a link being rendered.

sample from my nuxt.config.js:

let md = require('markdown-it')({
  html: true
})

build: {
    extend(config, { isDev, isClient }) {
      config.module.rules.push({
        test: /\.md$/,
        loader: 'frontmatter-markdown-loader',
        options: {
          markdown: body => {
            return md.render(body)
          }
        }
      })
    }
  }

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

How can we access the markdown attributes right from nuxt.config.js?

I need to create filter function in order to build sitemap from dynamic article routes. The filter function will work to filtering out published article by read the status attributes inside each markdown files.

The problem is I cannot find the right way to access & iterate each markdown attributes directly from nuxt.config.js.

Because of I'm use this repo brevifolia-nuxt-forestry as my project base. I've try to create function by modified the default nuxt.config.js like this:

const dynamicRoutesPublished = getDynamicPathsPublished({
  '/content/blog/': 'content/blog/*.md',
})

...

function getDynamicPathsPublished(urlFilepathTable) {
  const stories = [].concat(
    ...Object.keys(urlFilepathTable).map(url => {
      const filepathGlob = urlFilepathTable[url];
      const routes = glob
        .sync(filepathGlob)
        .map(filepath => `${url}/${path.basename(filepath, '.md')}`);
      return routes
    })
  )
  const filtered = stories.map(story => {
     const storyName = '~'+story+'.md'
     const published = require(storyName)
     console.log(published)
  })

console log output is
Cannot find module '~/content/blog/my-another-post.md'

Trying to import the file directly

import post from "~/content/blog/my-another-post.md"

also give the same output
Cannot find module '~/content/blog/my-another-post.md'

Is there anything wrong with my function or something I missed?

Thank you

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.