Incorporating dynamic component registration and display in Nuxt can be a valuable feature, but it does come with its own set of challenges as well.
Approach 1 - Compatible with SSR & SSG
This approach facilitates the dynamic registration of components while preserving Server-Side Rendering/Static Site Generation functionality within Nuxt. The only downside is that you are required to specify the names and file paths of all potential imported components. Although manageable for specific use cases (especially when dealing with a limited number of ACF fields), creating an entire component library using this method might become laborious.
<template>
<div>
<div v-for="field in page.acf" :key="field.uniqueId">
<component :is="field.type" :my-prop="field.content" />
</div>
</div>
</template>
<script>
export default {
components: {
hero: () => import('~/components/hero.vue'),
slider: () => import('~/components/slider.vue'),
testimonial: () => import('~/components/testimonial.vue')
},
data() {
return {
page: {
acf: [
{
uniqueId: 1,
type: 'hero',
content: '...'
},
{
uniqueId: 2,
type: 'slider',
content: '...'
},
{
uniqueId: 3,
type: 'testimonial',
content: '...'
}
]
}
}
}
}
</script>
Approach 2 - Limited to Client-Side Rendering
This method empowers you to dynamically register component names and their respective file locations programmatically. While saving you from enumerating each individual component manually, this technique does not support SSR or SSG. However, it could be the preferred choice if your project follows a Single Page Application (SPA) paradigm.
<template>
<div>
<div v-for="field in page.acf" :key="field.uniqueId">
<no-ssr>
<component :is="field.type" :my-prop="field.content" />
</no-ssr>
</div>
</div>
</template>
<script>
import Vue from 'vue'
export default {
data() {
return {
page: {
acf: [
{
uniqueId: 1,
type: 'hero',
content: '...'
},
{
uniqueId: 2,
type: 'slider',
content: '...'
},
{
uniqueId: 3,
type: 'testimonial',
content: '...'
}
]
}
}
},
mounted() {
const sections = this.page.acf
for (let i = 0; i < sections.length; i++) {
Vue.component(sections[i].type, () =>
import(`~/components/${sections[i].type}.vue`)
)
}
}
}
</script>
It's worth noting that the <no-ssr>
tag is becoming deprecated, and if you're working with Nuxt versions above v2.9.0
, you should consider using <client-only>
instead.
Tips Regarding Your Query
While I appreciate your attempt to streamline the data architecture, looping through your JSON object may pose a challenge due to the changing keys within each array object. Also, unnecessary objects in the data structure can complicate matters. I've restructured the data method to offer a simplified view for better comprehension.
To effectively implement the v-for loop, ensure that the component is nested inside an HTML tag with a v-for attribute, as exemplified above.
Consider sanitizing the data obtained from the WordPress API to prevent instances where WordPress provides a module that doesn't correspond to any existing component. Failing to align the supplied type with an actual component could disrupt the entire project build process.
I hope this clarifies things for you!
P.S. If anyone has insights on a methodology that enables setting component name and file location programmatically while still supporting SSG, I'd love to hear about it!