9

I'm using nuxt / content in my app and it's working fine. In another part of the app, I'd like to fetch some markdown from a database and display it.

let mytext = "Some *markdown* fetched from a db here."

<nuxt-content :document="mytext" />

This does not work because I'm missing a parsing step; when you do $content("a_page_title_here").fetch() it parses the fetched text and presents it to the component as structured json.

How do I use $content to parse text, so it can be passed to the component for display?

I'll bet there is a way to do it, but the documentation does not include a reference section that describes everything you can do with $content.

If there is an easy way to use the underlying Remark component, I can do that.

ccleve
  • 15,239
  • 27
  • 91
  • 157

4 Answers4

12

nuxt@3 and @nuxt/content@2

You can use @nuxt/content's Markdown transformer to parse an arbitrary string:

// ~/utils/parseMarkdown.js
import markdownParser from '@nuxt/content/transformers/markdown'

// first arg to parse() is for id, which is unused
export const parseMarkdown = md => markdownParser.parse('custom.md', md)

Then render it with @nuxt/content's ContentRendererMarkdown component like this:

<script setup>
import { parseMarkdown } from '~/utils/parseMarkdown'

const result = ref(null)
const loadMarkdown = async () => {
  const data = await $fetch('https://example.com/page.md')
  result.value = await parseMarkdown(data)
}
loadMarkdown()
</script>

<template>
  <ContentRendererMarkdown :value="result" v-if="result" />
</template>

demo 1

nuxt@2 and @nuxt/content@1

You can use the underlying Markdown class from @nuxt/content. Its async toJSON() function takes a filename or string (via gray-matter) that contains Markdown to parse, and resolves a JSON object that could be passed to <nuxt-content>.document.

To initialize Markdown with the default rehype plugins, use getDefaults() and processMarkdownOptions():

// ~/utils/parseMarkdown.js
import Markdown from '@nuxt/content/parsers/markdown'
import { getDefaults, processMarkdownOptions } from '@nuxt/content/lib/utils'

export async function parseMarkdown(md) {
  const options = getDefaults()
  processMarkdownOptions(options)
  return new Markdown(options.markdown).toJSON(md) // toJSON() is async
}

Then use it in your component like this:

<script>
import { parseMarkdown } from '~/utils/parseMarkdown'

export default {
  async asyncData({ $axios }) {
    const resp = await $axios.get('https://example.com/page.md')
    const page = await parseMarkdown(resp.data)
    return { page }
  }
}
</script>

<template>
  <nuxt-content :document="page" />
</template>

demo 2

tony19
  • 125,647
  • 18
  • 229
  • 307
  • `[plugin:vite:import-analysis] Missing "./parsers/markdown" specifier in "@nuxt/content" package`. It must have been changed. I wish we could get the same output as Nuxt offers for file-based Markdown for consistency. – Lukas Jul 26 '23 at 10:21
  • @Lukas Interesting. `@next/content/parsers/markdown` is from `nuxt@2` and `@nuxt/content@1`. Do you have the right versions installed? If so, you're probably right that they removed it. I haven't had a chance to check this yet. – tony19 Jul 26 '23 at 22:47
  • I'm sorry, I must have been tired and I missed the versions. I'm on Nuxt 3 and content 2... my bad. – Lukas Jul 27 '23 at 00:30
1

Thanks to tony19's answer, I was able to create simple component which renders passed string with Markdown content dynamically. Maybe it will be useful for somebody, too!

<script setup>
import markdownParser from "@nuxt/content/transformers/markdown"

const props = defineProps({
  markdownString: {
    type: String,
    required: true,
  }
});

const record = ref("");

watchEffect(async () => {
  await markdownParser.parse("custom.md", props.markdownString).then((md) => record.value = md);
});
</script>

<template>
  <ContentRendererMarkdown :value="record" v-if="record" />
</template>

Component usage example:

<MarkdownStringRenderer :markdownString="description" />

Markdown will be re-rendered each time description changes.

Hazadus
  • 78
  • 8
1

As an alternative you could use the marked npm package.

npm install marked
npm install @types/marked # For TypeScript projects

And use like this:

<script setup lang="ts">
import { marked } from 'marked';

const parsedDescription = computed(() => {
  return marked.parse(description);
});
</script>
Rens
  • 489
  • 5
  • 11
0

Would this not work?

const mytext = await this.$content('a_page_title_here').fetch()
tauzN
  • 5,162
  • 2
  • 16
  • 21
  • 2
    No, because $content looks for the text in a file on disk, and is not processing text from an external source. – ccleve Apr 09 '21 at 16:35