Voltar

ūüóěÔłŹ Criando um blog com Next 14 e Prismic CMS

Aprenda a construir um blog pessoal com Next.js 14 e Prismic CMS. Este tutorial pr√°tico mostrar√° como configurar e integrar essas ferramentas para criar um blog din√Ęmico, focando em rotas, gest√£o de conte√ļdo modular e componentes reutiliz√°veis.

Banner principal para a postagem Criando um blog com Next 14 e Prismic CMS
LP

Leonardo Petta do Nascimento

24 min. de leitura · Criado em 02 mai, 2024


Gostou? Compartilhe!


Seja bem-vindo ao nosso primeiro tutorial! Neste artigo, mostrarei como desenvolver um blog pessoal utilizando as tecnologias Next.js e Prismic CMS.

Antes de prosseguirmos, farei uma breve descri√ß√£o dos conceitos que abordaremos. √Č importante que voc√™ leia com aten√ß√£o os t√≥picos te√≥ricos para entender melhor os termos que utilizaremos ao longo do desenvolvimento.

O projeto que desenvolveremos será inicialmente simples, mas o enriqueceremos com funcionalidades em futuras postagens. Para acompanhar a evolução do projeto, você pode seguir o repositório no GitHub. Sempre que uma nova postagem for concluída, criarei uma tag específica para ajudá-lo a não se perder.

Para acessar o repositório com todo o código desenvolvido nesta postagem, clique neste link. Se deseja ver um exemplo de um blog completo, similar ao que construiremos, visite este repositório.

Vamos começar?

O que é um CMS?

No projeto do blog que estamos desenvolvendo, uma tecnologia crucial √© o CMS (Sistema de Gerenciamento de Conte√ļdo). Um CMS facilita a cria√ß√£o, edi√ß√£o e gest√£o de conte√ļdo digital em um website, sem exigir conhecimento t√©cnico avan√ßado.

Essencialmente, um CMS fornece uma interface intuitiva onde usu√°rios podem gerenciar posts, p√°ginas e arquivos de m√≠dia, como imagens e v√≠deos. Essa ferramenta simplifica a publica√ß√£o de conte√ļdos e, muitas vezes, suporta colabora√ß√£o em equipe por meio de diferentes n√≠veis de acesso e permiss√Ķes. Isso √© particularmente √ļtil para projetos com m√ļltiplos colaboradores.

Por exemplo, no blog que estamos criando, utilizo um CMS que me permite escrever e editar artigos diretamente pela plataforma. Com isso, elimino a necessidade de lidar com HTML est√°tico. A estrutura do blog √© definida uma √ļnica vez, e todas as postagens futuras s√£o automaticamente adaptadas a essa estrutura, economizando tempo e mantendo a consist√™ncia visual do conte√ļdo.

Vantagens e por que usar o Prismic CMS

A sele√ß√£o de um Sistema de Gerenciamento de Conte√ļdo (CMS) deve ser baseada na finalidade espec√≠fica do seu conte√ļdo. Enquanto muitos CMSs s√£o vers√°teis e funcionam bem em v√°rias situa√ß√Ķes, alguns conte√ļdos se beneficiam mais de sistemas especializados para tipos espec√≠ficos de conte√ļdo.

Veja alguns exemplos de CMSs populares e suas especialidades:

  • WordPress: Perfeito para blogs e sites variados.
  • Joomla: Excelente para sites corporativos e portais.
  • Drupal: Ideal para sites complexos e de grande escala.
  • Magento: Especializado em e-commerce de grande volume.

Para nosso projeto, optamos pelo Prismic CMS, destacado pela sua efic√°cia na cria√ß√£o de artigos e se√ß√Ķes de p√°ginas web. Escolhi o Prismic por v√°rias raz√Ķes importantes:

  • Interface Amig√°vel e Custos Acess√≠veis: Prismic tem uma interface intuitiva e uma pol√≠tica de pre√ßos atraente, com um plano gratuito robusto para desenvolvedores e sites pessoais.
  • Alta Cota de Uso Gratuito: O plano gratuito √© suficiente para a maioria dos blogs pessoais de tecnologia, permitindo uma opera√ß√£o com custo quase nulo.
  • Excelente Integra√ß√£o com Next.js: A integra√ß√£o facilita tanto a renderiza√ß√£o no servidor (SSR) quanto a gera√ß√£o est√°tica de sites (SSG), melhorando o carregamento das p√°ginas e o SEO.
  • Documenta√ß√£o Acess√≠vel e Suporte Comunit√°rio: A documenta√ß√£o de Prismic √© clara e o f√≥rum da comunidade √© um excelente recurso para solucionar d√ļvidas e problemas t√©cnicos.

A decis√£o de usar o Prismic equilibra facilidade de uso, efic√°cia e custo, tornando-o ideal para nosso blog focado em tecnologia.

Criando uma conta e repositório básico no Prismic CMS

Agora que você entendeu os conceitos por trás de um CMS, vamos por a mão na massa. A partir de agora, vamos interagir com o Prismic.

Primeiro passo, precisamos criar uma conta e configurar um repositório no Prismic.

Acesse o site do Prismic e crie uma conta utilizando um email e senha, ou sua conta no Github se preferir.

Aqui estou simulando a cria√ß√£o de uma nova conta com um email tempor√°rio. Coloque algumas informa√ß√Ķes b√°sicas sobre voc√™ e clique em ‚ÄúContinue‚ÄĚ

Na pr√≥xima tela, veremos uma dashboard vazia com algumas op√ß√Ķes para cria√ß√£o de um reposit√≥rio. Para prosseguir selecione o framework Next.js.

Como vamos criar algo do zero, recomendo selecionar a criação de um projeto vazio para facilitar nosso exemplo e evitar recursos desnecessário.

Escolha um nome √ļnico para o seu reposit√≥rio. Se desejar, voc√™ pode tamb√©m adicionar um nome de visualiza√ß√£o, que facilitar√° a identifica√ß√£o do seu reposit√≥rio entre outros que voc√™ possa criar no futuro. Certifique-se de selecionar o plano gratuito e, em seguida, finalize criando o seu reposit√≥rio.

