Building a Serverless CMS Powered by Vue.js

Vue.js, a progressive framework for building user interfaces, is gaining in popularity among developers. But why yet another JavaScript framework? Vue has learned from the experiences of Angular and React and many see it as simpler to implement and understand.

Vue.js is lightweight and easily adoptable. It’s reactive and component-based, allowing you to create pluggable components you can add to any project. Most importantly for this tutorial, Vue and its hallmark incremental adoptability allows you to try Vue without putting your existing code base at risk.

Vue works well with serverless application architectures. Serverless architectures are becoming the preferred architecture for many developers because it allows them to create and fine-tune products efficiently without having to bear the burdens (server maintenance, outages, and scaling bottlenecks) of traditional server-based architecture. Sarah Drasner recently wrote an entire series on how to create a serverless checkout flow powered by Vue and is a good example of this in practice.

In this tutorial, you’ll learn how to build a marketing website as a serverless Vue.js application using ButterCMS. ButterCMS is a headless CMS and blogging platform that lets you build CMS-powered apps using any programming language, including Vue. There are other options for going with a headless CMS, but I happen to develop for ButterCMS and know it extremely well so that's what we'll be using in our examples.

This tutorial will show you how to add performant content APIs to your Vue.js application. These APIs are easy to navigate even for the non-technical members of your team, enabling you to enjoy agile content management without having to spin up and maintain your own CMS infrastructure.

Note that the designs in the screenshots we use throughout this post will likely differ from what you build and are styled with light CSS for demonstration. Your real design would use the global styling from your app making the pages look consistent with the rest of your site.

Getting Started

Example 1: Customer Case Studies

Let's start by making it possible for any non-technical person on your team to add customer case studies to the site. In this case, we'll create a page that can hold all of the published case studies that promote the product or service we're selling which, when clicked, open up the page for that case study.

Step 1: Setup Customer Case Study Page Type

Using the dashboard on ButterCMS, you can create a "page type" entitled "Customer Case Study” and define the content fields. Once you’ve done this, you can create your first page. Specify the name and URL of the page using the ButterCMS dashboard and complete the populate the content fields we just defined.

Once this is all done, the ButterCMS API will return your defined page in JSON format. It should look something like this:

You have content in a data file, which is great, but now you need a page that uses the content. You're going to define a getpages() method that fetches all of the case study pages so you can render them together on a single landing page to create an index of them all. This will be a "homepage" for all of the published case studies.

Here's an example of something close to what you have so far after publishing one case study:

Now, you're going to set up the page we get when clicking on a case study from the homepage. To do so, in components/CustomerPage.vue we define a getPage() method to get a particular customer page based on its slug:

Success! Now you can go directly to a page that lists all published case studies and click on any of them to be taken to the detail page for a specific case study post.

Example 2: Frequently Asked Questions

Now lets's walk through how to create a Frequently Asked Questions (FAQ) page for the app. We’ll be using ButterCMS "Content Fields” for this. Content fields are simply global pieces of content that can be managed by your team. This content can span multiple pages and each content field has a unique ID for querying, as you’ll see below.

Step 1: Setup Content Fields

First, you’ll need to set up some custom content fields. Using the dashboard, you can set up a workspace to organize content fields. Workspaces will allow content editors to curate content without affecting development or the API.

Once you're in a workspace, click the button to create a new content field. Choose the "Object" type and use "FAQ Headline" as the name of the field. It will have an API slug of faq_headline.

After saving, add another field but this time choose the "Collection" type and use "FAQ Items" as the name of the field. This one will have an faq_items API slug. On the next screen, set up two properties for items in the collection and go back to your workspace to update your heading and add some FAQ posts.

Step 2: Integrating Your App

Now that you’ve created dynamic content using content fields, it’s time to display it in the app. To do this, you’ll fetch the fields with an API call and reference them in your view. First, set up a route to your FAQ page:

If you have been following along with the previous examples, then you may start to see a pattern here and know that you need to display the content by defining the template and calling the fields in the same component file:

Again, assuming you're using similar fields as the example, this is what you might expect to see:

Step 4: Handling Blog Post Routes

At this point, your app is pulling all blog posts, allowing you to navigate to individual posts. But, you will notice the next/previous buttons in the browser aren’t working. Why? When using routes with params, the same component instance will be reused when the user navigates from /blog/foo to /blog/bar.

Since both routes render the same component, this is more efficient than destroying the old instance and creating a new one. But, this also means that the lifecycle hooks of the component will not be called.

There is a fix for this. We need to watch the $route object and call getPost() when the route changes. To do this, update the script section in components/BlogPost.vue:

At this point, your app has a working blog that can be updated easily from the CMS dashboard.

You can also use APIs to filter and feature content on your blog with categories, tags, and authors. In fact, there’s a lot you can do with an API in terms of managing different aspects of your blog, including RSS, Atom feeds, sitemap markup, and content styling with CSS.

Wrapping Up

Congrats! You’ve built a serverless Vue.js application with performant content API and are now equipped with real-life use cases for content you might expect to see on any given marketing site. Your development team can get back to coding and non-technical members of your team can have an easy way to manage content without any hand-holding through the code base. And, best yet, this your app is powered by dynamic content that will can be adapted, re-purposed and scaled for future needs.

Related

Comments

Doesn’t the butter CMS have to have a node server behind it? Wouldn’t that mean its running on a server? Or is it just the fact that the traffic hitting the front end doesn’t need to talk to the backend that makes this good?

Great question – ButterCMS is a 3rd party service that provides a content API. Butter is not something you download and install / maintain yourself. You simply query that content API directly from your Vue.js app, there’s no CMS software for you to worry about or host. Hence “Serverless” CMS, as in you don’t need to worry about a server to get CMS capability.

Posting Code!

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.