Este artigo tem como objetivo relatar o processo de desenvolvimento de um blog utilizando Vue.js, Nuxt e consumindo dados de um CMS via API.

Não farei um passo a passo detalhado de como instalar e utilizar as ferramentas, mas trarei algumas dicas e desafios que enfrentei nesse processo e que poderão servir de referência para quem busca construir um blog.

Ferramentas

Primeiro, irei listar e fazer uma breve descrição das ferramentas e tecnologias utilizadas nesse projeto justificando a escolha de cada uma.

Vue.js

O Vue é um framework progressivo para construção de interfaces de usuário. Construído para ser incrementalmente adotável, sua implementação em páginas já existente é muito simples e direta. Mesmo com essas características o Vue é perfeitamente capaz de executar Single-Page Applications. Sua arquitetura busca combinar as melhoras características do React e do Angular.

Mais informações podem ser encontradas na página do Vue.

Escolhi o Vue principalmente por causa de sua estrutura de Single File Component - que combina html, css e javascript num mesmo arquivo - torna o desenvolvimento dos componentes Vue mais próximo de uma página web tradicional.

Nuxt.js

O Nuxt é um framework que adiciona algumas funcionalidades ao Vue.js, tais como Server Side Redering (SSR) - Renderização do lado do servidor - e Static Site Generation (SSG) - Geração de páginas estáticas.

SSR vs SPA?

Em uma SPA (Single-Page Application) o conteúdo da página é exibido depois que a página é carregada, para o usuário essa estratégia não representa nenhum problema, uma vez que o funcionamento é preservado.

No entanto, para os motores de busca (como Google, Bing etc.) que utilizam robôs para ler as páginas, nem sempre aguardam o conteúdo ser carregado para indexar as páginas, como efeito, para eles, nosso site não possui conteúdo e, portanto não será indexado.

Utilizando Server Side Rendering (SSR) todos os arquivos javascript e CSS são carregados e disponibilizados como arquivos estáticos. Assim quando a página é acessada, ela já está pronta, possibilitando que seu carregamento seja mais rápido e indexável pelos mecanismos de SEO (Search Engine Optimization).

Para um site ou blog público, é desejável que ele exista nos mecanismos de busca, por esse motivo escolhi adotar um framework que implementa SSR. Como estou utilizando Vue como framework javascript, o Nuxt tornou a melhor opção para esse fim.

CMS

Um Content Management System (CMS) - Sistema de gerenciamento de conteúdo - é um software que permite criação, edição e organização de conteúdo de maneira dinâmica. CMSs podem ser divididos em duas categorias:

  • Tradicional: onde o conteúdo é disponibilizado pelo próprio software, como um site.
  • Headless: nesse tipo de CMS o conteúdo é disponibilizado via API, possibilitando, entre outras, a construção de diferentes tipos de clientes (SPA e App Mobile, por exemplo).

Existem diversas ferramentas excelentes de gerenciamento de conteúdo: WordPress, Prismic, Ghost CMS e outros.

Para essa tarefa escolhi o Ghost CMS por ser gratuito, possuir um editor de texto muito poderoso - ideal para um blog - e por possuir funcionalidades que o classificam, também, como um Headless CMS.

Construção do blog

Dividi o processo de criação do site/blog em 3 etapas:

  1. Instalação do Ghost
  2. Criação do Front-End
  3. Deploy da aplicação

Instalação do Ghost

A documentação oficial do Ghost recomenda que ele seja instalado em um servidor linux com no mínimo 1GB de memória RAM. Por isso optei por executá-lo utilizando docker em um servidor virtual da Oracle.

Para disponibilizar o acesso através de SSL na internet, em conjunto com o Ghost, utilizei o Caddy como servidor web, que também foi instalado via docker.

Para facilitar a inicialização dos containers do CMS e do Caddy, criei um docker-compose com o seguinte código:

version: "3.7"

services:
  blog:
    image: ghost
    restart: unless-stopped
    container_name: blog
    volumes:
      - /caminho/para/content:/var/lib/content:z
    ports:
      - 2368:2368
    expose:
      - "2368"
    environment:
      url: <URL do blog>

  proxy:
    image: abiosoft/caddy
    container_name: proxy
    restart: unless-stopped
    links:
      - "blog:blog"
    ports:
      - 80:80
      - 443:443
    volumes:
      - /caminho/para/Caddyfile:/etc/Caddyfile:z
      - $PWD/.caddy:/root/.caddy:z

Para iniciar os serviços basta executar docker-compose up -d

