Utilice highlight.js para implementar el resaltado de sintaxis de código en ToolMi

Presenta en detalle cómo integrar highlight.js en el proyecto Vue 3 para lograr el resaltado de la sintaxis del código, incluida la selección técnica completa, el proceso de implementación y el intercambio de experiencias de pozo.

Antecedentes del proyecto y análisis de requisitos

Como desarrollador de ToolMi(gongjumi.com), siempre me esfuerzo por ofrecer a los usuarios una mejor experiencia con las herramientas en línea. Recientemente, al actualizar la función de visualización de código del sitio, descubrí que el componente nativo textarea tiene limitaciones de UX significativas al manejar la entrada y salida de código.

Gongjumi ofrece muchas herramientas relacionadas con código, como el Formateador YAML, el Generador de entidad Java desde SQL y el Beautificador de TypeScript. Todas requieren que los usuarios ingresen código y muestren los resultados procesados. Sin embargo, los textarea simples carecen de resaltado de sintaxis, lo que dificulta que los usuarios localicen errores en códigos complejos y disminuye la experiencia general.

Selección de tecnología: Por qué highlight.js

Entre las muchas bibliotecas de resaltado de sintaxis disponibles, elegí highlight.js por varias razones clave:

Amplio soporte de lenguajes

highlight.js soporta más de 190 lenguajes de programación, desde populares como JavaScript, Python y Java hasta lenguajes funcionales menos comunes. Esta cobertura es esencial para un sitio como Gongjumi que maneja múltiples formatos de código.

Biblioteca de temas variada

La biblioteca ofrece estilos de tema como GitHub, VS Code y Atom. Esto permite elegir un tema de visualización que se alinee con la estética de Gongjumi.

Gran compatibilidad con el ecosistema

highlight.js se integra de forma natural con Vue.js y es fácil de configurar. Además, su detección automática de lenguaje aplica resaltado incluso si el usuario no lo especifica.

Ventajas de rendimiento

En comparación con editores pesados como Monaco Editor, highlight.js es mucho más ligero y se carga rápidamente, ideal para las herramientas en línea rápidas de Gongjumi.

Detalles de implementación

Primer intento: Superposición de dos capas

Inicialmente probé superponer un div con el código resaltado sobre un textarea transparente:

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

Esta configuración permitía escribir en el textarea mientras la capa de fondo mostraba el código resaltado. Pero presentaba fallos críticos:

  • La capa de resaltado y la de entrada se desalineaban con código largo o múltiples líneas.
  • Mantener la sincronización del desplazamiento era complejo.
  • Igualar fuentes, alturas de línea y rellenos resultaba muy complicado.

Optimización con CSS Grid

Para alinear ambos elementos, los coloqué en la misma área de cuadrícula:

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

Esto mejoró la alineación, pero el desplazamiento sincronizado y la consistencia de estilos seguían siendo un reto.

Solución final: Div con contenteditable

Después de varios intentos, la mejor solución fue usar un div con contenteditable:

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

Ventajas:

  • Usa estilos CSS nativos de highlight.js sin adaptaciones.
  • Evita estructuras superpuestas complejas.
  • Edición y visualización unificadas para una UX más fluida.

Implementación del código principal

Diseño de la interfaz del componente

Para reutilizar el editor en todas las herramientas de Gongjumi, diseñé esta interfaz:

interface Props {
  modelValue: string      // contenido del código con enlace bidireccional
  language?: string       // lenguaje opcional
  readonly?: boolean      // modo solo lectura
  placeholder?: string    // texto de marcador
  rows?: number           // líneas visibles
}

Lógica de resaltado de sintaxis

El núcleo es invocar la API de highlight.js y gestionar errores:

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('Error de resaltado de sintaxis:', error);
    highlightedCode.value = escapeHtml(localValue.value);
  }
};

Modo edición vs. solo lectura

Implementé dos modos según la necesidad:

<template>
  <pre v-if="readonly" class="readonly-code hljs" v-html="highlightedCode"></pre>
  <div v-else contenteditable="true" class="editable-code hljs" @input="handleInput"></div>
</template>

Detalles técnicos clave

Integración de temas

Para ajustar al diseño de Gongjumi, importé el tema GitHub:

import 'highlight.js/styles/github.css';

Mejoras de interacción

  • Manejo de Tab: insertar espacios en lugar de cambiar de foco.
  • Pegado: conservar solo texto plano.
  • Debounce: evitar actualizaciones excesivas al escribir rápido.

Mantener posición del cursor

Implementé lógica para guardar y restaurar la posición del cursor:

const handleInput = () => {
  const cursorPosition = saveCursorPosition();
  updateContent();
  updateHighlight();
  nextTick(() => {
    restoreCursorPosition(cursorPosition);
  });
};

Efectos de aplicación en el mundo real

Actualización de la herramienta SQL a entidad Java

  • Resaltado completo de sintaxis SQL en el textarea de entrada.
  • Resaltado profesional en el código Java generado.
  • Interfaz más pulida y feedback muy positivo.

Mejora del formateador JSON

El resaltado de sintaxis ayuda a visualizar la jerarquía y detectar errores más rápido.

Beautificador de TypeScript

De simples <pre> y <code> a un componente completo con experiencia similar a un IDE.

Optimización de rendimiento y mejores prácticas

Carga bajo demanda

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);

Ciclo de vida del componente

  • Inicializar highlight.js al montar.
  • Actualizar resaltado en cada actualización.
  • Limpiar recursos al desmontar.

Diseño responsivo

  • Tamaños de fuente y altura de línea adecuados.
  • Interacciones táctiles.
  • Desplazamiento y zoom optimizados.

Lecciones aprendidas

Problemas comunes y soluciones

Desalineación de capas

La solución fue abandonar las dos capas y usar un div con contenteditable. Si es inevitable, usar CSS Grid en lugar de posición absoluta.

Salto del cursor

Se resolvió guardando/restaurando la posición del cursor y aplicando debounce.

Conflictos de estilos

Usar CSS scoped o CSS Modules para aislar los estilos de highlight.js.

Consejos de depuración

  • Inspeccionar cambios del DOM con las DevTools.
  • Monitorear errores de highlight.js en la consola.
  • Probar distintos lenguajes y longitudes de código.
  • Verificar en varios navegadores y dispositivos.

Planes de expansión futura

Mejoras de funcionalidades

  • Números de línea: facilitar la localización en fragmentos largos.
  • Plegado de código: colapsar/expandir bloques.
  • Búsqueda y reemplazo: encontrar y reemplazar texto rápidamente.
  • Formateo integrado: un clic con Prettier u otra herramienta.

Tuning de rendimiento adicional

  • Implementar desplazamiento virtual para archivos grandes.
  • Optimizar algoritmos para reducir latencia.
  • Añadir caché para evitar análisis redundante.

Resumen del proyecto y reflexión

Logros técnicos

La integración de highlight.js permitió entender en profundidad los editores front-end modernos, dominar interacciones complejas y aplicar desarrollo basado en componentes.

Valor entregado al usuario

El nuevo resaltado mejora drásticamente la UX en detección de errores y comprensión de código complejo, según el feedback de usuarios.

Perspectivas arquitectónicas

El diseño basado en componentes sienta una base sólida para futuras funciones y reutilización en otros proyectos.

En Gongjumi, cada detalle de UX importa. El resaltado de sintaxis puede parecer pequeño, pero refleja un profundo entendimiento del usuario y búsqueda de calidad.