Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render Blok Components within RichText #476

Open
1 task done
joezimjs opened this issue Jul 7, 2023 · 20 comments
Open
1 task done

Render Blok Components within RichText #476

joezimjs opened this issue Jul 7, 2023 · 20 comments
Labels
dx [Issue] Improvement or fix with impact on the developer experience. enhancement [Issue][PR] New feature pending-author [Issue] Awaiting further information or action from the issue author

Comments

@joezimjs
Copy link

joezimjs commented Jul 7, 2023

Description

Right now, there's no built-in way to render Blok components within rich text. This is odd... why would you give us the ability to embed bloks inside our rich text and then completely ignore that inside your SDKs? Sure, there are several "solutions" thrown around, but they all have issues:

The Astro Storyblok SDK has implemented this directly. I'm honestly quite surprised this hasn't been done for a while now.

Suggested solution or improvement

Implement a RichText component that will render blok component where bloks are used. Also, it would be nice to allow the rich text resolver to return VNodes so we can render custom components there, but if the first thing is implemented, I'm not sure what use I'd have for this.

Additional context

No response

Validations

@joezimjs joezimjs added enhancement [Issue][PR] New feature pending-author [Issue] Awaiting further information or action from the issue author pending-triage [Issue] Ticket is pending to be prioritised labels Jul 7, 2023
@Dawntraoz
Copy link
Contributor

Hi, @joezimjs, you are completely right in your statement; thanks for sharing your concerns with us. Actually, the Astro implementation is our first try at introducing this in our SDKs (I see you fast there 😏). As Astro is kind of new as an SDK in our list, it is easy to test new initiatives (it is less used by our clients) to then introduce this in the rest of the SDKs, so sooner than later, this will be implemented to the Nuxt SDK too (@alexjoverm do you want to add anything here?).

For now, about the links you mention, the 3rd one you should ignore it since we are using Nuxt 3 here, and that article is for the old Nuxt 2. For the FAQ and the runtime template compiler, for now, this is a working approach. I know it is not the ideal case, but for now, it is the simplest way.

As we always say, this is a community effort, we are trying to provide the most features we can, but we don't have a dedicated team for the SDKs. We help when we have less workload, so please, if any day you want to do a pair programming session with me or one of my colleagues or open a PR with the features you need we will be so happy to see it happening!

@Dawntraoz Dawntraoz added dx [Issue] Improvement or fix with impact on the developer experience. and removed pending-triage [Issue] Ticket is pending to be prioritised labels Jul 7, 2023
@joezimjs
Copy link
Author

I got something working in my own repository by creating a custom RichText component: https://github.com/joezimjs/nuxt-storyblok-poc/tree/main/components/rich-text
Basically converted everything into Vue components rather than using functions that return HTML. And the RTText component (for text nodes) handles all the different mark types. I'm not sure how to integrate something like this into storyblok-nuxt, primary because I'm not sure which of the auto-import features are available inside a plugin.

@joezimjs
Copy link
Author

joezimjs commented Jul 11, 2023

Hmm... now that I'm thinking about it, there may be a better way that relies on the marks/nodes functionality that is defined for renderRichText from @storyblok/js, which would allow this to automatically stay up-to-date if new node/mark types are added.

Also, I looked more closely at @storyblok/astro's implementation and it's not adequate to take care of bloks that are embedded inside other nodes (e.g. inside a bullet point item) because it only looks for bloks in the first level of content items, then renders the rest with the provided renderRichText from @storyblok/js. So, I guess I can't get on your butts for taking this long to implement it if none of the other teams have implemented it quite right yet either. :)

@joezimjs
Copy link
Author

joezimjs commented Jul 12, 2023

There! I changed it so it's all packed in one component and it takes advantage of the provided RichTextSchema and even allows a user to pass in a different schema. https://github.com/joezimjs/nuxt-storyblok-poc/blob/main/components/RichText.ts