Após isso, você verá uma tela como essa, significando que ocorreu tudo bem.

Criando o projeto Next

Tendo um repositório básico no Prismic, agora precisamos ter nosso projeto Next para continuar. Se você olhar na página que se abriu no Prismic, ele segue um passo a passo para configurarmos um projeto Next e linka-lo com o CMS.

Tendo o Node instalado, rode o seguinte comando em um terminal para criar seu projeto next:

ATEN√á√ÉO: n√£o se esque√ßa de substituir ‚ÄúNOME_DO_SEU_PROJETO‚ÄĚ pelo nome que voc√™ preferir, de prefer√™ncia, utilize o mesmo nome que voc√™ deu ao seu reposit√≥rio e em caso de duvida, copie o comando da pr√≥pria p√°gina do Prismic.

npx create-next-app@latest NOME_DO_SEU_PROJETO

As seguintes informa√ß√Ķes v√£o aparecer e recomendo que voc√™ selecione as op√ß√Ķes que marquei para criar um projeto Next utilizando Typescript com paths habilitado, Eslint, Tailwind e a nova App routes do Next.

Terminando de criar seu projeto, rode os comando abaixo para entrar na pasta criada e iniciar o servidor local do Next.

cd NOME_DO_SEU_PROJETO npm run dev

Com isso, acesse http://localhost:3000 e se tudo estiver correto, você verá uma página parecida com essa:

Agora, precisamos inicializar as configura√ß√Ķes do Prismic no projeto. Rode o seguinte comando para tal:

ATEN√á√ÉO: Troque ‚ÄúNOME_DO_REPOSIT√ďRIO_CRIADO_NO_PRISMIC‚ÄĚ pelo nome dado ao seu reposit√≥rio no Prismic. Esse campo deve ser igual ao que foi colocado no Prismic.

npx @slicemachine/init@latest --repository NOME_DO_REPOSIT√ďRIO_CRIADO_NO_PRISMIC

Após a execução dos comando acima, a CLI vai pedir para você se logar com sua conta do Prismic. Siga os passos que indicarem no terminal e aguarde o Prismic instalar e configurar o básico do Slice Machine (não se preocupe, iremos entender melhor o que é esse recurso mais pra frente). Ao final, a CLI vai perguntar se deseja rodar o Slice Machine, diga que sim e uma aplicação começara a rodar em http://localhost:9999.

Ao acessar a URL acima, uma página do Slice Machine será aberta. De inicio, precisamos criar um modelo de Page Type reutilizável dando um nome para ele e ao final, realizamos o envio de nossa criação para a nuvem do Prismic.

Você pode acompanhar essa criação abaixo.

Voltando ao site do Prismic, podemos avan√ßar at√© o passo 4 na tela e confirmar que criamos um modelo clicando no bot√£o ‚ÄúI‚Äôve pushed my models‚ÄĚ

Se a página do Prismic se parecer com a imagem abaixo, nós temos tudo que é necessário para iniciar nosso blog.

O que é o Slice Machine do Prismic?

Antes de avan√ßarmos, vamos explorar um recurso fundamental que usaremos em breve: o Slice Machine. Essa ferramenta do Prismic revoluciona a maneira como desenvolvedores e designers criam e gerenciam componentes de interface para projetos web. Com o Slice Machine, voc√™ pode construir e organizar se√ß√Ķes de p√°gina, conhecidas como "slices", de forma modular e reutiliz√°vel.

Utilizando o Slice Machine, definimos a estrutura f√≠sica de nossas postagens e, como b√īnus, incorporamos a tipagem est√°tica, um recurso que considero essencial para qualquer projeto.

O processo é simples, mas poderoso, e envolve alguns passos essenciais:

  1. Cria√ß√£o de Slices: Primeiro, utilizamos o Slice Machine para projetar a estrutura de conte√ļdo que desejamos para nosso blog ‚ÄĒ neste caso, a estrutura de uma postagem. Isso √© feito atrav√©s de uma interface gr√°fica onde voc√™ pode arrastar e soltar diferentes tipos de campos e componentes, como textos, imagens e v√≠deos, configurando-os para atender √†s necessidades espec√≠ficas do seu conte√ļdo.
  2. Gera√ß√£o de Tipagem Est√°tica: Ap√≥s definir os componentes de nossa postagem, o pr√≥ximo passo √© gerar a tipagem est√°tica dessa estrutura. Isso √© feito automaticamente pelo Slice Machine, que cria defini√ß√Ķes de tipos Typescript. Essas defini√ß√Ķes s√£o cruciais, pois integram-se ao Next.js para garantir que o desenvolvimento do seu site seja seguro em termos de tipos, reduzindo a possibilidade de erros e facilitando a manuten√ß√£o do c√≥digo.
  3. Sincroniza√ß√£o com a Nuvem do Prismic: Uma vez que a estrutura do conte√ļdo e a tipagem est√£o prontas, sincronizamos tudo com a nuvem do Prismic. Este passo envolve enviar a configura√ß√£o dos slices criados para o seu reposit√≥rio Prismic, onde voc√™ pode come√ßar a criar e gerenciar postagens usando a estrutura previamente definida. Este processo √© facilitado pelo Prismic, que hospeda e gerencia os dados, permitindo que voc√™ se concentre apenas no conte√ļdo.

Se isso parece complexo, não se preocupe! Vamos descomplicar esses conceitos com exemplos práticos, mostrando cada passo em detalhes para que você possa seguir facilmente e aplicar no seu projeto.

Criando nosso primeiro modelo

Agora que está mais claro o que é o Slice Machine, vamos criar nossas primeiras estruturas.

Se j√° n√£o estiver rodando, em um terminal na pasta do app Next, execute o Slice Machine com o seguinte comando:

npm run slicemachine

Assim que o emulador iniciar, acesse http://localhost:9999, navegue pelo menu lateral at√© a p√°gina ‚ÄúPage Types‚ÄĚ e depois acesse o modelo que criamos durante a configura√ß√£o inicial do Prismic.

