Clique aqui para a documentação da v3.x.

Você está navegando a documentação da v2.x e anterior. Para a v3.x, clique aqui.

Criar um Blog com ButterCMS

Introdução

Então, você concluiu o seu site com Vue, parabéns! Mas agora você quer adicionar um blog que rapidamente se encaixe ao seu site, e quer evitar ter um servidor a mais apenas para hospedar uma instância do WordPress (ou qualquer outro gerenciador de conteúdo com um banco de dados apenas para este fim). Você apenas quer que seja possível adicionar alguns componentes Vue destinados ao blog, algumas rotas e ter tudo isso funcionando, certo? O que você está procurando é um blog que seja inteiramente construído através de uma API, que você possa consumir diretamente a partir da sua aplicação Vue. Esse tutorial vai lhe ensinar exatamente como fazer isso, vamos lá!

Nós vamos construir rapidamente um blog utilizando um sistema de gerenciador de conteúdo, ou CMS (Content Management System), com Vue. Será utilizado o ButterCMS, um CMS que nos permite utilizar uma interface gráfica e integrar o conteúdo que queremos com um aplicativo Vue. Você pode utilizar o ButterCMS para projetos Vue novos ou que já existam.

Painel de Controle Butter

Instalando

Execute o seguinte comando:

npm install buttercms --save

O ButterCMS também pode ser carregado através do CDN:

<script src="https://cdnjs.buttercms.com/buttercms-1.1.0.min.js"></script>

Início Rápido

Configure o token da sua API:

var butter = require('buttercms')('seu_token_da_api');

Usando ES6:

import Butter from 'buttercms';
const butter = Butter('seu_token_da_api');

Usando CDN:

<script src="https://cdnjs.buttercms.com/buttercms-1.1.0.min.js"></script>
<script>
  var butter = Butter('seu_token_da_api');
</script>

Importe o ButterCMS em qualquer componente que você queira utilizá-lo. Então execute no console:

butter.post.list({page: 1, page_size: 10}).then(function(response) {
  console.log(response)
})

Essa requisição à API obtém as postagens do seu blog. A sua conta vem com uma postagem de exemplo que você verá na resposta da requisição.

Exibindo as Postagens

Para exibir as postagens, vamos criar uma rota /blog (usando o Vue Router) na nossa aplicação e adquirir as postagens do blog a partir da API do ButterCMS, assim como a rota /blog/:slug exibirá as postagens individuais.

Veja a documentação do ButterCMS para mais informações, assim como, por exemplo, filtrar postagens por categoria ou autor. A resposta da requisição também inclui alguns metadados que usaremos para paginação.

router/index.js:

import Vue from 'vue'
import Router from 'vue-router'
import BlogHome from '@/components/BlogHome'
import BlogPost from '@/components/BlogPost'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/blog/',
      name: 'blog-home',
      component: BlogHome
    },
    {
      path: '/blog/:slug',
      name: 'blog-post',
      component: BlogPost
    }
  ]
})

Em seguida, crie components/BlogHome.vue que vai ser a página inicial do seu blog e listará as últimas postagens dele.

<script>
  import { butter } from '@/buttercms'
  export default {
    name: 'blog-home',
    data() {
      return {
        page_title: 'Blog',
        posts: []
      }
    },
    methods: {
      getPosts() {
        butter.post.list({
          page: 1,
          page_size: 10
        }).then(res => {
          this.posts = res.data.data
        })
      }
    },
    created() {
      this.getPosts()
    }
  }
</script>

<template>
  <div id="blog-home">
      <h1>{{ page_title }}</h1>
      <!-- Cria `v-for` e aplica um `key`, usando uma combinação do slug e index. -->
      <div
        v-for="(post,index) in posts"
        :key="post.slug + '_' + index">
        <router-link :to="'/blog/' + post.slug">
          <article class="media">
            <figure>
              <!-- Vincula results usando um `:` -->
              <!-- Usa um `v-if`/`else` caso seja `featured_image` -->
              <img
                v-if="post.featured_image"
                :src="post.featured_image"
                alt="">
              <img
                v-else
                src="http://via.placeholder.com/250x250"
                alt="">
            </figure>
            <h2>{{ post.title }}</h2>
            <p>{{ post.summary }}</p>
          </article>
        </router-link>
      </div>
  </div>
</template>

