Use highlight.js para implementar o destaque de sintaxe de código no ToolMi

Ele apresenta em detalhes como integrar o highlight.js ao projeto Vue 3 para obter o destaque da sintaxe do código, incluindo seleção técnica completa, processo de implementação e compartilhamento de experiência no poço.

Contexto do projeto e análise de requisitos

Como desenvolvedor do ToolMi(gongjumi.com), esforço-me constantemente para oferecer aos usuários uma experiência online superior. Recentemente, ao atualizar o recurso de exibição de código do site, percebi que o componente nativo textarea apresenta limitações claras de UX ao lidar com entrada e saída de código.

O Gongjumi oferece várias ferramentas relacionadas a código, como o Formatador YAML, o Gerador de entidade Java a partir de SQL e o Beautifier TypeScript. Todas essas ferramentas exigem que o usuário insira código e visualize o resultado processado. No entanto, as textarea simples não oferecem realce de sintaxe, dificultando a localização de erros em códigos complexos e prejudicando a experiência geral.

Escolha tecnológica: por que highlight.js

Dentre as várias bibliotecas de realce de sintaxe disponíveis, escolhi highlight.js pelos seguintes motivos:

Amplo suporte de linguagens

highlight.js suporta mais de 190 linguagens de programação, desde as mais populares (JavaScript, Python, Java) até linguagens funcionais menos comuns. Essa cobertura é essencial para um site como o Gongjumi, que lida com diversos formatos de código.

Variedade de temas

A biblioteca oferece vários estilos de tema, como GitHub, VS Code e Atom. Isso permite escolher um tema que se alinhe à estética do Gongjumi.

Compatibilidade com o ecossistema

highlight.js se integra facilmente ao ecossistema Vue.js e sua configuração é relativamente simples. Além disso, possui detecção automática de linguagem, aplicando realce mesmo sem especificação pelo usuário.

Desempenho otimizado

Comparado a editores mais pesados como o Monaco Editor, highlight.js é mais leve e carrega mais rápido, ideal para as ferramentas online responsivas do Gongjumi.

Detalhes da implementação

Primeira abordagem: sobreposição em duas camadas

Inicialmente, tentei a abordagem comum de sobrepor um div com o código realçado sobre um textarea transparente:

<div class="editor-container">
  <div class="code-highlight" v-html="highlightedCode"></div>
  <textarea v-model="code" class="code-textarea"></textarea>
</div>

Essa configuração permitia digitar no textarea transparente enquanto a camada de fundo exibia o código realçado. Porém, apresentou falhas críticas:

  • As camadas de realce e entrada frequentemente se desalinham em códigos longos ou com várias quebras de linha.
  • Sincronizar a rolagem era difícil, pois uma camada não acompanhava a outra.
  • Combinar fontes, espaçamento entre linhas e padding ficou muito complicado.

Otimização com CSS Grid

Para corrigir o alinhamento, utilizei CSS Grid colocando ambos os elementos na mesma área de grade:

.editor-container {
  display: grid;
  grid-template-areas: "editor";
}
.code-highlight, .code-textarea {
  grid-area: editor;
}

Isso melhorou o alinhamento, mas sincronizar a rolagem e manter a consistência de estilo ainda era desafiador.

Solução final: div contenteditable

Após várias tentativas, a melhor solução foi usar um div com contenteditable:

<div
  contenteditable="true"
  class="editable-code hljs"
  v-html="highlightedCode"
  @input="handleInput"
/>

Vantagens:

  • Uso direto dos estilos nativos do highlight.js sem adaptações extras.
  • Evita estruturas sobrepostas complexas, eliminando problemas de alinhamento e sincronização.
  • UX mais consistente, com edição e exibição totalmente unificadas.

Implementação do código principal

Design da interface do componente

Para tornar o editor reutilizável em todas as ferramentas do Gongjumi, projetei esta interface:

interface Props {
  modelValue: string      // conteúdo de código com vínculo bidirecional
  language?: string       // especificação de linguagem opcional
  readonly?: boolean      // modo somente leitura
  placeholder?: string    // texto placeholder
  rows?: number           // número de linhas visíveis
}

Lógica de realce de sintaxe

O núcleo do realce consiste em chamar a API do highlight.js corretamente e tratar erros:

const updateHighlight = () => {
  try {
    if (props.language && hljs.getLanguage(props.language)) {
      const result = hljs.highlight(localValue.value, { language: props.language });
      highlightedCode.value = result.value;
    } else {
      const result = hljs.highlightAuto(localValue.value);
      highlightedCode.value = result.value;
    }
  } catch (error) {
    console.error('Erro ao realçar sintaxe:', error);
    highlightedCode.value = escapeHtml(localValue.value);
  }
};