Acessando esse modelo nós veremos 3 partes importantes que eu destaquei com cores diferentes.

  • Em vermelho: S√£o as camadas (layer ou tab) do seu modelo. Com as camadas, podemos segmentar os documentos que iremos criar em grupos de dados mais espec√≠ficos. Por exemplo, por padr√£o, temos duas camadas, Main (Onde vamos trabalhar e criar toda a estrutura visual da nossa postagem) e SEO & Metadata (onde v√£o os dados de SEO para a postagem). Voc√™ pode Criar v√°rias camadas dependendo da complexidade do seu modelo e caso queira segmentar em v√°rias camadas de informa√ß√£o. Para o nosso exemplo, s√≥ vamos precisar da primeira p√°gina.
  • Em azul: √Č aqui que vamos colocar os campos est√°ticos. Esses campos s√£o fixos e pertencem exclusivamente a esse modelo. Todo documento desde modelo vai precisar ter os campos que registrarmos aqui.
  • Em roxo: Aqui vai ser onde colocaremos o que o Prismic chama de ‚ÄúSlice‚ÄĚ. Basicamente esse campo serve para compartilhar estruturas din√Ęmicas entre os modelos. Para o nosso caso, n√£o ser√° necess√°rio criar Slices, j√° que teremos estruturas bem simples, por√©m, entenda que esse recurso √© muito importante se voc√™ quiser criar estruturas parecidas entre os seus modelos. Trazendo para uma analogia do mundo do React, seria o equivalente a criar componentes reutiliz√°veis.

Vamos focar na √°rea azul. O Prismic gera o primeiro campo para voc√™ chamado ‚ÄúUID‚ÄĚ, esse campo vai representar um id √ļnico para nossa postagem, ele n√£o pode ser exclu√≠do, por√©m pode ser renomeado se voc√™ desejar.

Iremos criar uma estrutura de artigo com campos simples. Nossa estrutura vai precisar de:

  1. Título
  2. Subtítulo
  3. Uma imagem central
  4. Autor
  5. Conte√ļdo T√≠tulo Par√°grafos de conte√ļdo

O Prismic tem muitos tipos para um campo, Para o nosso exemplo iremos utilizar os tipos:

  • Rich Text: esse tipo representa um campo de texto vers√°til no formato de par√°grafo. Atrav√©s dele podemos renderizar algumas tags do HTML como por exemplo <H1-6>, <strong>, <p>, <image> e entre outros. Por ele ser vers√°til, podemos utilizar todas as tags juntas em um mesmo campo, parecendo como se estiv√©ssemos criando elementos HTML aninhados.
  • Image: como o pr√≥prio nome diz, renderiza uma Imagem no campo, podendo ser interna ao storage do Prismic ou externa com o link.
  • Key Text: esse campo √© uma string exclusivamente e serve como um campo √ļnico dentro do seu modelo.
  • Group: um grupo serve para criamos uma √°rea de conte√ļdo repet√≠vel no modelo. Trazendo para o mundo da programa√ß√£o, podemos entender um grupo como um array de objetos onde cada objeto tem a mesma estrutura interna (tipagem).

Qualquer outro campo não será tratado neste artigo, mas caso tenha curiosidade em entender como os campos do Prismic funcionam, pode acessar a documentação.

Para criar a estrutura acima vamos clicar no bot√£o ‚ÄúAdd a new field‚ÄĚ para abrir um modal para podermos escolher o tipo do campo. Selecionando o tipo, de um nome leg√≠vel e clique em ‚ÄúAdd‚ÄĚ.

O t√≠tulo e subt√≠tulo ser√£o do tipo ‚ÄúRich Text‚ÄĚ, a imagem ser√° do tipo ‚ÄúImage‚ÄĚ e o Autor ser√° ‚ÄúKey Text‚ÄĚ.

Agora que temos os campos, vamos personaliza-los. T√≠tulo e subt√≠tulo v√£o precisar respeitar uma estrutura sem√Ęntica igual no HTML, ent√£o queremos definir que tenhamos um H1 e um H2 respectivamente. Para isso, clicamos no l√°pis para editar e modificamos o campo ‚ÄúAccept‚ÄĚ para permitir somente as tags desejadas.

Por √ļltimo, iremos criar o conte√ļdo. O conte√ļdo ser√° do tipo ‚ÄúGroup‚ÄĚ, esse grupo vai conter um t√≠tulo do de tipo um "Rich Text" que permite somente a tag H3 e os par√°grafos tamb√©m ser√£o "Rich Text", por√©m v√£o permitir mais tipos de tag HTML, pois cada par√°grafo vai poder ter uma estrutura mais flex√≠vel dependendo do que quisermos escrever na postagem. Por exemplo, dentro do conte√ļdo de nossos artigos, teremos listas, imagens, texto, c√≥digo, links e etc.

Ao final, vamos excluir a camada ‚ÄúSEO & Metadata‚ÄĚ j√° que ela n√£o ser√° √ļtil para nosso exemplo.

Agora que temos uma estrutura, precisamos enviar nossas altera√ß√Ķes para o a nuvem do Prismic.

Acesse no menu lateral esquerdo o bot√£o "Review changes‚ÄĚ. Se for necess√°rio realizar login, realize clicando no bot√£o que surgir na tela. Ap√≥s isso, a tela exibira um resumo do que foi atualizado, basta ent√£o clicar no bot√£o ‚ÄúPush‚ÄĚ e pronto, seus modelos est√£o sincronizados.

Sempre que você fizer alteração nos modelos, é necessário realizar esse procedimento de envio para a nuvem.

Uma informação importante é que se você olhar a pasta do seu projeto, vai notar que dois arquivos foram gerados pelo Prismic.

Não aconselho que você edite esses arquivos por conta própria, eles servem basicamente para adicionar tipagem estática nos recursos da SDK do Prismic quando formos utiliza-la no Next, então, por enquanto, pode simplesmente envia-los em seu repositório.

Criando nossa primeira postagem

Agora que temos nosso modelo, vamos criar nossa primeira postagem. Primeiro, acessamos nosso repositório nod painel do Prismic e vamos clicar no botão central para iniciar uma postagem.

Ao Iniciar uma postagem vamos ser apresentados ao editor do Prismic, nele, toda a estrutura que criamos no modelo está disponível de forma de um formulário onde podemos simplesmente preencher. Nesta hora, podemos entender melhor como funciona os campos que construímos.