It's missing just a few things:

  • Use configured schema from Storyblok options passed into the plugin.
  • Image optimization options (I noticed @storyblok/js's renderRichText does not support this either...)
  • Custom resolver (not sure if this should still be supported if we're rendering component for bloks, but it could be designed to use this by default and use StoryblokComponent if this resolver returns a falsey value)

@Youhan
Copy link

Youhan commented Mar 14, 2024

@joezimjs Thank you for your efforts on this. Here is how I added <NuxtLink and <NuxtImg components to your solution at https://github.com/joezimjs/nuxt-storyblok-poc/blob/main/components/RichText.ts. Hope it helps a bit.

Just like we check the node.type for blok we can also check for node.type === 'image'

import { NuxtImg, NuxtLink } from '#components'

// use NuxtImg for images
if (node.type === 'image') {
	return h(NuxtImg, {
		provider: 'storyblok',
		format: 'webp',
		quality: 75,
		src: node.attrs.src,
		alt: node.attrs.alt,
		title: node.attrs.title,
		loading: 'lazy',
		width: 700,
		sizes: '90vw md:570px lg:700px',
	})
}

and since link is a mark on the RenderTag function we can add a check for a tags:

if (tagItem.tag === 'a')
    return h(NuxtLink, { ...tagItem.attrs }, () => [innerNode])
return h(tagItem.tag, tagItem.attrs, innerNode ? [innerNode] : undefined)

@PP-Tom
Copy link

PP-Tom commented Apr 17, 2024

I've done a very simple fix for this:

<script setup lang="ts">
type Props = { text: any };
defineProps<Props>();

const renderText = (text: any) => {
	const markup = { type: 'doc', content: [text] };
	return renderRichText(markup);
};
</script>

<template>
	<template v-if="text?.content" v-for="element in text?.content">
		<template v-if="element.type === 'blok'" v-for="blok in element?.attrs?.body" :key="blok.id">
			<component :is="blok.component" :blok />
		</template>
		<div v-else v-html="renderText(element)"></div>
	</template>
</template>

I haven't thoroughly texted it yet but seems to be working.

@joezimjs
Copy link
Author

joezimjs commented Apr 17, 2024

@PP-Tom Looks pretty good but I don't think this will catch bloks that are embedded in a lower level of structure. For example, if you put a blok into a bullet point, the bulleted list will hit the renderRichText call and the blok inside it will never be seen by this component. It's the same problem as the first example I linked in my original post.

To be fair, I was complaining that Astro had this implemented already while Nuxt still hadn't, but Astro implemented it in a very similar way to this, so it's like I'm the only person who cares about low-level embedded bloks... and I'm not even sure how much I care because I don't know if I have any use cases for it, but I see it as a blind spot for everyone who tries to implement this.

@PP-Tom
Copy link

PP-Tom commented Apr 17, 2024

@PP-Tom Looks pretty good but I don't think this will catch bloks that are embedded in a lower level of structure. For example, if you put a blok into a bullet point, the bulleted list will hit the renderRichText call and the blok inside it will never be seen by this component. It's the same problem as the first example I linked in my original post.

Good point. I'm really surprised that StoryBlok's UI is built in Vue but it's been almost a year for a 1st party solution for this. I know it's a DX thing, but just surprised.

@joezimjs
Copy link
Author

Good point. I'm really surprised that StoryBlok's UI is built in Vue but it's been almost a year for a 1st party solution for this. I know it's a DX thing, but just surprised.

Right?!?

@alvarosabu
Copy link
Contributor

alvarosabu commented Apr 17, 2024

Hi @joezimjs @PP-Tom @Youhan jumping here to give some good news on Richtext topic.

I'm currently working on a framework agnostic solution for the Richtext Renderer that is potentially extendable to each major framework (vue, react etc). Between all the features the use-case for rendering Blok components is covered and was successfully tested on the PoC. And yes, it includes as well overwriting resolves like adding the NuxtLink 😉

The community has been very patient about this topic so I want to be transparent that there IS a work-in-progress solution for this, we just need to wait a little bit more so it's rolled out since we are discussing internally the DX.

Hope this brings a little bit of light to this topic, will keep you posted.

@joezimjs
Copy link
Author

Love to hear it!

@narr07
Copy link

narr07 commented Jun 8, 2024

Hai melompat ke sini untuk memberikan kabar baik tentang topik.Richtext

Saat ini saya sedang mengerjakan solusi agnostik kerangka kerja untuk Richtext Renderer yang berpotensi dapat diperluas ke setiap kerangka kerja utama (vue, react, dll). Di antara semua fitur, kasus penggunaan untuk merender komponen Blok tercakup dan berhasil diuji pada PoC. Dan ya, itu termasuk juga menimpa resolusi seperti menambahkan 😉NuxtLink

Komunitas telah sangat sabar tentang topik ini jadi saya ingin transparan bahwa ada solusi yang sedang dalam proses untuk ini, kita hanya perlu menunggu sedikit lagi sehingga diluncurkan karena kita sedang mendiskusikan DX secara internal.

Semoga ini membawa sedikit cahaya ke topik ini, akan membuat Anda tetap diposting.

So glad to hear that 😇

@moracabanas
Copy link

Sorry to bother this community but I wasted a lot of time trying to know why StoryblokRichText component wasn't getting imported in Nuxt when I check this issue.

It was so confusing to have Rich Text component example available on the documentation to see there is not implementation yet.

<StoryblokRichText :doc="blok.description" />

Please don't do that before implementing something because developers trust documentation.

I was getting:

Failed to resolve component: StoryblokRichText
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.

@alvarosabu
Copy link
Contributor

Hi @moracabanas, the module should be exporting the StoryblokRichText component from version 6.2.0 on. I prepared a small reproduction to show it is in fact the case https://stackblitz.com/~/edit/nuxt-starter-cwrbwd?file=app.vue

Could you please check if you are using the latest version of the module? If that's the case could you provide me a minimal reproduction link so I can help you?

Thanks

@alvarosabu
Copy link
Contributor

Screenshot 2024-11-13 at 15 03 51

@alvarosabu
Copy link
Contributor

@joezimjs Did you have a chance to test the new component? https://stackblitz.com/~/edit/nuxt-starter-cwrbwd?file=app.vue

@moracabanas
Copy link

Hi @moracabanas, the module should be exporting the StoryblokRichText component from version 6.2.0 on. I prepared a small reproduction to show it is in fact the case https://stackblitz.com/~/edit/nuxt-starter-cwrbwd?file=app.vue

Could you please check if you are using the latest version of the module? If that's the case could you provide me a minimal reproduction link so I can help you?

Thanks

That was my fault..
At first I considered to upgrade "@storyblok/nuxt" and it ended up in "^5.6.12"

I will try to upgrade to 6.

Thanks to point me to the right direction I will try that and see.

@alvarosabu
Copy link
Contributor

@moracabanas no worries, we are here to help 😊, let me know if you find any issue in the future.

@danissima
Copy link

danissima commented Nov 21, 2024

Hi, @alvarosabu! I tested StoryblokRichText in my project and it handles blok components just fine, but I get the Invalid watch source: undefined warning. It appears in your reproduction too as can be seen on a screenshot.

Also the real-time changes in Storyblok's visual editor don't seem to work properly when using this component, so I think it's worth to note that.

@alvarosabu
Copy link
Contributor

Hi @danissima thanks for the feedback, yes I'm working on a quickfix for the warning. I will also check the visual editor topic to see if i can reproduce it since it was working before.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dx [Issue] Improvement or fix with impact on the developer experience. enhancement [Issue][PR] New feature pending-author [Issue] Awaiting further information or action from the issue author
Projects
None yet
Development

No branches or pull requests

8 participants