Load Blocks on demand (Lazy Load) in Vue / Nuxt

I’m currently implementing a POC and pretty impressed by DatoCMS!

We are currently using the datacms-structured-text and it’s renderBlock feature in a Nuxt project which works as expected.

One thing though, as we’re focused on performance, we need to load components on demand to ensure only the necessary is JS is loaded on every page.

Something like :

renderBlock: async ({ record, key }) => {
      if (record.__typename === 'HeroRecord') {
        const hero = await import(`../components/${record.__typename.replace(/Record/g, '')}/index.vue`);
        return h(hero.default, {
          key,
          props: {
            title: record.title,
            description: record.description,
            image: record.image.responsiveImage,
          },
        })
      }
      return null
    },

Our attempt at this can be found here but it’s faling with this error : [Vue warn]: createElement() has been called outside of render function.

Any hint?

This is due to the fact that React/Vue components must return JSX in a synchronous fashion. I’m not proficient with Vue, but you should decouple the asynchronous loading of components from the synchronous rendering, ie.

  • on beforeMount:
    1. intercept all the different block types (__typename) contained in data.homePage.content (you can use unist utils for that);
    2. start the import() of the required components;
    3. once loaded, store them in local state;
  • inside the renderBlock method, check if component is already loaded. If so, use it, otherwise show a loading indicator.

Does it make sense @gabriel.slama?

Is does make sense Stefano, we’ll try with such implementation and get back to you.
Thanks for your enlightening suggestion.