Irei preencher rapidamente com informa√ß√Ķes b√°sicas e loren ipson. Os pontos que mais importam nesse momento s√£o:

  • O campo UID pode ser preenchido manualmente, por√©m sempre que voc√™ digitar o t√≠tulo, ele vai usar o conte√ļdo para gerar um ‚Äúslug‚ÄĚ;
  • √Č poss√≠vel adicionar tags a sua postagem no topo da tela;
  • O banner pode usar uma imagem local sua ou pode ser pesquisada no banco de imagens do Prismic para ser preenchido automaticamente.
  • O campo de conte√ļdo √© repet√≠vel, ent√£o podemos adicionar v√°rios tipos de conte√ļdo nele;

Neste momento recomendo que você teste bem cada campo e veja as várias possibilidades para a criação de sua postagem.

Terminando de criar o conte√ļdo, basta clicar em ‚ÄúSave‚ÄĚ no canto superior direito e ent√£o clicar em ‚ÄúPublish‚ÄĚ. A partir dai, sua postagem j√° est√° no ar e podemos come√ßar a codificar a p√°gina no Next.

Criando a p√°gina de listagem de postagens

√Č chegada a hora de codificarmos algumas estruturas b√°sicas de um blog. Devo dizer novamente que o exemplo que iremos fazer n√£o vai ter l√° o design mais bonito e funcional. Irei focar em como funciona a SDK do Prismic, busca na api e como ela se integra com a constru√ß√£o dos server componentes e componentes ass√≠ncronos do Next.

Para casos mais específicos, design e certos componentes do blog, irei criar postagens focadas neles.

Vamos abrir o projeto no VS Code e apagar alguns detalhes que o Next traz por padr√£o que n√£o nos servir√£o. No arquivo src/app/globals.css podemos apagar a maioria das estiliza√ß√Ķes deixando o arquivo somente com as importa√ß√Ķes do Tailwind.

/* src/app/globals.css */ @tailwind base; @tailwind components; @tailwind utilities;

No arquivo src/app/page.tsx, podemos remover todo o código e deixar um componente em branco.

// src/app/page.tsx export default function Component() { return <h1>Hello Word</h1>; }

Com isso, teremos uma aplicação limpa igual a imagem abaixo:

Para facilitar o uso de classes Tailwind, vamos instalar uma biblioteca chamada tailwind-merge que vai nos ajudar a mesclar classes CSS sem a necessidade de ficarmos juntando strings e correndo o risco de ter classes duplicadas ou que se anulem. Para isso, rode o comando abaixo no terminal do seu projeto.

npm install tailwind-merge

Agora vamos criar um layout mínimo para a listagem de posts. No arquivo src/app/layout.tsx

iremos adicionar algumas classes ao body para tornar o conte√ļdo mais simples e responsivo, al√©m de permitir um tema claro e escuro. Tamb√©m iremos modificar o arquivo de metadata para mudar o t√≠tulo e descri√ß√£o da p√°gina.

// src/app/layout.tsx import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.scss"; import { twMerge } from "tailwind-merge"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: "Meu Blog", description: "Blog onde vou escrever sobre tutoriais e dicas de programação.", }; export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={twMerge( inter.className, "max-w-3xl mx-auto lg:max-w-5xl dark:bg-gray-900 min-h-screen sm:p-10 p-5 text-slate-900 dark:text-white" )}> {children} </body> </html> ); }

Dentro do arquivo src/app/page.tsx iremos adicionar alguns detalhes no header e com isso já vamos conseguir visualizar um cabeçalho inicial do nosso blog.

// src/app/page.tsx export default function Component() { return ( <div className="grid gap-6 lg:gap-8"> <header className="space-y-2"> <h2 className="text-3xl font-bold tracking-tight sm:text-4xl text-slate-900 dark:text-white"> Meu Blog </h2> <p className="text-gray-500 dark:text-gray-400"> Blog onde vou escrever sobre tutoriais e dicas de programação. </p> </header> </div> ); }

Ok, agora nós temos um cabeçalho e podemos começar a listar nossas postagens. Para isso, iremos utilizar a SDK do Prismic. No começo da página, podemos importar o createCliente diretamente da pasta src/prismicio.ts. Esse arquivo foi criado pelo próprio Prismic alguns passos atrás quando inicializamos nosso projeto. Nele iremos encontrar dois pontos importantes:

  1. A constante routes : Iremos deixar ela inaltera por enquanto, mas saiba que esse √© o ‚ÄúRoute Resolver‚ÄĚ do Prismic, uma funcionalidade essencial para mapear as rotas de nossa aplica√ß√£o com os documentos espec√≠ficos armazenados no Prismic. Ele facilita a integra√ß√£o entre nossa aplica√ß√£o Next e o Prismic, permitindo o uso de URLs locais diretamente pelo editor do Prismic. Al√©m disso, contribui significativamente para a otimiza√ß√£o do SEO, assegurando que as URLs sejam consistentes e amig√°veis aos motores de busca.
  2. A fun√ß√£o createClient: Essa fun√ß√£o basicamente cria uma inst√Ęncia do cliente do Prisma e nos retorna para fazermos requisi√ß√Ķes diretamente para a API. Podemos importar ele em qualquer componente do nosso app, mas vamos focar em importar em em componentes ass√≠ncronos. Outro ponto interessante de notar, √© que ele possui por padr√£o uma configura√ß√£o de cache em produ√ß√£o e uma para desenvolvimento. Qualquer coisa aqui √© modific√°vel, por√©m o padr√£o que vem j√° √© o suficiente para trazer uma experi√™ncia de cache favor√°vel em nossa aplica√ß√£o, onde em desenvolvimento, teremos uma revalida√ß√£o do cache a cada 5 minutos e em produ√ß√£o iremos armazenar nossas requisi√ß√Ķes no cache do Next por tempo indeterminado.

Voltando para a importação, adicione o código abaixo no topo do arquivo src/app/page.tsx:

import { createClient } from "@/prismicio";

Tendo o createClient, iremos fazer nossa primeira busca. Para fazermos uma busca, é necessário transformar a página em um componente assíncrono (uma funcionalidade do Next 14), adicionamos a palavra reservada async a função. Então, dentro da função iremos chamar a função createClient e pegaremos seu retorno.

