loading...
Cover image for How to Build a CMS-powered Blog with MeteorJS

How to Build a CMS-powered Blog with MeteorJS

rogerjin12 profile image Roger Jin ・4 min read

For more content like this, follow ButterCMS on Twitter and subscribe to our blog.

You know the story, you've built a great MeteorJS website for your client and they want a blog that lives in a subdirectory (not a subdomain) for SEO purposes.

In this tutorial I'm going to show you how to build a CMS-powered blog using MeteorJS and ButterCMS. The finished code for this tutorial is available on Github.

ButterCMS is a hosted API-based CMS and content API that lets you build CMS-powered apps using any programming language including Ruby, Rails, Node.js, .NET, Python, Phoenix, Django, Flask, React, Angular, Go, PHP, Laravel, Elixir, and Meteor. Butter lets you manage content using our dashboard and integrate it into your front-end of choice with our API – you can think of Butter as similar to WordPress except that you build your website in your language of choice and then plug-in the dynamic content using an API.

Getting Started

If you're new to MeteorJS, check out their quick start guide or follow the steps below.

Install Meteor:

curl https://install.meteor.com/ | sh

Create a new app and make sure it runs:

meteor create meteor-cms-blog
cd meteor-cms-blog
meteor npm install
meteor

Open your web browser and go to http://localhost:3000 to see the app running.

Creating the blog

First install the ButterCMS Node.js API client:

meteor npm install buttercms

We'll also use Iron Router to setup our blog routes:

meteor add iron:router

We'll then create some basic routes and templates. We're using an API token for a ButterCMS test account. Sign in with Github to create your own account and API token.

client/main.js:

import Butter from 'buttercms';
import './main.html';

const butter = Butter('de55d3f93789d4c5c26fb07445b680e8bca843bd');

Router.route('/', function() {
  this.render("Home")
});

Router.route('/blog', function() {
  let that = this;

  butter.post.list({page: 1, page_size: 10}).then(function(response) {
    that.render('Blog', {data: {posts: response.data.data}});
  });
});

Router.route('/blog/:slug', function() {
  let slug = this.params.slug;
  let that = this;

  butter.post.retrieve(slug).then(function(response) {
    let post = response.data.data;

    that.render('Post', {data: {post: post}});
  });
});

client/main.html:

<head>
  <title>Meteor Blog</title>
</head>
<body>
</body>

<template name="home">
  <a href="/blog">View blog</a>
</template>

<template name="blog">
<h2>Blog Posts</h2>
{{#each posts}}
  <div>
    <a href="/blog/{{slug}}">{{title}}</a>
  </div>
{{/each}}
</template>

<template name="post">
  <h2>{{post.title}}</h2>
  {{{post.body}}}
</template>

Let's take a closer look at one of our routes to see what's happening.

Router.route('/blog/:slug', function() {
  let slug = this.params.slug;
  let that = this;

  butter.post.retrieve(slug).then(function(response) {
    let post = response.data.data;

    that.render('Post', {data: {post: post}});
  });
});

In the code above, we create a route for the URL /blog/:slug which takes a post slug as a URL parameter, and then uses the slug to make an API request to ButterCMS to fetch the post and render it.

SEO

Our blog is setup, but crawlers from search engines and social networks do not execute Javascript so our blog has terrible SEO.

First we'll install the ms-seo helper package and make sure we have good HTML titles, descriptions, and meta tags.

meteor add check
meteor add manuelschoebel:ms-seo

ms-seo provides a simple SEO.set method for configuring tags. You can verify that tags are getting set properly by inspecting the DOM.

Router.route('/blog/:slug', function() {
  let slug = this.params.slug;
  let that = this;

  butter.post.retrieve(slug).then(function(response) {
    let post = response.data.data;

    SEO.set({
      title: post.seo_title,
      meta: {
        description: post.meta_description
      },
      rel_author: 'https://www.google.com/+ButterCMS',
      og: {
        'title': post.seo_title,
        'description': post.meta_description,
        'image': post.featured_image
      }
    });

    that.render('Post', {data: {post: post}});
  });
});

Finally, we want to server render our blog so that its crawalable by search engines and social networks like Twitter.

The easiest way to do this is to use Meteor's hosting platform, Galaxy, which provides an integrated pre-rendering service (Prerender.io). The Prerender.io service is included as part of Galaxy at no additional cost.

Follow Meteor's guide for deploying to Galaxy. To turn on the built-in Prerender.io integration, add the Galaxy SEO package:

meteor add mdg:seo

Wrap Up

If you don't want to use Galaxy, you can manually integrate Prerender.io. Another option is implementing server-side rendering into your app. At the time of this writing, server-side rendering isn't natively supported by Meteor, but you can check out Meteor SSR or Flow Router's alpha release of SSR support.

Meteor is a powerful development platform that solves a lot of pains of building Javascript apps for web, mobile, and desktop. However there aren't many CMS options available for building CMS-powered features in Meteor like blogs, FAQS, and templated pages. A headless CMS like ButterCMS let you easily build CMS-powered apps in Meteor.

We hope you enjoyed this tutorial. If you have any questions about setting up your ButterCMS-powered Meteor app reach out to me at roger@buttercms.com!

Posted on by:

rogerjin12 profile

Roger Jin

@rogerjin12

Engineer at ButterCMS.com — develops with Ruby, Node.js, and React. Email me at roger@buttercms.com and I’ll definitely reply!

Discussion

markdown guide
 

MeteoJS is an incredible framework for creating pure JS site, but I have done an experiment and found that it is slightly slow. I have a website that is built on Asgard, which is considered one of the best Laravel CMS. To learn Meteor i tried creating the same site on it, a replica with same things. I found that the admin dashboard was slow to load.