Veja o resultado (note que adicionamos o CSS do Bulma):

Lista de Postagens do ButterCMS

Agora vamos criar components/BlogPost.vue, a página de uma postagem do blog.

<script>
  import { butter } from '@/buttercms'
  export default {
    name: 'blog-post',
    data() {
      return {
        post: {}
      }
    },
    methods: {
      getPost() {
        butter.post.retrieve(this.$route.params.slug)
          .then(res => {
            this.post = res.data
          }).catch(res => {
            console.log(res)
          })
      }
    },
    created() {
      this.getPost()
    }
  }
</script>

<template>
  <div id="blog-post">
    <h1>{{ post.data.title }}</h1>
    <h4>{{ post.data.author.first_name }} {{ post.data.author.last_name }}</h4>
    <div v-html="post.data.body"></div>

    <router-link
      v-if="post.meta.previous_post"
      :to="/blog/ + post.meta.previous_post.slug"
      class="button">
      {{ post.meta.previous_post.title }}
    </router-link>
    <router-link
      v-if="post.meta.next_post"
      :to="/blog/ + post.meta.next_post.slug"
      class="button">
      {{ post.meta.next_post.title }}
    </router-link>
  </div>
</template>

Aqui vai uma prévia de como ficou:

Detalhes da Postagem do ButterCMS

Agora nossa aplicação está trazendo todas as postagens do blog e podemos navegar através delas de forma individual. Contudo, os botões que exibem a postagem anterior e a seguinte não estão funcionando.

É importante notar que, quando usamos rotas com parâmetros, quando o usuário navega de /blog/foo para /blog/bar, a mesma instância do componente será utilizada. Ambas as rotas exibindo o mesmo componente é mais eficiente do que destruir uma instância antiga e criar uma nova.

Fique atento que, usando um componente deste jeito, significará que os gatilhos do ciclo de vida do componente não serão chamados. Veja a documentação do roteador do Vue para aprender mais sobre isso em combinando rotas dinâmicas.

Para corrigir isso, precisamos observar o objeto $route e chamar o getPost() quando a rota for alterada.

Atualize a seção <script> em components/BlogPost.vue:

<script>
  import { butter } from '@/buttercms'
  export default {
    name: 'blog-post',
    data() {
      return {
        post: null
      }
    },
    methods: {
      getPost() {
        butter.post.retrieve(this.$route.params.slug)
          .then(res => {
            this.post = res.data
          }).catch(res => {
            console.log(res)
          })
      }
    },
    watch: {
      $route: {
        immediate: true,
        handler(to, from) {
          this.getPost()
        }
      }
    }
  }
</script>

Com isso, a sua aplicação agora possui um blog que pode ser, facilmente, atualizado através da interface gráfica fornecida pelo ButterCMS.

Categorias, Marcações e Autores

Use a API do ButterCMS para categorias, marcações e autores para filtrar o conteúdo do seu blog. Veja a documentação do ButterCMS para mais informações sobre isso:

Aqui está um exemplo de como listar todas as categorias do blog e, também, de como obter as postagens organizadas por categoria. Chame esses métodos no gatilho created() do ciclo de vida do componente.

methods: {
  // ...
  getCategories() {
    butter.category.list()
      .then(res => {
        console.log('Lista de Categorias:')
        console.log(res.data.data)
      })
  },
  getPostsByCategory() {
    butter.category.retrieve('example-category', {
        include: 'recent_posts'
      })
      .then(res => {
        console.log('Postagens de categoria específica:')
        console.log(res)
      })
  }
},
created() {
  // ...
  this.getCategories()
  this.getPostsByCategory()
}

Padrões Alternativos

Um padrão alternativo a ser considerado, especialmente se você preferir escrever apenas em Markdown, é usar algo como o Nuxtent. Nuxtent permite que você use um componente Vue dentro de um arquivo Markdown. Essa seria uma abordagem bem parecida à abordagem de um site estático (por exemplo, usando Jekyll), onde as postagens do blog são escritas em arquivos Markdown. O Nuxtent possui uma boa integração entre o Vue e o Markdown, permitindo que você viva 100% no mundo do Vue.

Considerações Finais

É isso! Você agora possui um blog completamente funcional alimentado por um CMS executando junto à sua aplicação. Esperamos que esse tutorial tenha lhe ajudado e feito o seu desenvolvimento com Vue ainda mais agradável.