Com o objeto retornado, podemos utiliza-lo para fazermos requisi√ß√Ķes ao nosso CMS. O c√≥digo ficaria assim:

// src/app/page.tsx import { createClient } from "@/prismicio"; export default async function Component() { const prismicClient = createClient(); const posts = await prismicClient.getAllByType("blog_post").catch(e => { console.error(e); return []; }); //... resto do componente }

Se voc√™ analisar o c√≥digo, vai ver que estamos utilizando diretamente do prismicClient a fun√ß√£o getAllByType. Essa fun√ß√£o serve para pegarmos todos os documentos (no nosso caso chamamos de postagens) do Prismic baseado no tipo que passarmos como par√Ęmetro. Esse nome √© o mesmo nome do modelo que criamos no Slice Machine, mas n√£o se preocupe se voc√™ n√£o se lembrar, o Prismic j√° criou a tipagem todos os seus modelos para voc√™.

Após chamarmos a função assíncrona, envolvemos seu retorno com o operador await e guardamos seu resultado na nossa constante posts. Outro ponto interessante para notar é que estamos tratando os erros simplesmente imprimindo o erro no console e retornando um array vazio como fallback.

Podemos agora pegar o resultado e renderizar em tela para vermos o que estamos recebendo. para isso, vamos abrir uma tag <main> e simplesmente envolver o array em um JSON.stringfy() :

// src/app/page.tsx import { createClient } from "@/prismicio"; export default async function Component() { const prismicClient = createClient(); const posts = await prismicClient.getAllByType("blog_post").catch(e => { console.error(e); return []; }); return ( <div className="grid gap-6 lg:gap-8"> <header className="space-y-2"> <h2 className="text-3xl font-bold tracking-tight sm:text-4xl text-slate-900 dark:text-white"> Meu Blog </h2> <p className="text-gray-500 dark:text-gray-400"> Blog onde vou escrever sobre tutoriais e dicas de programação. </p> </header> <main className="flex flex-col divide-y">{JSON.stringify(posts)}</main> </div> ); }

Se olharmos nossa p√°gina principal no navegador, veremos algo assim:

√ďbvio que isso √© s√≥ um amontoado de dados, mas se estamos vendo isso, significa que tivemos um retorno favor√°vel da API, ent√£o n√≥s podemos continuar.

Agora, vamos transformar essa informa√ß√Ķes em cards simples para termos uma visualiza√ß√£o interessante. Crie uma pasta chamada components dentro de src e vamos criar o componente PostItem.tsx .

Esse componente vai receber por propriedades um post e usaremos a informação recebida para exibir alguns dados. O código do componente pode ser visto abaixo:

// src/components/PostItem.tsx import Link from "next/link"; import { AllDocumentTypes } from "../../prismicio-types"; import { asText } from "@prismicio/client"; import dayjs from "dayjs"; interface PostItemProps { post: AllDocumentTypes; } export function PostItem({ post }: PostItemProps) { return ( <div className="flex flex-col gap-2 py-4"> <Link className="font-medium transition-opacity hover:opacity-70" href={post.uid}> <div className="flex flex-col gap-2"> <h3 className="transition-opacity duration-200 dark:text-white text-slate-900 hover:opacity-70"> {asText(post.data.title)} </h3> <p className="text-gray-500 font-normal">{asText(post.data.subtitle)}</p> </div> </Link> <p className="dark:text-white text-slate-900 text-sm"> Por{" "} <Link className="text-gray-900 dark:text-gray-500 hover:underline" href="#"> {post.data.author} </Link>{" "} <time dateTime="2023-10-10" className="text-gray-500"> - {dayjs(post.first_publication_date).format("DD/MM/YYYY")} </time> </p> </div> ); }

Vamos analisa-lo. Primeiro, se voc√™ notar, utilizo a biblioteca dayjs para trabalhar com datas no Javascript. Ela √© uma biblioteca muito √ļtil, pois facilita opera√ß√Ķes com datas al√©m de ser extremante leve. Ent√£o, vamos instala-la:

npm install dayjs

Outro ponto importante é que eu importei e usei o tipo BlogPostDocument . Se você seguir sua localização, vai ver que ele está no arquivo prismicio-types.d.ts na raiz do projeto. Esse arquivo é gerado pelo Prismic quando enviamos nosso modelo pelo Slice Machine. Nele estarão todas as tipagens de nossos modelos, então podemos importa-las onde precisarmos e teremos toda a tipagem necessária para os nossos documentos.

Também é possível notar o uso de um utilitário do Prismic, o asText. Esse utilitário tem como funcionalidade receber qualquer objeto do tipo RichTextField e traduzir para uma string. Muito util quando queremos simplesmente o valor real do campo sem toda a formatação e tags auto geradas do Prismic. No código, podemos notar que utilizei a função para exibir o título e o subtítulo. Fiz isso para conseguir ter uma maior personalização do campo, já que se eu utiliza-se o dado puro vindo do Prismic, não conseguiria estilizar diretamente a tag ou então teria que utilizar os componentes do Prismic que veremos em momentos posteriores.

Um Link do Next é utilizado no componente também. Nele redirecionamos para a página própria da postagem que criaremos mais pra frente.

De resto, temos só estilização para tornar o componente minimamente apresentável.

Agora, podemos utilizar esse componente na nossa página principal e renderizar nossa listagem de posts. Para isso, iremos remover o JSON.stringfy e colocar no lugar um map que percorre todas as postagens no array e renderiza nosso recém criado PostItem:

// src/app/page.tsx import { PostItem } from "@/components/PostItem"; import { createClient } from "@/prismicio"; export default async function Component() { const prismicClient = createClient(); const posts = await prismicClient.getAllByType("blog_post").catch(e => { console.error(e); return []; }); return ( <div className="grid gap-6 lg:gap-8"> <header className="space-y-2"> <h2 className="text-3xl font-bold tracking-tight sm:text-4xl text-slate-900 dark:text-white"> Meu Blog </h2> <p className="text-gray-500 dark:text-gray-400"> Blog onde vou escrever sobre tutoriais e dicas de programação. </p> </header> <main className="flex flex-col divide-y"> {posts.map(post => ( <PostItem key={post.id} post={post} /> ))} </main> </div> ); }

