Random Thoughts

This blog development process

Criando componente React com renderizador de Markdown e syntax highlight de código

Friday, March 16, 2018

Markdown é bem legal. Como talvez você já saiba, este blog é baseado em arquivos markdown estáticos. Arquivos FrontMatter para ser mais preciso. Confira o arquivo fonte deste post. Agora deixe eu te contar como eu faço a renderização do conteúdo dos arquivos markdown.

Na verdade existem muitas formas de lidar com essa situação. Uma por exemplo, como na documentação do storybook deste site, usa o Webpack loader para importar arquivos Markdown diretamente para JavaScript. Simples como import Content from 'content.md' e então os dados importados podem ser renderizados usando algo como o dangerouslySetInnerHTML.

Mas mais especificamente para o conteúdo deste site, o gerador de dados retorna o conteúdo markdown em um arquivo JSON estático. Ainda sem converter para HTML. Para usar essa string markdown para renderizar na página, primeiro ela precisa ser convertida para HTML e então renderizada como JSX.

Eu usei algumas bibliotecas de terceiros para me ajudar com o trabalho pesado:

Não tem muito segredo, todas essas bibliotecas têm boa documentação. Vá em frente e instale os pacotes:

yarn add marked react-render-html highlight.js

Então crie um componente para encapsular essa lógica de renderização, assim você pode simplesmente reutilizar a mesma lógica em qualquer lugar.

O componente MarkdownRenderer

É assim que meu componente React se parece:

// MarkdownRenderer.js
import { PureComponent } from 'react'
import marked from 'marked'
import renderHTML from 'react-render-html'
import hljs from 'highlight.js'
import 'highlight.js/styles/tomorrow-night-eighties.css'

marked.setOptions({
  highlight: (code, language) => language
    ? hljs.highlight(language, code).value
    : hljs.highlightAuto(code).value
})

class MarkdownRenderer extends PureComponent {
  static defaultProps = {
    text: '',
  }

  render() {
    const { text } = this.props
    return text ? renderHTML(marked(text)) : null
  }
}

export default MarkdownRenderer

Veja no código fonte.

Extras legais

O highlight.js vai tentar identificar a linguagem do código automaticamente e criar estilos da melhor forma possível. Mesmo assim, usá-lo com o marked também permite definir a linguagem nos blocos de código, como em:

// markdown-file.md
```javascript
function() {
  console.log('this is actually a "markdown" code block haha')
}

[Edição 2018-03-20]

A opção de highlight que eu estava usando quando escrevi este post não estava identificando corretamente as linguagens de forma automática, então eu melhorei um pouco o código do MarkdownRenderer.js:

marked.setOptions({
-  highlight: (code) => hljs.highlightAuto(code).value
+  highlight: (code, language) => language
+    ? hljs.highlight(language, code).value
+    : hljs.highlightAuto(code).value
})