[Vuejs]-Vue 3 h() with custom component

3👍

Wow, this was such a painful journey, yet the answer is so simple.

here is how you render vue components from the server dynamically, even if they’re mixed within html

I’m extremely surprised the answer is not in more places… people had me registering global components, using methods that didnt’t work. I actually eventually just stumbled across it on my own while trying to piece together tons of different answers.

Here’s the final version that:

  1. compiles vue code in realtime from the server
  2. does so with components and methods IN that component, without requiring global components
<script>
import { h } from 'vue';
import AppAlert from '@/components/AppAlert.vue';

export default {
  props: {
    content: {
      type: String,
      default: '',
    },
  },
  render() {
    const r = {
      components: {
        AppAlert,
      },
      template: `<div class="content">${this.content || ''}</div>`,
      methods: {
        hello() {
          // method "hello" is also available here
        },
      },
    };
    return h(r);
  },
};
</script>

If you have tons of components in your content you can also make them all async components:

components: {
  AppAlert: defineAsyncComponent(() => import('@/components/AppAlert.vue')), 
  ...

0👍

You should better use Vue slots for content instead of props

And you should also not interpolate HTML, since it will not work with components.

template: `<div class="content">${this.content}</div>`,

Use Vue Render Functions instead.

const { createApp, h, defineAsyncComponent  } = Vue;

const test = { template: 'Test' }
const PageCalculator = 
  defineAsyncComponent(() => {
    return new Promise((resolve, reject) => {                
       resolve( { template: 'My PageCalculator' } )
    })
  })

const CompiledContent = {
  template: 'Slot: <slot></slot>'  
}

const App = { 
  components:  {CompiledContent, PageCalculator }
}

const app = createApp(App)
const vm = app.mount('#app')
#app { line-height: 2; }
[v-cloak] { display: none; }
<div id="app" v-cloak>
 <compiled-content><page-calculator></page-calculator></compiled-content>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

Leave a comment