Com isso, temos uma listagem funcional e b√°sica, onde poderemos ver um resumo de nossas postagens e acessa-las.

Criando a p√°gina da postagem

Por √ļltimo, iremos come√ßar a implementa√ß√£o da p√°gina da postagem. Para come√ßar, vamos criar a pasta src/app/[uid] . Essa nomenclatura de pasta √© como fazemos para que o Next entenda que teremos uma rota din√Ęmica, assim, poder√≠amos acessar http://localhost:3000/testando-uma-rota e o Next nos forneceria uma rota v√°lida e como propriedade do componente desta p√°gina uma vari√°vel chamada uid com o valor "testando-uma-rota".

Dentro da pasta criada, vamos também criar também um arquivo chamado page.tsx. Ele será parecido com a página principal, porém iremos começar fazendo uma busca direcionada para uma postagem específica ao invés de buscar todas as postagens.

// src/app/[uid]/page.tsx import { createClient } from "@/prismicio"; import { notFound } from "next/navigation"; interface BlogPostProps { params: { uid: string; }; } export default async function BlogPost({ params }: BlogPostProps) { const prismicClient = createClient(); const post = await prismicClient.getByUID("blog_post", params.uid).catch(() => notFound()); return ( <div className="flex flex-col gap-4"> //TODO: Implementar conte√ļdo </div> ); }

De início podemos notar alguns pontos:

  1. Primeiro, estou declarando minha tipagem dizendo que nossa p√°gina vai receber como propriedades um campo chamado params e dentro dele vai haver nosso uid ;
  2. Segundo, nosso componente deve ser assíncrono para podermos buscar os dados do Prismic;
  3. Terceiro, estou trazendo o createClient novamente, mas desta vez, estou usando a função getByUID. Essa função, diferente da getAllByType, recebe qual modelo é nosso documento e qual é o UID dele, assim, traremos exatamente a postagem relacionada a essa página.
  4. Quarto ponto, estamos tratando o erro independente do tipo durante a busca, para redirecionar o usu√°rio √° p√°gina 404. Isso √© √ļtil para garantir que caso o UID passado n√£o exista ou tenha acontecido algum erro durante a busca, o usu√°rio vai ser redirecionado por seguran√ßa.

Como na página principal, vamos começar pelo header. No header, vamos renderizar um botão de voltar para o menu anterior, o título, subtítulo, a imagem principal da postagem e dados do autor e data de postagem.

// src/app/[uid]/page.tsx import { createClient } from "@/prismicio"; import { asText } from "@prismicio/client"; import { PrismicImage } from "@prismicio/react"; import dayjs from "dayjs"; import { CircleArrowLeft } from "lucide-react"; import Link from "next/link"; import { notFound } from "next/navigation"; interface BlogPostProps { params: { uid: string; }; } export default async function BlogPost({ params }: BlogPostProps) { const prismicClient = createClient(); const post = await prismicClient.getByUID("blog_post", params.uid).catch(() => notFound()); return ( <div className="flex flex-col gap-4" > <header className="flex flex-col gap-4"> <Link href=".." className="hover:opacity-80 transition-opacity flex gap-2 items-center mb-5"> <CircleArrowLeft /> Voltar </Link> <h1 className="text-3xl font-bold">{asText(post.data.title)}</h1> <h2 className="text-xl text-gray-500">{asText(post.data.subtitle)}</h2> <PrismicImage field={post.data.banner} /> <section> {post.data.author} - Criado em{" "} {dayjs(post.first_publication_date).format("DD/MM/YYYY")} </section> </header> <hr /> </div> ); }

Uma coisa importante sobre o código acima é que logo no começo do header, nós precisamos utilizar o componente <CircleArrowLeft /> . Esse componente é um ícone da biblioteca Lucid Icons. Ela será nossa biblioteca principal de ícones, já que é bem simplista e se encaixa bem com o Next e seus componentes de servidor. Para instala-la, rode o comando abaixo no terminal:

npm install lucide-react

Novamente, o t√≠tulo e o subt√≠tulo est√£o usando o utilit√°rio asText que j√° n√£o √© nenhum desconhecido para voc√™, por√©m, uma novidade aqui, √© como exibimos a imagem principal, j√° que estamos utilizando nosso primeiro componente do Prismic. O Prismic, fornece v√°rios componentes que se integram com os dados gerados pelo pr√≥prio, assim, ele vai fornecer um componente para cada tipo de dado que era poss√≠vel ser utilizado durante a montagem do modelo. O componente da vez √© o <PrismicImage /> e sua funcionalidade √© exibir imagens (ūüėÖ). Ele abstrai por detr√°s dos panos o Image do Next e fornece tudo que √© necess√°rio para uma boa renderiza√ß√£o de imagem na web.

Após essa codificação, se você acessar a página principal e clicar no nome da sua primeira postagem vai ver uma página parecida com essa:

Por√©m, essa √© s√≥ a ponta do iceberg, vamos continuar montando nossa p√°gina. Agora podemos adicionar o conte√ļdo repet√≠vel.

Para isso, vamos criar uma tag <main> e percorrer o array de conte√ļdo do nosso objeto de postagem que est√° acess√≠vel por post.data.content e para cada elemento neste array, iremos renderizar uma <Section /> da nossa postagem.

