Melhorando Meu Blog
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 😔
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.