Getting started with Nuxt.js and BCMS

This is the Nuxt.js plugin documentation for the BCMS.

Starting a Nuxt.js project from scratch

If you are starting a Nuxt.js project from scratch, and want to connect it with BCMS, You can initialize Nuxt project by using the BCMS CLI. Through an interactive terminal questionary, BCMS cli will set it up for you.

To install BCMS CLI globally, run npm install @becomes/cms-cli -g. After that, you should be able to create a Nuxt project and connect it with BCMS by running: bcms --website create. Here you can read more about BCMS CLI. If you want to add BCMS to an existing Nuxt project, that's described here.

Adding BCMS to an existing Nuxt project

Developers usualy start Nuxt.js & BCMS with BCMS CLI projects by running bcms --website create, like described above. If you want to add BCMS to an existing Nuxt.js project, follow along.

First you'll need to install the BCMS Nuxt.js plugin by running nuxt-plugin-bcms. After that, add this code to your nuxt.config.js modules section:

modules: [
  ...
  [
    'nuxt-plugin-bcms',
    createBcmsNuxtConfig({
      cms: {
        origin: process.env.BCMS_API_ORIGIN /** your BCMS_API_ORIGIN */,
        key: {
          id:  process.env.BCMS_API_KEY /** your BCMS_API_KEY */,
          secret:  process.env.BCMS_API_SECRET /** your BCMS_API_SECRET */
        },
      },
      websiteDomain: process.env.ORIGIN || 'http://localhost:3000',
      media: {
        download: false,
      },
    }),
  ],
]

Getting data from BCMS in a Nuxt page

There are two ways how you can get data in Nuxt page.

The first is by using BCMS Client methods, available in Nuxt context with the name $bcms. The other way is by making API calls to the Nuxt middleware, by using $bcms.request( ... ). Depending on how complex your use case is, you'll chose the simpler on more complex one.

Getting data in a Nuxt.js page using BCMS Client

If you want to get an entry from Blog template, and the entry's slug is 'how-to-connect-bcms-and-nuxtjs', all you have to do is:

const { data } = useAsyncData(async (ctx) => {
  const blog = (await ctx?.$bcms.entry.get({
    template: 'blog',
    entry: 'how-to-connect-bcms-and-nuxtjs',
  })) as BlogEntry;
  return { blog }
});

For this particular use case, you will probably put this code in your blog/_slug.vue file, and set entry parameter to be dynamic, like this: entry: ctx.route.params.slug. After that, your blog's data is available in the blog variable.

Getting data using Nuxt middleware API

When using BCMS with Nuxt middleware API, you don't call BCMS API endpoints every time you need something from the CMS. Instead, Nuxt middleware caches the reponse data in RAM, prividing fast response time and more flexibility. Here's how to set it up:

Create a bcms.routes.ts file. Inside, create a simple configuration and an endpoint which will return list of all templates.

import { createBcmsMostServerRoutes, createBcmsMostServerRoute } from '@becomes/cms-most';

export default createBcmsMostServerRoutes({
  '/template-list.json': createBcmsMostServerRoute({
    method: 'get',
    async handler({ bcms }) {
      await bcms.template.pull();
      const result = await bcms.template.find(async () => true);
      return result.map((temp) => {
        return {
          title: temp.label,
          slug: '/' + temp.name,
        };
      });
    },
  }),
});

In the example above, there's an endpoint that returns a light model of all templates from the BCMS instance, containing only the title and slug properties of each template.

You can now call this endpoint inside of asyncData, as shown bellow:

const { data } = useAsyncData(async (ctx) => {
  const result = await ctx?.$bcms.request<Array<{ title: string; slug: string }>>({
    url: '/template-list.json',
  });
  return result;
});

Working with BCMSImage Nuxt.js component

Images on the web are great. High-quality, sharp ones. But, fast websites are even more great! Why can't there be both? Well, BCMS Image lets you have both. To simplify handling responsive images and performance optimization, BCMS comes with the BCMSImage component.

It automatically creates several variants of the source image, including WEBP format. To start, import BCMSImage component, and pass an object from BCMS, containing an image. In the example below, the prop is cover_image object.

<template>
  ...
  <BCMSImage :media="blog.meta.en.cover_image" />
</template>
<script lang="ts">
  import BCMSImage from 'nuxt-plugin-bcms/components/image.vue';
  export default Vue.extend({
    components: {
      BCMSImage,
    },
  });
</script>

Adding data from Nuxt.js to BCMS

Now the things got a bit more spicy 🌶️. Is there a website that doesn't have a contact form / newsletter subscription form? Comment form even. When working with modern static site generators like Nuxt.js, developers usualy end up using some 3rd party form providers. With BCMS, you don't need to do that. The same way you get data from BCMS, you can add or update data.

If you want to create a comment section, you could easily create a template, and name it Comment for example. It can contain properties like full_name and message.

In your Nuxt.js code, you'll have something like this:

<template>
  <form @submit="handleSubmit()">
    <label>
      <span>Your name</span>
      <input type="text" v-model="full_name" />
    </label>
    <label>
      <span>Your message</span>
      <textarea v-model="message"></textarea>
    </label>
  </form>
</template>
<script lang="ts">
  export default Vue.extend({
    data: {
      return {
        full_name: '',
        message: '',
      }
    },
    methods: {
      async handleSubmit() {
      const bcms = this.$bcms as BCMSNuxtPlugin;
      const date = new Date();
      await bcms.entry.create({
        templateId: '1234567', /** Your template ID */
        meta: [
          {
            lng: 'en',
            props: [
              {
                id: 'title-prop-id', /** Your title prop ID */
                data: [`Comment from ${date.toDateString()}`],
              },
              {
                id: 'slug-prop-id', /** Your slug prop ID */
                data: ['anthony-hopkins-comment'],
              },
              {
                id: 'full_name-prop-id', /** Your full_name prop ID */
                data: [this.full_name]
              },
               {
                id: 'message-prop-id', /** Your message prop ID */
                data: [this.message]
              }
            ],
          },
        ],
        content: [
          {
            lng: 'en',
            nodes: [
              // ProseMirror nodes
            ],
            plainText: '',
          },
        ],
      });
    },
    }
  });
</script>

Now you'll be able to get data from your Nuxt.js aplication to your BCMS instance.

Updateing BCMS data from Nuxt.js to BCMS

The same way you create an entry, you can update an entry too. Here's how:

<script lang="ts">
  export default Vue.extend({
    methods: {
      async handleUpdate() {
        const bcms = this.$bcms as BCMSNuxtPlugin;
        const date = new Date();
        await bcms.entry.update({
          _id: '7654321', /** Your entry ID */
          templateId: '1234567', /** Your template ID */
          meta: [
            {
              lng: 'en',
              props: [
                {
                  id: 'title-prop-id', /** Your title prop ID */
                  data: [`Comment from ${date.toDateString()}`],
                },
                {
                  id: 'slug-prop-id', /** Your slug prop ID */
                  data: ['anthony-hopkins-comment'],
                },
                {
                  id: 'full_name-prop-id', /** Your full_name prop ID */
                  data: 'Anthony Hopkins'
                },
                {
                  id: 'message-prop-id', /** Your message prop ID */
                  data: 'First, principles, Clarice. Simplicity. Read Marcus Aurelius. Of each particular thing, ask what is it in itself? What is its nature?'
                }
              ],
            },
          ],
          content: [
            {
              lng: 'en',
              nodes: [
                // ProseMirror nodes
              ],
              plainText: '',
            },
          ],
        });
      },
    }
  });
</script>