Criando componente React com renderizador de Markdown e syntax highlight de código
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:
- https://github.com/markedjs/marked/
- https://github.com/isagalaev/highlight.js/
- https://github.com/utatti/react-render-html/
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
})