nuxt / content

The file-based CMS for your Nuxt application, powered by Markdown and Vue components.
https://content.nuxt.com
MIT License
3.09k stars 624 forks source link

Add an composable to get the html content generated for `<ContentRenderer>` #2019

Open maximepvrt opened 1 year ago

maximepvrt commented 1 year ago

Is your feature request related to a problem? Please describe

Currently if I want get the html content generated by <ContentRenderer>, I need to generate a reference and extract the content with innerHTML.

Describe the solution you'd like

add a composable to return the html generated

Additional context

<script setup>
import { ref } from 'vue';
const route = useRoute();

const { data } = await useAsyncData('hello', () => queryContent(route.path).findOne());

const myComponent  = ref(null)

onMounted(() => {
  mjmlContent.value = myComponent.value.innerHTML;
});

watch(data, () => {
  setTimeout(function () {
    mjmlContent.value = myComponent.value.innerHTML;
  }, 50);
});

</script>

<template>
  <div ref="myComponent" v-show="false">
    <ContentRenderer :value="data" tag="mj-column"/>
  </div>
</template>
atinux commented 1 year ago

I am wondering if this is not possible by using the h method directly 🤔

maximepvrt commented 1 year ago

how to use this function ?

ryoheiw commented 1 year ago

I use Nuxt Content and would use the composable if it existed.

As a workaround, I run the data from const { data } = await useAsyncData('hello', () => queryContent(route.path).findOne()); through a function renderToText that I got from the Markdown Parser in the Nuxt Content codebase. I use html within my Markdown so I don't know if this helps you in particular.

const renderToText = (node: MarkdownNode): string => {
  if (node.type === "text") {
    return node.value!;
  }

  if (!node.children?.length) {
    return `<${node.tag}>`;
  }

  return `<${node.tag}>${
    node.children?.map(renderToText).join("") || ""
  }</${node.tag}>`;
};

renderToText(data.value.body.children?.[0])

It's the parser in the Nuxt Content codebase but reversed.

maximepvrt commented 1 year ago

@farnabaz @Atinux @danielroe Do you think it would be possible to move the generation of the view component into a composable? Currently, using the renderToText method suggested by @ryoheiw does not allow us to take advantage of rewriting the prose or specific components created. https://github.com/nuxt/content/blob/main/src/runtime/components/ContentRendererMarkdown.vue#L106-L116

dword-design commented 1 year ago

I created nuxt-content-body-html that does this but I think it would be better if it is integrated into this module.

// server/plugins/body-html.js

import { defineNitroPlugin, useNuxtContentBodyHtml } from '#imports'

const nuxtContentBodyHtml = useNuxtContentBodyHtml()

export default defineNitroPlugin(nitroApp => {
  const bodyHtmls = {}

  nitroApp.hooks.hook('content:file:beforeParse', async file =>
    // @nuxt/content will reset the file object somewhere between beforeParse and afterParse, open issue exists
    bodyHtmls[file._id] = await nuxtContentBodyHtml.generate(file)
  )
  nitroApp.hooks.hook('content:file:afterParse', file => (file.bodyHtml = bodyHtmls[file._id]))
})
maximepvrt commented 1 year ago

It's possible to use island components : https://roe.dev/blog/nuxt-server-components#case-study-nuxt-content (poke @danielroe) and use the directly the HTTP API POST /__nuxt_island/static-markdown-render with body {"props":{"path":"my-content-path"}}

kecrily commented 1 year ago

and use the directly the HTTP API POST /__nuxt_island/static-markdown-render with body {"props":{"path":"my-content-path"}}

I tried to use this solution, but it console

[Vue warn]: Component <Anonymous> is missing template or render function.
[Vue Router warn]: No match found for location with path "/__nuxt_island/static-markdown-render"
maximepvrt commented 1 year ago

@kecrily, have you tried restarting with run dev ?

an example : https://codesandbox.io/p/sandbox/nuxt-content-api-component-island-2kljn2

kecrily commented 1 year ago

@maximepvrt Thanks, I found the problem with my code, I used method: 'POST'. But according to your example, GET should be used.

maximepvrt commented 1 year ago

@kecrily I updated with method: 'POST': https://codesandbox.io/p/sandbox/nuxt-content-api-component-island-2kljn2