Este artículo demuestra las nuevas características implementadas para mostrar código de manera profesional, basadas en las mejores prácticas de documentación técnica moderna.
Line Highlighting: Destaca lo importante
A veces necesitas llamar la atención sobre líneas específicas de código. El line highlighting te permite hacerlo fácilmente.
Ejemplo 1: Destacar una sola línea
Aquí destacamos la línea 2 donde ocurre la lógica crítica:
1function calculateTotal(items) {2const total = items.reduce((sum, item) => sum + item.price, 0);3return total * 1.19; // IVA incluido4}
Ejemplo 2: Destacar un rango
Cuando quieres destacar un bloque completo, usa la sintaxis de rango:
1export default defineConfig({2integrations: [3react(),4tailwind(),5sitemap(),6],7vite: {8ssr: {9noExternal: ['react', 'react-dom'],10},11},12});
Ejemplo 3: Líneas múltiples no consecutivas
Combina ranges y líneas individuales para máxima flexibilidad:
1import { useState, useEffect, useCallback } from 'react';2import { Moon, Sun } from 'lucide-react';3import { cn } from '@/lib/utils';45export function ThemeToggle() {6const [theme, setTheme] = useState('light');7const [mounted, setMounted] = useState(false);89useEffect(() => {10setMounted(true);11const savedTheme = localStorage.getItem('theme');12setTheme(savedTheme || 'light');13}, []);1415const toggleTheme = useCallback(() => {16const newTheme = theme === 'light' ? 'dark' : 'light';17setTheme(newTheme);18localStorage.setItem('theme', newTheme);19}, [theme]);2021if (!mounted) return null;2223return (24<button onClick={toggleTheme}>25{theme === 'light' ? <Moon /> : <Sun />}26</button>27);28}
Sintaxis soportada:
"2"- Una sola línea"2-5"- Rango de líneas"1,3,5"- Líneas individuales"1-3,7,9-11"- Combinación de ranges e individuales
Code Diff: Muestra cambios antes/después
El componente CodeDiff es perfecto para tutoriales, migraciones, y documentación de refactorización.
Vista Split (lado a lado)
Ideal para comparar archivos completos o secciones grandes:
1export default defineConfig({2darkMode: 'class',3theme: {4extend: {5colors: {6background: 'hsl(var(--background))',7foreground: 'hsl(var(--foreground))',8}9}10}11});
1@theme {2--color-background: oklch(0.98 0 0);3--color-foreground: oklch(0.09 0 0);4}56@custom-variant dark (&:where(.dark, .dark *));78.dark {9--color-background: oklch(0.15 0 0);10--color-foreground: oklch(0.98 0 0);11}
Vista Unified (combinada)
Mejor para cambios pequeños donde quieres ver el contexto:
-function fetchUser(id) {+async function fetchUser(id) {-return fetch(`/api/users/${id}`)+const res = await fetch(`/api/users/${id}`);-.then(res => res.json())+const data = await res.json();-.then(data => data.user);+return data.user;}
Ejemplo Real: Refactorización de componente
Veamos cómo quedó la mejora de un componente React real:
1export function CodeBlock({ code, language }) {2const [copied, setCopied] = useState(false);34return (5<div className="bg-zinc-950 rounded-lg">6<pre>7<code className={`language-${language}`}>8{code}9</code>10</pre>11</div>12);13}
1export function CodeBlock({2code,3language,4highlightLines,5showLineNumbers = false6}) {7const [copied, setCopied] = useState(false);89const highlightedLines = useMemo(() => {10if (!highlightLines) return new Set();11// Parser logic...12return lines;13}, [highlightLines]);1415const codeLines = code.split('\n');1617return (18<div className="bg-background rounded-lg border border-border">19<pre>20{codeLines.map((line, i) => {21const isHighlighted = highlightedLines.has(i + 1);22return (23<div24key={i}25className={isHighlighted ? 'bg-blue-500/10' : ''}26>27{showLineNumbers && <span>{i + 1}</span>}28<code className={`language-${language}`}>29{line}30</code>31</div>32);33})}34</pre>35</div>36);37}
Casos de uso reales
1. Tutoriales de migración
Cuando explicas cómo migrar de una versión a otra:
-import { Twitter, Linkedin, Facebook } from 'lucide-react';+import { Share2, Link } from 'lucide-react';export function ShareButtons() {return (-<div className="bg-white dark:bg-zinc-950">+<div className="bg-background">-<Twitter />+<Share2 />-<Linkedin />+<Link />-<Facebook />+</div>-</div>+);-);+}-}
2. Explicar conceptos de seguridad
Destaca exactamente dónde está el problema:
1app.get('/user/:id', (req, res) => {2const query = "SELECT * FROM users WHERE id = " + req.params.id;3db.query(query, (err, result) => {4res.json(result);5});6});
Y luego la solución:
1app.get('/user/:id', (req, res) => {2const query = "SELECT * FROM users WHERE id = ?";3db.query(query, [req.params.id], (err, result) => {4res.json(result);5});6});
3. Mostrar mejoras de performance
Comparación de implementaciones:
1// ❌ Re-render en cada keystroke2function SearchInput() {3const [query, setQuery] = useState('');4const [results, setResults] = useState([]);56useEffect(() => {7fetch(`/api/search?q=${query}`)8.then(res => res.json())9.then(setResults);10}, [query]);1112return (13<input14value={query}15onChange={e => setQuery(e.target.value)}16/>17);18}
1// ✅ Debounced + AbortController2function SearchInput() {3const [query, setQuery] = useState('');4const [results, setResults] = useState([]);56useEffect(() => {7const controller = new AbortController();8const timer = setTimeout(() => {9fetch(`/api/search?q=${query}`, {10signal: controller.signal11})12.then(res => res.json())13.then(setResults)14.catch(err => {15if (err.name !== 'AbortError') throw err;16});17}, 300);1819return () => {20clearTimeout(timer);21controller.abort();22};23}, [query]);2425return (26<input27value={query}28onChange={e => setQuery(e.target.value)}29/>30);31}
Mejores prácticas
Cuándo usar Line Highlighting
✅ Usa highlighting cuando:
- Explicas un concepto específico en 1-3 líneas
- Muestras dónde ocurre un error
- Señalas cambios importantes en un bloque
- Enseñas patrones de código específicos
❌ No lo uses cuando:
- Todo el código es igualmente importante
- El bloque tiene menos de 5 líneas
- Destacas más del 50% de las líneas (pierde efectividad)
Cuándo usar CodeDiff
✅ Usa diff cuando:
- Explicas una migración o refactorización
- Comparas dos enfoques (antes/después)
- Muestras evolución de código
- Documentas breaking changes
❌ No lo uses cuando:
- Los cambios son cosméticos (espaciado, formatting)
- Son archivos completamente diferentes (no relacionados)
- Solo agregaste código nuevo (usa highlighting)
Split vs Unified
Split view (default):
- ✅ Mejor para archivos completos
- ✅ Comparación lado a lado clara
- ✅ Ideal en desktop
- ❌ Stack en mobile (menos óptimo)
Unified view:
- ✅ Mejor para cambios pequeños
- ✅ Más compacto en mobile
- ✅ Similar a git diff
- ❌ Puede ser confuso con muchos cambios
Implementación técnica
Line Highlighting
El parser soporta la sintaxis de ranges usando un Set para O(1) lookup:
1const highlightedLineNumbers = useMemo(() => {2if (!highlightLines) return new Set<number>();34const lines = new Set<number>();5const parts = highlightLines.split(',').map(p => p.trim());67for (const part of parts) {8if (part.includes('-')) {9const [start, end] = part.split('-').map(Number);10for (let i = start; i <= end; i++) {11lines.add(i);12}13} else {14lines.add(Number(part));15}16}1718return lines;19}, [highlightLines]);
Diff Algorithm
El algoritmo de diff es línea por línea (simple pero efectivo):
1const beforeLines = before.split('\n');2const afterLines = after.split('\n');3const maxLength = Math.max(beforeLines.length, afterLines.length);45Array.from({ length: maxLength }).map((_, index) => {6const beforeLine = beforeLines[index];7const afterLine = afterLines[index];89if (beforeLine === afterLine) {10return <UnchangedLine line={beforeLine} />;11}1213return (14<>15{beforeLine && <RemovedLine line={beforeLine} />}16{afterLine && <AddedLine line={afterLine} />}17</>18);19});
Performance
Bundle impact:
- CodeBlock v2.0: 0KB extra (solo lógica)
- CodeDiff: +3KB gzipped
- Total: ~3KB adicional
Rendering:
- Line highlighting usa
useMemopara cachear el parser - Solo re-calcula cuando cambia
highlightLines - Rendering iterativo con keys estables
Accesibilidad
Ambos componentes son WCAG 2.1 AA compliant:
- ✅ Contraste ≥4.5:1 en todas las combinaciones
- ✅ Botones de copia con
aria-labeldescriptivo - ✅ Código semántico con
<pre>y<code> - ✅ Line numbers con
select-nonepara no copiarlos - ✅ Dark mode totalmente soportado
Conclusión
Estas características elevan la calidad de la documentación técnica al nivel de las mejores herramientas modernas como Nextra, Material for MkDocs, y GitHub.
Line Highlighting hace que tus ejemplos sean más claros y enfocados.
CodeDiff convierte explicaciones complejas en comparaciones visuales instantáneas.
Juntos, hacen que el contenido técnico sea más fácil de entender y más agradable de leer.
Recursos
Contenido Relacionado
Más experimentos de Development