// src/app/[uid]/page.tsx import { createClient } from "@/prismicio"; import { asText } from "@prismicio/client"; import { PrismicImage, PrismicRichText } from "@prismicio/react"; import dayjs from "dayjs"; import { CircleArrowLeft } from "lucide-react"; import Link from "next/link"; import { notFound } from "next/navigation"; interface BlogPostProps { params: { uid: string; }; } export default async function BlogPost({ params }: BlogPostProps) { const prismicClient = createClient(); const post = await prismicClient.getByUID("blog_post", params.uid).catch(() => notFound()); return ( <div className="flex flex-col gap-4"> <header className="flex flex-col gap-4"> <Link href=".." className="hover:opacity-80 transition-opacity flex gap-2 items-center mb-5"> <CircleArrowLeft /> Voltar </Link> <h1 className="text-3xl font-bold">{asText(post.data.title)}</h1> <h2 className="text-xl text-gray-500">{asText(post.data.subtitle)}</h2> <PrismicImage field={post.data.banner} /> <section> {post.data.author} - Criado em{" "} {dayjs(post.first_publication_date).format("DD/MM/YYYY")} </section> </header> <hr /> <main className="flex flex-col gap-4 dark:text-gray-400 text-gray-600 font-light"> {post.data.content.map((item, index) => ( <section key={index}> <h3 className="text-2xl font-medium text-slate-900 dark:text-white"> {asText(item.title)} </h3> <PrismicRichText field={item.body} /> </section> ))} </main> </div> ); }

Em cada se√ß√£o, renderizei um <h3> contendo o t√≠tulo da se√ß√£o e novamente veremos mais um componente do Prismic. O <PrismicRichText /> √© um elemento que vai renderizar um campo do tipo Rich Text e se at√© ent√£o voc√™ n√£o entendeu a utilidade dos componente do Prismic, agora voc√™ vai entender. Por ele conseguir renderizar qualquer Rich Text , ele recebe o item.body do nosso conte√ļdo e vai renderizar todo o HTML necess√°rio, seja ele tags <h1-h6>, <strong>,<i>, <a>, <image>, <pre>, <p> ou seja o qu√™ for que voc√™ configurou no seu modelo para renderizar. A ideia aqui, √© que nosso c√≥digo n√£o sabe se voc√™ escreveu uma postagem com par√°grafos, imagens, links e etc, ent√£o, usando esse componente, ele vai conseguir transformar sua escrita em uma tag HTML correspondente para renderiza√ß√£o correta.

Com o código acima escrito, nossa página de postagem seria algo parecido com isso:

Estamos quase acabando agora. Para finalizar essa página podemos notar que alguns elementos não estão tão bem estilizados como gostaríamos. O tailwind tem um CSS Reset embutido, então tags como <ol> e <ul> por exemplo, não vão apresentar uma estilização e isso pode ocasionar em um visual estranho. Para resolver isso, temos duas abordagens:

  1. Utilizar uma propriedade do <PrismicRichText> chamado components que permite que voc√™ customize a renderiza√ß√£o de elementos espec√≠ficos do tipo Rich Text. Ao definir um objeto com pares de chave (tipo de elemento) e valor (componente React), voc√™ pode determinar como cada tipo de conte√ļdo (como t√≠tulos, par√°grafos e imagens) ser√° exibido dentro de um componente <PrismicRichText>. Por√©m, ao fazer isso, perdemos um pouco da m√°gica que o <PrismicRichText> nos d√°, fazendo com que tenhamos uma possibilidade de estiliza√ß√£o e personaliza√ß√£o extrema, por√©m perdemos a renderiza√ß√£o de tags autom√°ticas. H√° casos em que isso vale muito a pena e eu at√© utilizo no meu Blog original, por√©m acredito que para a situa√ß√£o atual, devemos partir por outro caminho. Se voc√™ quiser saber como utilizar melhor esse par√Ęmetro, n√£o se preocupe, o pr√≥prio c√≥digo do blog que voc√™ est√° vendo tem exemplos para isso e garanto que nas pr√≥ximas postagens irei tratar do uso deste campo. Por enquanto, se quiser um detalhe mais t√©cnico, veja a documenta√ß√£o do Prismic.
  2. Estilização do componente utilizando CSS/SASS: Essa abordagem basicamente remete em utilizarmos um arquivo .css ou .scss para estilizarmos somente dentro da nossa página de postagem e garantir que os elementos da nossa postagem tenham a estilização que desejamos e todo o resto da nossa aplicação continue intacto. Por ser uma abordagem simples e escalável, vamos seguir por ela.

Para iniciar, gosto de utilizar SASS no lugar do CSS por conta de sua versatilidade e por ter uma boa integração com o Tailwind. Para instalar o SASS, rode o seguinte comando no seu terminal:

npm install sass

Ap√≥s isso, vamos at√© o arquivo src/app/globals.css e vamos trocar seu nome para globals.scss e colocar como conte√ļdo o texto abaixo:

/* src/app/globals.css */ @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities";

Também não se esqueça de mudar o nome do arquivo na importação dentro de src/app/layout.tsx .

Agora, vamos at√© a pasta src/app/[uid] e vamos criar o arquivo styles.scss. Nele, adicionarei algumas estiliza√ß√Ķes referentes a algumas tags "resetadas" pelo Talwind. Um ponto interessante, √© que voc√™ vai notar o uso da palavra reservada @apply. Com ela conseguimos estilizar as tags utilizando as pr√≥prias classes do Talwind.

/* src/app/[uid]/styles.scss */ #blogPost { ul, ol { @apply mx-8 my-2; } ul { @apply list-disc; } ol { @apply list-decimal; @apply mx-10; } a { @apply underline; @apply font-medium; } em, strong { @apply font-medium; } }

Agora dentro de src/app/[uid]/page.tsx, vamos fazer duas coisas:

  1. Primeiro, adicionar a importação import "./styles.scss"; no topo do arquivo;
  2. Segundo, na primeira <div> da p√°gina vamos adicionar uma propriedade id com o valor: ‚ÄúblogPost‚ÄĚ. Fazemos isso para a estiliza√ß√£o ser aplicada somente nos filhos deste componente.

Com isso, teremos o suficiente para estilizar v√°rias tags. Sinta-se livre para testar v√°rias estiliza√ß√Ķes dependendo das suas postagens.

Configurando as Rotas no Prismic com o Route Resolver

Agora que todas as nossas páginas estão prontas, é crucial configurar corretamente as rotas no Prismic. Isso permite que links internos sejam adicionados às postagens diretamente pelo editor do Prismic, garantindo que esses links sejam funcionais e façam os redirecionamentos corretos em nossa aplicação.

Para configurar isso, precisamos editar o arquivo src/prismicio.ts. Nele, encontramos a constante routes, que inicialmente deixamos vazia. Esta constante é um array de objetos que define como as URLs dos documentos são resolvidas dentro do nosso aplicativo.

