huang-julien / nuxt-runtime-compiler

A simple module to enable vue runtime bundle on Nuxt 2 and 3
17 stars 2 forks source link

Could you provide an example to create a render function in runtime? #11

Closed shtse8 closed 2 years ago

shtse8 commented 2 years ago

Thanks for the module. It saves me a lot!

Currently, I am using the following code to create render function but not sure if it is the proper way.

// DynamicComponent.vue
<script setup lang="ts">
import type { Component } from '@vue/runtime-core'
import { NuxtLink, SmartImage } from '#components'

const props = defineProps<{
  content?: string
}>()

const renderer = computed(() => () => h({
  template: props.content,
  components: {
    NuxtLink
  },
}))
</script>

<template>
  <component :is="renderer" />
</template>

There is many example after searching, but quite confusing which one should I use. I tried compile in your Readme, but there is no way to inject custom components. Or do I misunderstand somethings?

huang-julien commented 2 years ago

Hi @shtse8 , there's many ways to create a component, i've merged a commit with the playground filled with components using the template prop. You can even generate a list of components from an API and use provide()/inject() to make them available for you nested components.

huang-julien commented 2 years ago

@shtse8 i couldn't reproduce your issue, do your have a repo where i can reproduce it ?

The compile in the README solve an issue due to babel parser and estree walker being mocked in the nuxt config by default.

I think that you can directly return a VNode in your computed

const renderer = computed(() => h({
  template: props.content,
  components: {
    NuxtLink
  },
}))

let me know if it has been resolved

shtse8 commented 2 years ago

@shtse8 i couldn't reproduce your issue, do your have a repo where i can reproduce it ?

The compile in the README solve an issue due to babel parser and estree walker being mocked in the nuxt config by default.

I think that you can directly return a VNode in your computed

const renderer = computed(() => h({
  template: props.content,
  components: {
    NuxtLink
  },
}))

let me know if it has been resolved

My version is working, but not sure if it is the correct way to make it works. I am confusing to use h or other compile function and any the difference between these methods to create a component. Thanks for your example in playground. h should be the correct way.

huang-julien commented 2 years ago

compile was a workaround, prefer using template to define the component render function. The compiler SSR will cache the render function for the component see here

shtse8 commented 2 years ago

compile was a workaround, prefer using template to define the component render function. The compiler SSR will cache the render function for the component see here

do you mean it is better to use compile rather than h? because the ssrCompile will cache it? But how can I pass custom Component to compile function?

huang-julien commented 2 years ago

no i mean it's better to use

h({
  template: "<div></div>" <-- this
})

ssrCompile will compile the template then cache it.

using compile from vue

import { compile } from "vue"

{
  render: compile( "<div></div>" )
}

make the server-renderer compile your template each time it need to render the component.

Thanks for the module. It saves me a lot!

Currently, I am using the following code to create render function but not sure if it is the proper way.

// DynamicComponent.vue
<script setup lang="ts">
import type { Component } from '@vue/runtime-core'
import { NuxtLink, SmartImage } from '#components'

const props = defineProps<{
  content?: string
}>()

const renderer = computed(() => () => h({
  template: props.content,
  components: {
    NuxtLink
  },
}))
</script>

<template>
  <component :is="renderer" />
</template>

There is many example after searching, but quite confusing which one should I use. I tried compile in your Readme, but there is no way to inject custom components. Or do I misunderstand somethings?

To pass your components, import them then pass it into the component just like you did here :+1:

shtse8 commented 2 years ago

Got it !! Huge thanks!

shtse8 commented 2 years ago

@huang-julien One more question, I am embedding twitter plugin to my article which is generated using runtime compiler. the template containing a script tag. something like:

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">So here’s what Tesla’s Bitcoin payment screen looks like <a href="https://t.co/vbUdidzURR">pic.twitter.com/vbUdidzURR</a></p>&mdash; Whole Mars Catalog (@WholeMarsBlog) <a href="https://twitter.com/WholeMarsBlog/status/1374600604337672193?ref_src=twsrc^tfw">March 24, 2021</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Initial loading of page is working fine and the script will execute. But reenter the page, after routing in vue router, the script won't be executed. Do you have any idea to simply solve this issue without extracting the script to postprocess?

huang-julien commented 2 years ago

i wouldn't recommend you to pass directly <script> tags into template, vue normally don't allow it. What you can do is to vueuse/head composable to add your script. if you really need it in your template, try to pass:

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">So here’s what Tesla’s Bitcoin payment screen looks like <a href="https://t.co/vbUdidzURR">pic.twitter.com/vbUdidzURR</a></p>&mdash; Whole Mars Catalog (@WholeMarsBlog) <a href="https://twitter.com/WholeMarsBlog/status/1374600604337672193?ref_src=twsrc^tfw">March 24, 2021</a></blockquote>
<component is="script" async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<component is="script"> instead of `<script>