storyblok / storyblok-vue

Vue.js SDK for Storyblok CMS
MIT License
95 stars 20 forks source link

renderRichText : custom resolver not triggered #445

Open ChristPetitjean opened 1 year ago

ChristPetitjean commented 1 year ago

Describe the issue you're facing

When configuring a custom resolver globally OR once, it is not triggered

Reproduction

https://stackblitz.com/edit/vitejs-vite-1xmq7p?file=src%2Fmain.ts

Steps to reproduce

Open the repro url

Here you should have a console message because of this line: console.error(component); put in the main.ts file at root. And you should not have the bottom text because of the global resolver returning some static text instead.

But everything is ignored.

The aim of my resolver is to fix a BUG inside the vue version of the renderRich text where it try to render a story-link without using vue-router and therefore is ignoring every router config like BASE_URL. I was trying to adapt it by using the resolver.

Digging into your codebase 'around this particular method: https://github.com/storyblok/storyblok-js/blob/e5934867a61a9004218f359c434b25445e598ece/lib/index.ts#L102) I have a strong feeling that the resolver is only triggered when you put some blok in the richtext and not for everything. Is that a bug ? How to fix it ?

System Info

node: v18.16.0
@storyblok/vue: 7.3.1
pinia: 2.1.6
vue: 3.3.4
vue-router: 4.2.4
vuetify: 3.3.17
typescript: 5.2.0

Used Package Manager

npm

Error logs (Optional)

No response

Validations

ChristPetitjean commented 1 year ago

Found a way to overcome the issue: create my own schema extended from yours. Issues:

So ATM I created this file (the magic happens near href resolution with the if condition: linktype == 'story'

/// /src/custom_schema/index.ts
import clone from 'clone';
import { RichTextSchema } from '@storyblok/vue'
import { SbHelpers, type ISbNode, type ISbSchema } from 'storyblok-js-client'

const schema: ISbSchema = clone(RichTextSchema);
const isEmailLinkType = (type: string) => type === 'email'
schema.marks.link = (node: ISbNode) => {
    if (!node.attrs) {
        return {
            tag: '',
        }
    }
    const escapeHTML = new SbHelpers().escapeHTML
    const attrs = { ...node.attrs }
    const { linktype = 'url' } = node.attrs
    delete attrs.linktype

    if (attrs.href) {
        let baseUrl = '';
        if (linktype == 'story' && import.meta.env.BASE_URL && import.meta.env.BASE_URL.length > 1) {
            baseUrl = import.meta.env.BASE_URL.substring(0, import.meta.env.BASE_URL.length - 1);
        }
        attrs.href = baseUrl + escapeHTML(node.attrs.href || '')
    }

    if (isEmailLinkType(linktype)) {
        attrs.href = `mailto:${attrs.href}`
    }

    if (attrs.anchor) {
        attrs.href = `${attrs.href}#${attrs.anchor}`
        delete attrs.anchor
    }

    if (attrs.custom) {
        for (const key in attrs.custom) {
            attrs[key] = attrs.custom[key]
        }
        delete attrs.custom
    }

    return {
        tag: [
            {
                tag: 'a',
                attrs: attrs,
            },
        ],
    }
};

export default schema;

And then in the main.ts:

// main.ts
//....
import CustomSchema from './custom_schema';
//...
app.use(StoryblokVue, {
    //...
    richText: {
        schema: CustomSchema
    }
})