Criação do Site

A construção do site foi iniciada como um projeto Nuxt tradicional:

npx create-nuxt-app [projeto]

O CLI do create-nuxt-app realiza uma série de perguntas para poder configurar o projeto com as bibliotecas e configurações necessárias. Todos os recursos podem ser adicionados a qualquer momento utilizando o npm ou yarn. Optei por deixar o CLI configurar o Nuxt apenas com:

  • Typescript
  • ESLint
  • Tailwindcss

Ao término do processo, o projeto ficou com a seguinte estrutura de pastas (todas as pastas principais tem um arquivo README.md que direciona para a documentação do Nuxt correspondente):

  • assets: aqui coloquei todos os arquivos de imagens, css, etc.;
  • components: todos os componentes Vue ficam nessa pasta, componentes nessa pasta são carregados globalmente e de maneira automática, pelo Nuxt;
  • layouts: utilizei o layout com apenas um objetivo, aplicar a classe do estado da aplicação (dark ou light) é através dessa classe que o tailwind consegue aplicar as variantes das classes aos componentes filhos;
  • pages: pasta principal da aplicação, todo arquivo Vue nessa pasta se transformará numa página e terá uma rota associada. O nome do arquivo será utilizado como rota do Nuxt, por exemplo o conteúdo do arquivo blog.vue será exibido quando a rota http://endereco/blog é acessada;
  • static: os arquivos nessa pasta são acessíveis diretamente pelo HTML, utilizei principalmente para o favicon;
  • store: nessa pasta fica a configuração do Vuex - o Gerenciador de estados global da aplicação;
  • types: como utilizei typescript, criei essa pasta com o arquivo vue-shim.d.ts dessa maneira o typescript é capaz de identificar os arquivos .vue como módulos e consiga aplicar a tipagem e transpilar o código, quando enviarmos para produção, de maneira correta;
  • api: criei essa pasta para abrigar todos os arquivos que realizem qualquer interação com APIs;
  • nuxt.config.js: arquivo principal do Nuxt, todos os módulos, plugins e configurações ficam nesse arquivo.

Escolhi o Tailwind como framework CSS por sua possibilidade de compor o design utilizando classes, aplicar variantes das cores (dark mode) além de utilidades cini responsividade e palheta de cores.

Integração com o CMS

Para integrar o site ao CMS, primeiro foi necessário criar uma entrada à API no ghost. Na área administrativa do CMS (http://endereco_do_blog/ghost) acesse:

  1. o menu integrações;
  2. crie uma integração personalizada.
  3. anote as seguintes informações: Content API Key e API URL, que serão utilizadas mais tarde.

Para que o site se comunique com CMS, o Ghost disponibiliza a biblioteca GhostContentAPI @tryghost/content-api que possui os métodos necessários para consumir os dados do Ghost de maneira simples. Para utilizar criei um arquivo posts.ts dentro da pasta api e utilizei o seguinte código para configurar a GhostContentAPI:

import GhostContentAPI from '@tryghost/content-api';
const api = new GhostContentAPI({
	url: 'API URL',
	key: 'Content API Key',
	version: 'v3',
});

Dos métodos que a API nos disponibiliza utilizei apenas dois: api.posts.browse para listar os posts e api.posts.read para exibir apenas um artigo.

Os demais métodos podem ser conferidos na documentação.

A listagem de artigos é exibida em duas páginas distintas, portanto, optei por realizar o carregamento dos posts no store. Assim foi possível compartilhar a mesma listagem de posts em duas páginas distintas realizando apenas uma chamada à API.

Deploy

Realizei o deploy da aplicação na plataforma da Vercel por já possuir a estrutura  e ferramentas necessárias para hospedagem de uma aplicação Nuxt. O passo a passo para o deploy é tão simples quanto criar um arquivo vercel.json e pode ser conferido na documentação.

Conclusão

A construção desse blog me permitiu passar por diversos conceitos desde criação de um servidor virtual na nuvem, passando por instalação e configuração de um servidor web, técnicas avançadas de desenvolvimento Front-end, SSR, UI e SEO.

Pretendo continuar o desenvolvimento desse projeto aplicando algumas outras técnicas e funcionalidades, que incluem, dentre outras:

  • Cobertura de testes utilizando jest;
  • Adicionar paginação na listagem dos posts;
  • Possibilidade de inserir comentários nos posts;
  • Aplicar estratégias de SEO.

Confira o projeto íntegra: https://github.com/virb30/blog