Interactive Vue Islands with Sitecore and Astro

Anton Tishchenko
Anton Tishchenko
Cover Image for Interactive Vue Islands with Sitecore and Astro

We discussed using React interactivity inside your Sitecore Astro website in the previous post. Today, we will talk about the same, but for Vue.

Sitecore JSS supports 4 web frameworks: Angular, Vue, React, and Next.js. The modern web development trend is to use SSG(Static Site Generation) for the content pages. From the framework that Sitecore supports, only Next.js allows you to generate static pages. Static pages allow us to get better website performance and decrease hosting costs(if use them wisely). There is also a straightforward way for React. If your Sitecore website is based on React, you can easily migrate it to React + Next.js. And it actually happens, according to our analysis of NPM package download statistic.

You don’t have a straightforward option for Vue. Usually, when you use Vue the way of starting using SSG will be using Nuxt. Sitecore JSS does not support the Nuxt framework. But, if you understand how Sitecore headless websites work, you can add it yourself.

Another option is using Astro! Astro is the ideal choice for content-based sites. It was designed as a content-centric framework, compared to React/Vue/Angular, which are app-centric frameworks. If you have Sitecore JSS websites that are based on Vue, you can easily get an SSG website based on the Astro framework. Vue is officially supported by the Astro team. You can get a Sitecore SSG website from your existing Sitecore Vue website in a few days.

Installation

First of all, you need to set up the required NPM packages

npm install @astrojs/vue
npm install vue

Then add Vue integration to the Astro config:

import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';

export default defineConfig({
  // ...
  integrations: [vue()],
  //             ^^^^^
});

That is it, you are ready to use Vue with Astro.

Simple component

Now Astro understands the .vue extension and you can add components, for example:

<template>
    <div className="flex">
      <div>
        Count: {{ count }}
      </div>
      <button v-on:click="count += 1" class="btn btn-primary m-2">
        Increment
      </button>
      <button v-on:click="count -= 1" class="btn btn-primary m-2">
        Decrement
      </button>
    </div>
</template>

<script>
export default {
  name: 'Counter',
  props: {
    count: {
      type: Number,
      default: 0,
    }
  }
};
</script>

And we call this Vue component from the Astro:

---
import StyleguideSpecimen from '../styleguide/Styleguide-Specimen.astro';
import Counter from './vue/Counter.vue';
---

<StyleguideSpecimen
  route={Astro.props.route}
  e2eId="styleguide-integration-vue-simple"
>
  <Counter client:load />
</StyleguideSpecimen>

Rendering Sitecore fields

Rendering Sitecore fields from the Vue components is still available:

<template>
  <div class="contentBlock">
    <sc-text tag="h6" class="contentTitle" :field="fields.heading" />
    <sc-rich-text class="contentDescription" :field="fields.description" />
  </div>
</template>

<script>
import { Text, RichText } from '@sitecore-jss/sitecore-jss-vue';

export default {
  name: 'ContentBlock',
  props: {
    fields: {
      type: Object,
      default: () => ({}),
    },
    params: {
      type: Object,
    },
    rendering: {
      type: Object,
    },
  },
  components: {
    ScText: Text,
    ScRichText: RichText,
  },
};
</script>

We need just pass the proper props from the Sitecore layout service:

---
import StyleguideSpecimen from '../styleguide/Styleguide-Specimen.astro';
import ContentBlock from './vue/ContentBlock.vue';
---

<StyleguideSpecimen
  route={Astro.props.route}
  e2eId="styleguide-integration-vue-sitecore-content"
>
  The same fields output but using Vue based component.
  <ContentBlock client:load fields={Astro.props.route.fields} />
</StyleguideSpecimen>

Placeholders

Page composition using placeholders inside Vue is also still available:

<template>
  <sc-placeholder
    name="vue"
    :rendering="rendering"
    :params="params"
    :componentFactory="{componentFactory}"
  />
</template>

<script>
import { Placeholder } from '@sitecore-jss/sitecore-jss-vue';

export default {
  name: 'Placeholder',
  props: {
    rendering: {
      type: Object,
    },
    params: {
      type: Object,
    },
    componentFactory: {
      type: Function,
    },
  },
  components: {
    ScPlaceholder: Placeholder,
  },
};
</script>

We need to pass Vue components factory together with page presentation JSON.

---
import StyleguideSpecimen from "../styleguide/Styleguide-Specimen.astro";
import Placeholder from "./vue/Placeholder.vue";
import ComponentFactory from "./vue/componentFactory";
---

<StyleguideSpecimen
  route={Astro.props.route}
  e2eId="styleguide-integration-react-placeholder"
>
  <Placeholder
    rendering={Astro.props.route}
    componentFactory={ComponentFactory}
    params={Astro.props.params}
    />
</StyleguideSpecimen>

<script is:inline>
  if (window.top.Sitecore != null) {
    const chromeTags = document.getElementsByTagName("code");
    for (let i = 0; i < chromeTags.length; i++) {
      const element = chromeTags[i];
      if (element.attributes.getNamedItem("phkey") !== undefined) {
        const phKey = element.attributes.getNamedItem("phkey")?.value ?? "";
        if (element.attributes.getNamedItem("key")?.value === undefined) {
          element.setAttribute("key", phKey);
        }
      }
    }
  }
  </script>

Conclusion

As you can see from the examples, Sitecore Vue components work perfectly with Astro. It allows you to build an Astro SSG website using your existing Vue components. And with the Astro client directive, we can easily control, how Vue components should behave. They can be fully static, with no JavaScript logic on the client or loading them at once, or any other options depending on our needs. The existing Sitecore JSS Vue website could be turned into the SSG website using Astro without changing any of the components in the first stage at all.

Do you want to discuss the cons and pros of this method compared to Nuxt? Drop me a message, I would be glad to discuss it and show you the Sitecore + Astro + Vue demo.