Nativo hasta el final, hasta que necesites texto
(justsitandgrin.im)- En macOS, si creas una UI de chat Markdown usando solo SwiftUI, puedes obtener un rendimiento base aceptable, pero es difícil soportar la selección de todo el documento
- Si lo migras a
NSTextViewy TextKit 2, pierdes el trabajo de pruebas y rendimiento hecho en SwiftUI, y aparecen picos de CPU con la entrada en streaming - Reimplementar con
NSCollectionViewprovoca parpadeo de celdas, y usar solo TextKit 2 ofrece un rendimiento aceptable pero una mala integración con el streaming - WebKit encaja bastante bien en renderizado Markdown, rendimiento, tipografía y nivel de control; además, en Electron el trabajo con texto funciona de forma predeterminada
- En chats largos y texto enriquecido, SwiftUI y los SDK nativos de Apple se vuelven una limitación, mientras que lo basado en web tiene ventaja en el modelo de texto y renderizado
Límites de una UI de chat Markdown nativa en macOS
- Si construyes un chat simple con soporte Markdown usando solo SwiftUI, puedes lograr un rendimiento base razonable, pero no puedes seleccionar el documento Markdown completo si está compuesto con primitivas de SwiftUI
- Si lo mueves a
NSTextView, ganas soporte de TextKit 2, pero pierdes gran parte del trabajo de pruebas y rendimiento que ya habías hecho en SwiftUI, y además deja de encajar bien con SwiftUI - Si insertas respuestas del modelo en
NSTextViewmediante streaming, se producen picos de CPU - Aunque se reimplemente con
NSCollectionView, las celdas siguen parpadeando, y eso termina siendo un comportamiento difícil de evitar por diseño - Un prototipo puro con TextKit 2 tiene un rendimiento aceptable, pero el streaming sigue funcionando mal y no encaja bien con componentes modernos
- Incluso si eliminas por completo SwiftUI y usas solo AppKit, tienes que manejar manualmente fragmentos de texto que se van expandiendo, y la selección de texto solo se vuelve posible cuando muchas partes ya están rotas
- Para llegar a un nivel similar al comportamiento básico de macOS, hay que volver a ajustar funciones que el usuario da por sentadas, como menús contextuales, consulta en diccionario, selección, accesibilidad e interacción con texto
Dónde encajan mejor WebKit y Electron
- Si renderizas Markdown con WebKit, hay algunos puntos a cuidar, pero en general funciona bien, ofrece buen rendimiento y tipografía, y también un nivel de control suficiente
- Si haces un proyecto simple con Electron, el trabajo con texto, el renderizado Markdown y una buena tipografía funcionan desde el inicio, y además se obtiene un rendimiento que fue más difícil de conseguir en una implementación pura con TextKit 2
- Electron también ofrece integración con macOS, permite renderizar vistosos Git diff con unas cuantas líneas de código, y existen casos como diffs.com
- Incluso revisando SwiftUI, AppKit, TextKit y WebKit, sigue siendo difícil cumplir bien un requisito tan simple como “un chat con soporte Markdown donde se pueda seleccionar el mensaje completo”
- Queda más claro por qué las nuevas apps donde importan el chat, el texto enriquecido de formato largo y la tipografía flexible terminan yéndose a la web
- SwiftUI es adecuado para pantallas simples sin mucho desplazamiento, y Swift sigue siendo útil en partes donde el rendimiento es importante
- Electron o React Native pueden obtener bastante rendimiento gracias a la interoperabilidad nativa, mientras mantienen un mejor modelo de texto y renderizado
- En el renderizado de texto enriquecido para chats de formato largo, SwiftUI y los SDK nativos de Apple dejan de ser una ventaja y pasan a ser una limitación
- Discusión relacionada: Hacker News, Lobsters
2 comentarios
Comentarios en Hacker News
Hace poco lancé un editor de texto para iOS usando TextKit 2, y el rendimiento sale muy bien incluso con archivos de 5,000 líneas
Lo probé con Moby Dick de Project Gutenberg, lo hice entre agosto de 2025 y abril de 2026, y el desarrollo sigue en marcha
Con cada pulsación de tecla se vuelve a aplicar el estilo en menos de 8 ms, y hasta una ráfaga rápida de 20 pulsaciones se procesa en 150 ms incluyendo el reestilizado completo tras cada entrada, sin debouncing ni renderizado diferido
Las búsquedas por etiquetas y booleanas terminan en menos de 20 ms, y renderizar solo el rango visible es 25 veces más rápido que aplicar estilo a todo el documento, además de soportar refresco de pantalla a 120 Hz
El tamaño del archivo de la app era 722 KB en la versión 1.0, y la 1.1, con más funciones, parece quedar en unos 950 KB
Si este nivel es posible en iOS, en macOS debería ser unas 10 veces más fácil
https://www.gingerbeardman.com/apps/papertrail/
No es que sea “imposible”; más bien entiendo por qué la gente elige tecnologías web en vez de lo nativo para este tipo de cosas. Uno quiere construir el producto, no pelearse con las limitaciones del sistema
Si es un visor de texto, debería manejar al menos archivos dos órdenes de magnitud más grandes. Los archivos JSON de cientos de miles de líneas son comunes, y los CSV y logs suelen ser todavía más largos
Antes normalmente se usaban APIs nativas en lugar de webviews por rendimiento, pero ahora ya no parece necesariamente cierto
Los motores de renderizado de los navegadores están bastante maduros, tienen mucha aceleración por GPU y llevan más de diez años siendo sometidos a pruebas de estrés con aplicaciones web infladas
En cambio, SwiftUI no se siente particularmente rápido. Incluso la Configuración del Sistema que Apple rehizo como lo más moderno, simplificando la UI en filas de casillas, a veces cambia de sección con más tirones que cargar una página web desde us-east-1
He creado apps nativas con Qt C++ y QML, y he demostrado que son mucho más rápidas y usan mucha menos RAM que apps web similares
Así que, en general, las apps web sí son más lentas y consumen más recursos que una app nativa bien diseñada
[1] https://notes.alinpanaitiu.com/SwiftUI%20is%20convenient,%20...
[2] https://x.com/daniel_nguyenx/status/1734495508746702936
[3] https://rubymamistvalove.com/block-editor#8-performance
Yo era desarrollador web, pero en los últimos 6 a 12 meses empecé a hacer apps nativas multiplataforma, y hasta en tareas simples la brecha de rendimiento es bastante clara
Me parece extraño descartar miles de años-persona de optimización y millones de años-persona de validación en condiciones reales para volver a inventar un motor de renderizado de texto peor
En macOS, WebKit es un framework nativo del sistema operativo. Usar WebKit para renderizar Markdown me parece totalmente razonable
Obviamente, renderizarlo todo con WebKit tendría tan poco sentido como renderizarlo todo con PDFKit. Pero para una vista de Markdown, WebKit es una elección lógica, y eso no significa que haya que dar el salto completo a una app web con Chromium
Además, durante mucho tiempo OS X renderizó la UI con DisplayPDF/Quartz
¿WebKit sería hacer trampa porque también existe en otras plataformas? Si ese es el criterio, entonces también se podría usar Java
Si renderizar texto con un renderizador HTML/CSS/JS es “totalmente apropiado”, ¿qué área no lo sería? ¿Por qué no renderizar todo con eso?
No entiendo la lógica que va de “para renderizar texto está bien” a “pero para renderizar todo sería absurdo”
Coincido en que WebKit es un framework nativo del sistema en macOS y que, en ese sentido, es “nativo”
Pero eso también refuerza la idea más amplia de que, para manejar bien texto enriquecido, Markdown, selección, tipografía y contenido largo con formato, las tecnologías web se vuelven rápidamente la única opción realmente práctica
No es que usar WebKit para una vista Markdown esté mal; al contrario, probablemente sea la decisión más razonable. El problema es que aquí la solución “nativa” en la práctica termina siendo una solución de renderizado web
Cada
WKWebViewtrae consigo un motor WebKit con su propio costo de rendimiento y memoria, así que no se puede esparcir por toda la interfaz y tratar como si fuera un componente nativo gratuito de macOSFrustra que para este tipo de UI SwiftUI / AppKit / TextKit no ofrezcan una ruta más limpia, moderna y componible que “simplemente usa WebKit”
Parece absurdo que algo como “permitir seleccionar el mensaje completo en un chat con Markdown” no funcione
En SwiftUI se puede aprovechar un renderizador de Markdown maduro. Basta ver https://github.com/gonzalezreal/swift-markdown-ui y su reemplazo de próxima generación https://github.com/gonzalezreal/textual
Yo los he usado y no tuve problemas. Incluso yo, que tontamente no soy fan de Swift ni de SwiftUI y prefiero Objective-C, lo saqué adelante sin ayuda de LLMs
El scroll de Markdown estático ya completado no pasó una nueva prueba de foco: p95 de 18.86 ms, por encima del presupuesto de 16.7 ms, y máximo de 232.49 ms
La ruta de actualizaciones largas en tiempo real de Markdown/código también falló: p95 de 59.33 ms frente a 16.7 ms, con máximo de 75.94 ms. Es un caso de estrés aparte pero relacionado al manejar superficies grandes de texto enriquecido durante actualizaciones
La expansión de historial largo técnicamente pasa, pero difícilmente se puede llamar fluida: 120 turnos p95 de 21.35 ms, 500 turnos 23.11 ms, 1000 turnos 36.77 ms
No está mal, pero es un poco más lento que mi solución, y la diferencia de rendimiento parece estar relacionada sobre todo con SwiftUI más que con la implementación específica de Textual
Yo usé swift-markdown-ui en una app antes, pero el rendimiento ni se acercaba a wkwebview. Si haces streaming de documentos grandes con elementos complicados como tablas grandes, bloques de código y citas anidadas, hasta puedes ver la pelota de playa; con wkwebview eso no me pasaba
Luego uno se da cuenta de que los navegadores y las tecnologías en las que se apoyan introdujeron un nuevo paradigma de UI, y que los frameworks nativos de UI no lograron mantenerse al día
Lo digo incluso prefiriendo las apps nativas sobre las basadas en web
O muestran el código o mejor se salen. Incluso ahora hay muchísimas apps nativas para Mac/iOS que manejan bien el renderizado Markdown y el texto en streaming
Solo me da curiosidad saber qué excusa hay exactamente
La mayoría terminó asentándose en soportar selección solo dentro de cada bloque continuo y poner un botón de copiar para el mensaje completo
Un dato curioso es que Apple ya hizo esto antes
El antiguo macOS / AppKit usaba WebKit para renderizar texto enriquecido dentro de NSTextField nativo. El texto es un problema difícil
Además, el WebView nativo es muy rápido y ligero, así que no es raro usarlo como motor de maquetación de texto. Incluso usar un WebView separado por cada fila de una tabla puede dar un rendimiento excelente
iMessage para Mac también usaba WebView, y Adium igual. Si estás renderizando texto enriquecido/de marcado, HTML es una herramienta totalmente adecuada
Mac nunca usó WebKit para renderizar NSTextField. Cuando iOS se creó por primera vez, sí usaba WebKit como renderizador de texto de forma bastante general, incluso para controles de UIKit, y a eso le llamaban la “sweet solution”
Pero resultó ser demasiado pesado y engorroso, así que se pasó al enfoque de renderizado de texto al estilo Core Text/AppKit
Descubren que el renderizado complejo de texto nativo es difícil, empiezan a renderizar texto con un enfoque de bajo nivel y luego se quejan de tener que volver a implementar interacciones nativas
Prueban WebKit y funciona muy bien, pero aun así lo descartan para volver a una situación donde tienen que reimplementar interacciones nativas
Personalmente, yo me habría detenido justo en el punto en que WebKit funciona bien
Recuerdo que en 2015, cuando era ingeniero junior, me tocó una tarea de renderizar enlaces clicables dentro de un párrafo en una app de iOS
Swift acababa de salir, así que era todo stack ObjC/UIKit, y fue una auténtica pesadilla. Apenas logré hacerlo funcionar
Como desde más o menos 2016 casi no he tocado iOS, asumí que el nuevo SwiftUI obviamente ya traería esto de fábrica, así que saber que no es así suena bastante loco
https://developer.apple.com/documentation/swiftui/link
A estas alturas no sé cómo podría hacerse más fácil
Que “lo nativo siga siendo tan inmaduro en cuanto sales de pantallas simples” es algo esperable
Si la gente no invierte suficiente esfuerzo, no puedes esperar que eso madure
Como cada vez más esfuerzo se va hacia tecnologías web, la gente queda atada a eso. Ven lo nativo, dicen que “todavía no está lo bastante desarrollado” y luego vuelven a desarrollar más para la web: se repite el ciclo
En el navegador ya “simplemente funciona”, así que casi nadie quiere esforzarse en mejorar lo nativo
Una de las razones por las que la web es mucho más madura es que los grandes fabricantes comerciales de sistemas operativos no quisieron adaptarse a los tiempos. Los toolkits de UI de Windows son un verdadero desastre
En mi app de chat con IA tuve casi exactamente la misma experiencia. Nada funciona bien
El renderizado de Markdown es lento y da tirones, el streaming también es lento y da tirones, y todo termina congelando la UI
Probé al menos 5 componentes de edición de texto populares en GitHub para UIKit y SwiftUI, y todos estaban rotos de una forma u otra, o tenían bugs y eran lentos. Es absurdo
Es un problema difícil. Escribí bastante sobre cómo lo resolví al construir desde cero un editor por bloques con Qt C++ y QML
Tuve problemas parecidos con la selección entre bloques discontinuos, mostrar el Markdown fuente bajo el cursor y tamaños distintos de delegate
Con base en lo que aprendí entonces, ahora estoy construyendo un cliente nativo para LLM con un parser de Markdown en streaming
[1] https://rubymamistvalove.com/block-editor
[2] https://www.get-vox.com
Opiniones de Lobste.rs
Electron es, en esencia, un wrapper alrededor de un WebView, pero como arrastra todo el motor de Chromium, el precio de esa conveniencia es que el tamaño de la app crece demasiado
En 2001~2002 implementé el icónico layout de texto con globos de chat de iChat usando
NSTextViewy todo tipo de trucos, y aun con la ayuda de Hideki Itamura, que era diseñador de texto de AppKit, fue bastante sufrido. Hoy en día con HTML+CSS se volvió bastante simpleParticipé en una app que usaba Tauri, y al cambiarla a Electron para usar Chromium funcionó muchísimo mejor. También importa que apuntaba a un rango muy amplio, especialmente desde win7 hasta win11
En la familia Tauri parece atractivo usar el webview del sistema, pero en Windows eso significa Chrome o Edge, en macOS Safari, y en otros entornos básicamente depender de la suerte. Al final ganaron la previsibilidad y la madurez, y por alguna razón desconocida el rendimiento también fue mejor
Al final quiero mejor software más que satisfacer la gráfica de
htopEl punto central del post no es “todos deberían elegir Electron”, sino que ahora entiendo por qué incluso empresas con recursos y dinero siguen eligiendo Electron o tecnologías web. Al menos para mí, ofrece una buena experiencia de usuario haciendo concesiones razonables donde corresponde
Hay mucha gente que defiende TextKit 2 de Apple u otros frameworks nativos de texto, pero casi no existen editores de texto populares y de alto rendimiento hechos solo con el SDK de Apple. Xcode lo hace bastante bien y probablemente sea el único caso cercano a uso real. Zed, Sublime Text, Visual Studio Code y los IDE de JetBrains usan todos soluciones propias de renderizado de texto por una razón
Entonces, incluso si construyen algo de la peor manera posible, en su propio entorno puede parecer que está bien
Mientras tanto, el resto de la gente, que usa dispositivos con especificaciones mucho más bajas, termina cargando con software inflado y lento
Aunque parece que el autor no exploró esa alternativa hasta ese punto
Visto desde fuera, Flutter parece una respuesta a “¿qué pasa si dejamos solo Skia, el renderizador de Chromium, y lo usamos para apps GUI?”. Debería ser una herramienta multiplataforma con funciones parecidas a Electron, pero más ligera
contentEditable, y que utiliza una subclase deWKWebViewLo irónico es que el motor nativo de texto de Apple usa un modelo de datos mucho mejor que el árbol DOM de HTML: una cadena y atributos de estilo codificados por longitud de ejecución
Editar texto en el DOM es casi una pesadilla, porque muchas veces la selección atraviesa múltiples elementos en varias capas, así que hay que dividir y fusionar todo de formas muy complejas. Cuando probé por primera vez una build de Safari con soporte para
contenteditable, reporté una enorme cantidad de bugs, y aún hoy muchos editores web de texto enriquecido se rompen al cortar o pegar elementos de listaAl final, parece que ocurrió algo parecido al CISC vs RISC de los 90~00. Una arquitectura “inferior” terminó produciendo una implementación mejor porque recibió muchos más recursos