Aqui est√° como definimos as rotas para nossa listagem principal e para as rotas din√Ęmicas das postagens:

// src/prismicio.ts /** * Uma lista de objetos Route Resolver que definem como o campo `url` de um documento √© resolvido. * * Saiba mais em: {@link <https://prismic.io/docs/route-resolver#route-resolver>} */ const routes: prismic.ClientConfig["routes"] = [ { type: "blog_post", // Tipo do documento no Prismic uid: "homepage", // Identificador √ļnico para a rota da homepage path: "/", // Caminho da URL para a homepage }, { type: "blog_post", // Tipo do documento para postagens do blog path: "/:uid", // Caminho din√Ęmico da URL para cada postagem, baseado em seu UID }, ];

Com essas configura√ß√Ķes, o Prismic saber√° exatamente como mapear as URLs para a estrutura de pastas do nosso aplicativo App.

Adicionando segurança nas chamadas com o Prismic

At√© ent√£o, estamos fazendo chamadas diretamente para a API do Prismic utilizando o SDK, por√©m, tudo de maneira p√ļblica, ou seja, qualquer pessoa que souber o nome do nosso reposit√≥rio, pode fazer requisi√ß√Ķes de leitura para nossa API por fora do nosso site e isso pode ocasionar problemas de seguran√ßa e cobran√ßas indevidas pelo Prismic.

Para resolver isso, iremos privar todas as chamadas para a API e s√≥ ser√° permitido realizar requisi√ß√Ķes se enviarmos um token de acesso junto a cada requisi√ß√£o.

Primeiro, vamos até o site do Prismic, entramos na página do nosso repositório e vamos em configuração. A partir de lá, só acessar a aba de API e segurança.

Vamos então até a área Repository security e iremos trocar o acesso de Public Api para Private Api. Após a seleção, só precisamos clicar no botão escrito Change the API visibility.

Ok, agora todas as chamadas estão protegidas e você não vai mais poder requisitar suas postagens como fazíamos antes. Precisamos então, gerar um Access Token.

Para gerar um Access Token vamos na mesma página um pouco abaixo até a aba Generate an Access Token. Nesta área, precisamos preencher somente um campo que é o nome do aplicativo e deixamos a Callback URL vazia, já que não iremos nos preocupar com Oauth. Coloque o nome que você preferir, mas recomendo que seja algo que te lembre a qual aplicativo esse token se refere. Após isso, só clicar no botão Add this application.

Para nosso caso de uso, iremos utilizar o Permanent access tokens que foi gerado, basta copia-lo j√° que iremos utiliza-lo mais tarde. Esse token da acesso total de leitura as nossas postagens e iremos utilizar ele em nossa aplica√ß√£o para tornar nossas requisi√ß√Ķes seguras.

Com o token em mãos, vamos até nosso código. A primeira coisa que devemos fazer e criar um arquivo na raiz do projeto chamada .env.local . Esse arquivo será onde o Next vai buscar nossas variáveis de ambiente e é imprescindível que os dados que colocarmos aqui não vazem, então certifique-se de não enviar esse arquivo para o repositório Git.

  • Lembre-se que em caso de vazamento, basta voc√™ gerar um novo Access Token e revogar o anterior. Essa dica vale para qualquer aplica√ß√£o que precise guardar dados seguros.

Dentro deste arquivo vamos colocar o conte√ļdo abaixo:

PRISMIC_ACCESS_TOKEN=SEU_TOKEN

Se você estava executando a aplicação do Next em algum terminal, recomendo que você feche ela e rode novamente para a aplicação ter acesso a sua nova variável de ambiente (O next faz isso sozinho, mas por garantia, recomendo realizar esse passo). Um ponto interessante disso, é que essa variável do jeito que está escrita só pode ser acessada pelo lado do servidor do Next. Isso é muito importante, pois como estamos guardando um valor sensível e que só é utilizado no servidor, não há riscos dessa variável vazar para o cliente web da nossa aplicação. Caso queira entender melhor como o Next disponibiliza essas variáveis, acesse essa documentação.

Agora que temos nossa variável, podemos utilizar em nossa aplicação. Vamos até o arquivo src/prismicio.ts e na função createClient iremos adicionar uma nova linha:

// src/prismicio.ts export const createClient = (config: prismicNext.CreateClientConfig = {}) => { const client = prismic.createClient(repositoryName, { routes, fetchOptions: process.env.NODE_ENV === "production" ? { next: { tags: ["prismic"] }, cache: "force-cache" } : { next: { revalidate: 5 } }, accessToken: process.env.PRISMIC_ACCESS_TOKEN,//NOTE: Adicione essa linha ...config, }); prismicNext.enableAutoPreviews({ client, previewData: config.previewData, req: config.req, }); return client; };

A linha adicionada vai informar ao SDK do Prismic que devemos utilizar esse Access Token em cada requisição e se tudo estiver correto, agora sua aplicação voltou a funcionar e seu repositório Prismic está mais seguro.

O fim?

Com isso, encerro esse artigo e espero que voc√™ tenha conseguido absorver o m√°ximo de conhecimento poss√≠vel. Como disse anteriormente, foquei nos detalhes t√©cnicos de nossa aplica√ß√£o e como fazer uma integra√ß√£o f√°cil e r√°pida para a cria√ß√£o de um blog pessoal. Fique a vontade para melhorar e personalizar seu blog do jeito que quiser e fique ligado nas atualiza√ß√Ķes por aqui. Sempre que poss√≠vel, irei criar novas postagens que v√£o melhorar esse c√≥digo que criamos e adicionarei v√°rios outros elementos que um blog deve ter.

Para acessar o repositório git desse projeto, você pode clicar nesse link. Neste repositório irei separar em tags os marcos da evolução do nosso blog. Caso queira ver um projeto de blog completo como o quê você está, Acesse esse repositório.

Agradeço por ter chegado até aqui e qualquer feedback e sugestão são bem vindos para mantermos uma boa comunidade de desenvolvedores.

Vejo você na próxima postagem!


Gostou? Compartilhe!


Prismic
React
ūüďö Tutorial
ūüóěÔłŹ Blog
Next