Parsing component references in CMS content in Nuxt

Parsing component references in CMS content in Nuxt

6 Jun 2022 javascript nuxt vue

What if you wanted to load CMS content into a Nuxt-powered web page, including parsing any component references in that content?

That's the position I found myself in on a recent project.

Let's load some CMS content via the asyncData hook, which runs in page components and allows us to merge the fetched content into the page component's data object.

export default { data() { return { //... }; }, async asyncData() { let article = await getContent('something'); //returns promise return {article}; } }

Let's assume the returned CMS content looks like this (note the reference to a custom component.):

<p>Hello, world</p> <some-component /> <p>Etc.</p>

Your first instinct, like mine, might be to hope that v-html would do the job of parsing component references, as it does for native HTML tags.

<div v-html='article'></div>

Alas, no dice. The component reference is stripped out, and all that's rendered is:

Hello, world Etc.

So what to do? The solution is to use the CMS content as the template for a dynamically-created Vue component. So rather than one created within Nuxt (i.e. by creating a file for it in /components), one instead created via Vue.component().

To do this we'll first need to import Vue into our page. Do this right before your component's export:

import Vue from 'vue' export default { //...

Now, in our asyncData hook, we can dynamically create our component.

async asyncData() { let article = await getContent('something'); let comp = Vue.component('article', { template: '<div>''</div>' }) return {article: comp};

If your CMS content already has a parent tag wrapping all content, you can omit the div tags.

Finally, where we want to render the article:

<component :is='article'></component>

Et voila! We have the equivalent to the v-html approach, except references to custom components will be rendered also.

Did I help you? Feel free to be amazing and buy me a coffee on Ko-fi!