eligolf
eligolf

Reputation: 1866

Using live preview with Payload CMS with Vue

I am trying to incorporate live preview with my Payload CMS, using Vue 3 as front end. I have followed this "tutorial" starting at around 11:00 but this CMS is usually more geared towards React.

I have set up this super simple Pages.js collections:

const Pages = {
  admin: {
    useAsTitle: 'title',
    livePreview:{
      url: 'http://localhost:1234',
    }
  },
}
export default Pages

And I now want to connect it to Vue somehow I guess. I have my router index.js file which loads the Page component:

import { createRouter, createWebHistory } from 'vue-router'
import Page from '../views/Page.vue'

const routes = [
  {
    path: '/:slug', 
    name: 'Page',
    component: Page,
    props: true
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

And the page component itself is pretty simple at the moment since I only offer one block type "Hero" block:

<template>
  <div v-if="pageData">
    <div v-for="block in pageData.layout" :key="block.id">
      
      <hero-block v-if="block.blockType === 'hero'" :title="block.title" :subtitle="block.content[0]?.children[0]?.text" :imageURL="block.media?.url" :imageAlt="block.media?.['alt text']"></hero-block>

    </div>
  </div>
  <div v-else>
    <p>Loading...</p>
  </div>
</template>

<script>
import HeroBlock from '../blocks/HeroBlock.vue'

export default {
  name: 'Page',
  components:{
    HeroBlock
  },
  props: {
    slug: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      pageData: null
    }
  },
  async mounted() {
    await this.fetchPageData();
  },
  methods: {
    async fetchPageData() {
      try {
        const apiUrl = import.meta.env.VITE_API_URL;
        const response = await fetch(`${apiUrl}/pages?where[slug][equals]=${this.slug}`);
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const data = await response.json();
        this.pageData = data.docs[0];

        if (!this.pageData) {
          console.error('pageData is missing, load 404 here instead');
        }
      } catch (error) {
        console.error('Error fetching page data:', error);
      }
    },
  }
}
</script>

So I have two questions:

1. How can I incorporate the live preview functionality with Vue 3 as front end framework?

2. Since Payload seems pretty into React, should I consider another CMS? People in their discord thought I could still use it, but are there other good open source headless CMS:s that are more "Vue friendly"?

Upvotes: 0

Views: 531

Answers (1)

Krislunde
Krislunde

Reputation: 11

If your front-end application is built with Vue 3 or Nuxt 3, you can use the useLivePreview composable that Payload provides.

First, install the @payloadcms/live-preview-vue package:

npm install @payloadcms/live-preview-vue

Then, use the useLivePreview hook in your Vue component:

<script setup lang="ts">
import type { PageData } from '~/types';
import { defineProps } from 'vue';
import { useLivePreview } from '@payloadcms/live-preview-vue';

// Fetch the initial data on the parent component or using async state
const props = defineProps<{ initialData: PageData }>();

// The hook will take over from here and keep the preview in sync with the changes you make.
// The `data` property will contain the live data of the document only when viewed from the Preview view of the Admin UI.
const { data } = useLivePreview<PageData>({
  initialData: props.initialData,
  serverURL: "<PAYLOAD_SERVER_URL>",
  depth: 2,
});
</script>

<template>
  <h1>{{ data.title }}</h1>
</template>

Docs here. If you want to roll your own solution there's a guide for that in the docs just below the Vue entry.

As for your second question. Another fantastic headless CMS to consider is Directus. It also has live preview, and is very customizable. Bonus for you is that the admin panel is based on Vue, and not React.

Upvotes: 1

Related Questions