Melhorando Meu Blog

(English version)
Um GIF de um fluxo de imagens que remete a algo digital.

Grandes mudanças aconteceram no Blog 🎉🎉🎉

Antes de explicar o que mudou, é importante explicar como o blog estava estruturado.

O blog tinha 3 rotas: a listagem de posts, o post em inglês e o post em português brasileiro.

Sempre que eu fazia um novo post, precisava criar uma nova rota para a postagem em Inglês e outra rota para a postagem em Português, além de copiar e colar todas as tags HTML que usei em um post para o outro.

Isso não escalava e dava um trabalhão 😔

A imagem de um gato branco, triste com lágrimas nos olhos

Eu precisava melhorar o blog para que meu foco ficasse apenas em escrever novas postagens e não em me preocupar com rotas, tags HTML e coisas do tipo.

Seria legal se eu pudesse escrever um arquivo Markdown, o blog convertesse isso para uma página HTML e criasse uma rota, tudo de forma automática.

Pesquisando na internet, descobri o gray-matter e então tudo mudou.

Gray-matter

O gray-matter é uma biblioteca inspirada no sistema de blog do Jekyll. Basicamente, ela consegue extrair o conteúdo e os metadados de um arquivo Markdown.

Vamos imaginar um arquivo chamado firstPost.md com este conteúdo:

# A Title For The First Post

This is the normal content, just a few things.

Another normal content to complete the blog post.

Agora, basta lermos o arquivo com o gray-matter, desta forma:

import fs from "fs";
import matter from "gray-matter";

const file = fs.readFileSync("content/firstPost.md");
const matterResult = matter(file);

A variável matterResult terá este valor:

{
  content: '# A Title For The First Post\n' +
    '\n' +
    'This is the normal content, just a few things.\n' +
    '\n' +
    'Another normal content to complete the blog post.\n',
  data: {},
  isEmpty: false,
  excerpt: ''
}

Todo o conteúdo do firstPost.md fica na chave content e você consegue manipulá-lo normalmente. Vamos ajustar nosso arquivo para ficar no padrão Front Matter.

---
title: A Title For The First Post
date: "2024-06-09"
---

This is the normal content, just a few things.

Another normal content to complete the blog post.

O resultado será:

{
  content: '\n' +
    'This is the normal content, just a few things.\n' +
    '\n' +
    'Another normal content to complete the blog post.\n',
  data: { title: 'A Title For The First Post', date: '2024-06-09' },
  isEmpty: false,
  excerpt: ''
}

Com isso, conseguimos segmentar e recuperar o conteúdo de um arquivo Markdown 😊

Mas como conseguimos converter isso para tags HTML?

React-markdown

O react-markdown é uma biblioteca que converte o conteúdo de um arquivo Markdown em tags HTML. Um parágrafo em Markdown vira uma tag <p>, um link em Markdown vira uma tag <a>, etc.

Para usar, é simples:

import fs from "fs";
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";

const file = fs.readFileSync("content/firstPost.md");
const matterResult = matter(file);

const PostComponent = () => (
  <div>
    <h1>{matterResult.data.title}</h1>
    <ReactMarkdown>{matterResult.content}</ReactMarkdown>
  </div>
);

O resultado vai ser algo parecido com isso:

<h1>A Title For The First Post</h1>

<p>This is the normal content, just a few things.</p>

<p>Another normal content to complete the blog post.</p>

Dessa forma, tudo que preciso fazer para criar novos posts é criar arquivos Markdown com os conteúdos.

#Bônus: Inserindo blocos de código

Para inserir em nosso blog trechos de código de forma elegante, basta usarmos a biblioteca react-syntax-highlighter. Ela oferece Syntax highlighting e formatação de código.

Mas como conseguimos integrar isso ao react-markdown?

Simples, basta usarmos a propriedade components. Imagine nosso arquivo firstPost.md, porém com esse trecho de código:

---
title: A Title For The First Post
date: "2024-06-09"
---

This is the normal content, just a few things.

Another normal content to complete the blog post.

```
const dogName = "Cacau";
console.log(dogName);
```

Agora precisamos ajustar o react-markdown para lidar com blocos de código:

import fs from "fs";
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";

const file = fs.readFileSync("content/firstPost.md");
const matterResult = matter(file);

const CodeBlock = ({ children }) => {};

const PostComponent = () => (
  <div>
    <h1>{matterResult.data.title}</h1>
    <ReactMarkdown components={{ code: CodeBlock }}>
      {matterResult.content}
    </ReactMarkdown>
  </div>
);

Neste momento, sempre que o ReactMarkdown se deparar com um trecho de código ele vai chamar a função CodeBlock. Agora, podemos usar o react-syntax-highlighter dentro da nossa nova função:

import fs from "fs";
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";
import { atomDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";

const file = fs.readFileSync("content/firstPost.md");
const matterResult = matter(file);

const CodeBlock = ({ children }) => {
  return (
    <SyntaxHighlighter language={"javascript"} style={atomDark}>
      {children}
    </SyntaxHighlighter>
  );
};

const PostComponent = () => (
  <div>
    <h1>{matterResult.data.title}</h1>
    <ReactMarkdown components={{ code: CodeBlock }}>
      {matterResult.content}
    </ReactMarkdown>
  </div>
);

A propriedade language indica a linguagem de programação utilizada e o style é o tema usado, no meu caso estou utilizando o atomDark.

Você pode verificar os temas disponíveis no próprio repositório do react-syntax-highlighter.

O código gerado vai se parecer com isso:

const dogName = "Cacau";

console.log(dogName);

Conclusão

Tudo isso foi uma grande mudança no blog que me possibilitou ser mais produtivo para escrever novos conteúdos. Agora não preciso mais me preocupar em criar tags HTML, tudo o que preciso fazer é apenas escrever um arquivo Markdown.

Em breve vou explicar como fiz para criar rotas dinâmicas utilizando Next.

Se quiser se aprofundar mais, o incrível post do Jose Felix explica em detalhes outros pontos.