Modo de edição vs modo somente leitura

Como o Gongjumi precisa de cenários de entrada e exibição, implementei dois modos:

<template>
  <!-- Modo somente leitura para exibir resultados processados -->
  <pre v-if="readonly" class="readonly-code hljs" v-html="highlightedCode"></pre>

  <!-- Modo de edição para entrada de código -->
  <div v-else contenteditable="true" class="editable-code hljs" @input="handleInput"></div>
</template>

Detalhes técnicos principais

Integração de temas

Para alinhar ao design do Gongjumi, escolhi o tema GitHub e fiz ajustes de cor:

// importar tema do highlight.js
import 'highlight.js/styles/github.css';

Melhorias na interação do usuário

  • Tratamento da tecla Tab: insere espaços em vez de mudar o foco.
  • Tratamento de colagem: remove formatação e mantém apenas texto puro.
  • Debounce na entrada: evita atualizações excessivas em digitações rápidas.

Manutenção da posição do cursor

Para evitar que o cursor seja resetado, implementei lógica de salvar e restaurar posição:

const handleInput = () => {
  // salvar posição atual do cursor
  const cursorPosition = saveCursorPosition();
  // atualizar conteúdo e realce
  updateContent();
  updateHighlight();
  // restaurar cursor após atualização do DOM
  nextTick(() => {
    restoreCursorPosition(cursorPosition);
  });
};

Impacto em aplicações reais

Atualização da ferramenta SQL → entidade Java

  • Realce completo de sintaxe SQL na área de entrada.
  • Realce profissional no código Java gerado.
  • Interface mais polida e feedback muito positivo.

Melhoria do formatador JSON

O realce de sintaxe facilita a visualização da estrutura e acelera a identificação de erros.

Beautifier TypeScript

De simples <pre> e <code> para um componente completo com experiência de IDE.

Otimizações de desempenho e melhores práticas

Carregamento sob demanda

// importar núcleo e apenas as linguagens necessárias
import hljs from 'highlight.js/lib/core';
import javascript from 'highlight.js/lib/languages/javascript';
import python from 'highlight.js/lib/languages/python';
import java from 'highlight.js/lib/languages/java';
import sql from 'highlight.js/lib/languages/sql';

hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('python', python);
hljs.registerLanguage('java', java);
hljs.registerLanguage('sql', sql);

Gerenciamento do ciclo de vida do componente

  • Inicializar highlight.js ao montar o componente.
  • Atualizar realce no momento de updates.
  • Limpar recursos ao desmontar.

Design responsivo

  • Fontes e espaçamento adaptados para dispositivos móveis.
  • Interações touch-friendly.
  • Rolagem e zoom otimizados.

Lições aprendidas

Problemas comuns e soluções

Desalinhamento de camadas

A solução foi abandonar a abordagem de duas camadas e usar um div contenteditable. Se necessário, prefira CSS Grid a posicionamento absoluto.

Pulo do cursor

Resolvido com salva/restaura cursor e debounce nas atualizações.

Conflitos de estilo

Use CSS Modules ou scoped CSS para isolar estilos do highlight.js.

Dicas de depuração

  • Inspecione mudanças no DOM com as DevTools.
  • Monitore erros do highlight.js no console.
  • Teste diferentes linguagens e tamanhos de código.
  • Valide em vários navegadores e dispositivos.

Perspectivas de evolução

Funcionalidades futuras

  • Números de linha: facilita referência em trechos longos.
  • Dobramento de código: collapse/expand de blocos.
  • Busca e substituição: encontre e substitua texto rapidamente.
  • Formatação integrada: um clique com Prettier.

Aprimoramentos de desempenho adicional

  • Implementar scroll virtual para arquivos grandes.
  • Otimizar algoritmos para reduzir latência.
  • Adicionar cache para evitar parse redundante.

Resumo do projeto e reflexão

Conquistas técnicas

Esta integração do highlight.js me permitiu entender a fundo editores front-end modernos, dominar interações complexas e fortalecer práticas de desenvolvimento baseado em componentes.

Valor entregue ao usuário

O realce de sintaxe melhorou drasticamente a UX na detecção de erros e na compreensão de códigos complexos, conforme feedback dos usuários.

Perspectivas arquitetônicas

Um componente bem projetado não atende apenas às necessidades atuais, mas também forma uma base sólida para futuras evoluções e reutilização em outros projetos.

No Gongjumi, cada detalhe de UX importa. O realce de sintaxe, embora pequeno, simboliza nosso compromisso contínuo com a qualidade e a compreensão das necessidades dos usuários.