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.