Natif jusqu’au bout, jusqu’à ce qu’on ait besoin de texte
(justsitandgrin.im)- Sur macOS, construire une UI de chat Markdown uniquement avec SwiftUI offre des performances de base correctes, mais il est difficile de prendre en charge la sélection de l’intégralité d’un document
- En migrant vers
NSTextViewet TextKit 2, on perd le travail de tests et d’optimisation réalisé avec SwiftUI, et des pics de CPU apparaissent avec les entrées en streaming - Une réimplémentation avec
NSCollectionViewprovoque des clignotements des cellules, et même TextKit 2 pur, bien que correct côté performances, s’intègre mal avec le streaming - WebKit convient globalement bien pour le rendu Markdown, les performances, la typographie et le niveau de contrôle, et avec Electron, le travail sur le texte fonctionne aussi nativement
- Pour les longues conversations et le texte enrichi, SwiftUI et les SDK natifs d’Apple deviennent une contrainte, tandis qu’une approche web prend l’avantage grâce à son modèle de texte et de rendu
Les limites d’une UI de chat Markdown native sur macOS
- En construisant un chat simple prenant en charge Markdown uniquement avec SwiftUI, on peut obtenir des performances de base acceptables, mais il est impossible de sélectionner l’intégralité d’un document Markdown composé de primitives SwiftUI
- En passant à
NSTextView, on gagne la prise en charge de TextKit 2, mais on perd l’essentiel des tests et du travail d’optimisation effectués dans SwiftUI, et l’intégration avec SwiftUI devient médiocre - Lorsque les réponses du modèle sont injectées en streaming dans
NSTextView, cela provoque des pics de CPU - Même une nouvelle implémentation avec
NSCollectionViewentraîne un clignotement permanent des cellules, un comportement difficile à éviter en raison de la conception même - Un prototype en TextKit 2 pur offre des performances correctes, mais le streaming reste mauvais et l’ensemble s’accorde mal avec les composants modernes
- Même en supprimant complètement SwiftUI pour n’utiliser qu’AppKit, il faut toujours gérer manuellement des fragments de texte qui s’allongent, et la sélection de texte ne devient possible qu’au prix de nombreuses régressions
- Pour atteindre un niveau comparable au comportement standard de macOS, il faut aussi réimplémenter des fonctions que les utilisateurs considèrent comme acquises, comme le menu contextuel, la consultation du dictionnaire, la sélection, l’accessibilité et les interactions avec le texte
Là où WebKit et Electron s’adaptent mieux
- En utilisant WebKit pour rendre du Markdown, il y a quelques points d’attention, mais dans l’ensemble cela fonctionne bien, avec de bonnes performances, une bonne typographie et un niveau de contrôle suffisant
- En créant un projet Electron simple, l’édition de texte, le rendu Markdown et une bonne typographie fonctionnent d’emblée, avec des performances qui se révèlent aussi difficiles à obtenir qu’avec une implémentation TextKit 2 pure
- Electron offre aussi une intégration macOS, permet de rendre un joli diff Git avec quelques lignes de code, et il existe des exemples comme diffs.com
- Même après avoir examiné SwiftUI, AppKit, TextKit et WebKit, il reste difficile de satisfaire correctement une exigence pourtant simple : « un chat prenant en charge Markdown et permettant de sélectionner un message en entier »
- Cela éclaire davantage pourquoi de nouvelles applications, où le chat, le texte enrichi long format et une typographie souple sont importants, choisissent une base web
- SwiftUI convient bien aux écrans simples avec peu de défilement, et Swift reste utile pour les parties où les performances sont cruciales
- Electron ou React Native peuvent obtenir de bonnes performances grâce à l’interopérabilité native tout en conservant un meilleur modèle de texte et de rendu
- Pour le rendu de texte enrichi destiné à des conversations longues, SwiftUI et les SDK natifs d’Apple cessent d’être un avantage et deviennent une contrainte
- Discussion associée : Hacker News, Lobsters
2 commentaires
Réactions sur Hacker News
J’ai récemment lancé un éditeur de texte pour iOS utilisant TextKit 2, avec de très bonnes performances même sur des fichiers de 5 000 lignes
Testé avec Moby Dick du Project Gutenberg, développé entre août 2025 et avril 2026, et le travail continue
À chaque frappe, le restylage se fait en moins de 8 ms, et même une rafale rapide de 20 frappes est traitée en 150 ms, restylage complet après chaque frappe inclus, sans debouncing ni rendu différé
Les tags et la recherche booléenne se terminent en moins de 20 ms, et le rendu de la seule zone visible est 25 fois plus rapide que le stylage de tout le document, avec prise en charge d’un rafraîchissement à 120 Hz
La taille du binaire de l’app était de 722 KB en 1.0, et la 1.1, avec plus de fonctionnalités, semble faire environ 950 KB
Si c’est possible à ce niveau sur iOS, cela devrait être environ 10 fois plus facile sur macOS
https://www.gingerbeardman.com/apps/papertrail/
Ce n’est pas que ce soit « impossible », mais ça aide à comprendre pourquoi les gens choisissent les technologies web plutôt que le natif pour ce genre de chose. Ils veulent construire un produit, pas se battre contre les limites du système
Pour un visualiseur de texte, il faut au minimum pouvoir gérer des fichiers d’un ordre de grandeur supérieur. Les fichiers JSON de plusieurs centaines de milliers de lignes sont courants, et les CSV comme les logs sont encore plus longs
En général, on utilisait des API natives plutôt qu’une WebView pour des raisons de performances, mais ce n’est plus forcément vrai aujourd’hui
Les moteurs de rendu des navigateurs sont très mûrs, largement accélérés par le GPU, et ont subi plus de dix ans de stress tests avec des apps web énormes
À l’inverse, SwiftUI ne donne pas vraiment une impression de rapidité. Même Réglages système, qu’Apple a reconstruit en version moderne en simplifiant l’UI autour de rangées de cases à cocher, peut parfois saccader davantage qu’une page web chargée depuis us-east-1
J’ai construit des apps natives en Qt C++ et QML, et j’ai montré qu’elles étaient bien plus rapides et consommaient bien moins de RAM que des apps web comparables
Donc en règle générale, une app web est plus lente et plus gourmande en ressources qu’une app native bien conçue
[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
J’étais développeur web à l’origine, mais depuis 6 à 12 mois je construis des apps natives multiplateformes, et même sur des tâches simples l’écart de performances est assez net
Il est étrange de rejeter des milliers d’années-homme d’optimisation et des millions d’années-homme de validation sur le terrain pour réinventer un moteur de rendu de texte moins bon
Sur macOS, WebKit est un framework natif de l’OS. Utiliser WebKit pour rendre du Markdown paraît tout à fait approprié
Évidemment, rendre absolument tout avec WebKit aurait autant de sens que tout rendre avec PDFKit. Mais pour une vue Markdown, WebKit est un choix logique, sans pour autant basculer dans une app web Chromium qui remplace tout
Et OS X a longtemps rendu son UI avec DisplayPDF/Quartz
WebKit existe aussi sur d’autres plateformes, donc ce serait de la triche ? Dans ce cas, on pourrait tout aussi bien utiliser Java
Si rendre du texte avec un moteur HTML/CSS/JS est « tout à fait approprié », alors quel domaine ne l’est pas ? Pourquoi ne pas tout rendre ainsi ?
Je ne comprends pas la logique qui mène de « le rendu de texte, c’est approprié » à « mais tout rendre ainsi, ce serait absurde »
Je suis d’accord sur le fait que WebKit est un framework natif de macOS et qu’en ce sens c’est bien du « natif »
Mais cela renforce aussi l’idée plus large selon laquelle, dès qu’il s’agit de bien gérer du texte enrichi, du Markdown, la sélection, la typographie ou du contenu long format mis en forme, les technologies web deviennent rapidement la seule option réellement pratique
Ce n’est pas que WebKit soit un mauvais choix pour une vue Markdown, au contraire, c’est probablement le plus rationnel. Le problème, c’est qu’ici la solution « native » est en fait une solution de rendu web
Chaque
WKWebViewembarque son propre moteur WebKit, avec son coût en performances et en mémoire, donc on ne peut pas en parsemer partout en les traitant comme des composants natifs macOS gratuitsCe qui est frustrant, c’est que SwiftUI / AppKit / TextKit n’offrent pas, pour ce type d’UI, une voie propre, moderne et composable meilleure que « utilise simplement WebKit »
Le fait de ne même pas pouvoir faire quelque chose d’aussi basique que « permettre de sélectionner l’intégralité d’un message dans un chat avec Markdown » semble absurde
SwiftUI permet d’utiliser des renderers Markdown mûrs. Il suffit de regarder https://github.com/gonzalezreal/swift-markdown-ui et son remplaçant de nouvelle génération https://github.com/gonzalezreal/textual
Je les ai utilisés moi-même et ça marchait sans problème. Même moi, idiot qui n’aime ni Swift ni SwiftUI et préfère Objective-C, j’y suis arrivé sans aide de LLM
Le scroll d’un Markdown statique terminé n’a pas passé le nouveau test de focalisation, avec un p95 à 18,86 ms au-dessus du budget de 16,7 ms, et un maximum à 232,49 ms
Le scénario de longues mises à jour Markdown/code en temps réel a aussi échoué, avec p95 à 59,33 ms contre 16,7 ms, et un max à 75,94 ms. C’est un cas de stress distinct mais lié, qui consiste à manipuler de grandes surfaces de texte enrichi pendant les mises à jour
L’extension d’un long historique passe techniquement, mais difficile de parler d’images fluides : 120 tours p95 à 21,35 ms, 500 tours à 23,11 ms, 1000 tours à 36,77 ms
Ce n’est pas mauvais, mais c’est légèrement plus lent que ma solution, avec un écart de performances similaire qui semble surtout lié à SwiftUI plutôt qu’à l’implémentation de Textual
J’ai déjà utilisé swift-markdown-ui dans une app, mais côté performances ce n’était même pas proche de wkwebview. Si on fait du streaming sur de gros documents avec des éléments compliqués comme de grands tableaux, des blocs de code ou des citations imbriquées, on peut même finir avec le beachball, ce qui ne m’est jamais arrivé avec wkwebview
control/option Cne copie pasPuis on se rend compte que le navigateur et ses technologies sous-jacentes ont introduit un nouveau paradigme pour l’UI, que les frameworks UI natifs n’ont pas réussi à suivre
Même en préférant les apps natives aux apps web, c’est l’impression que cela donne
Montrez le code, sinon il faut arrêter là. Il existe déjà énormément d’apps Mac/iOS natives qui gèrent très bien le rendu Markdown et le texte en streaming
J’aimerais juste savoir quelle excuse est avancée ici
La plupart des gens ont fini par se limiter à la sélection à l’intérieur de chaque bloc continu, avec un bouton de copie pour l’ensemble du message
Ce qui est amusant, c’est qu’Apple faisait déjà ce genre de chose autrefois
Les anciennes versions de macOS / AppKit utilisaient WebKit pour rendre le texte enrichi dans les NSTextField natifs. Le texte est un problème difficile
Et puis la WebView native est très rapide et légère, donc l’utiliser comme moteur de mise en page du texte n’a rien d’étrange. On peut même avoir d’excellentes performances avec une WebView distincte pour chaque ligne d’un tableau
iMessage sur Mac utilisait aussi une WebView, tout comme Adium. Si on rend du texte riche / balisé, HTML est un outil totalement approprié
Le Mac n’a jamais utilisé WebKit pour le rendu des NSTextField. Lors de la création initiale d’iOS, WebKit servait largement de moteur de rendu de texte, y compris pour les contrôles UIKit, et cela était présenté comme une « sweet solution »
Mais cela s’est révélé trop lourd et trop contraignant, ce qui a conduit à l’adoption d’une approche de rendu de texte à la Core Text/AppKit
Il découvre que le rendu de texte natif complexe est difficile, tente une approche bas niveau, puis se plaint de devoir réimplémenter les interactions natives
Il essaie WebKit, constate que ça marche très bien, puis abandonne pour revenir à une situation où il faut à nouveau réimplémenter les interactions natives
Personnellement, je me serais arrêté au moment où WebKit fonctionnait bien
Je me souviens qu’en 2015, quand j’étais ingénieur junior, on m’avait demandé de rendre des liens cliquables dans des paragraphes d’une app iOS
Swift venait juste de sortir, donc c’était une stack entièrement ObjC/UIKit, et c’était un vrai cauchemar. J’avais fini par le faire marcher à peu près
Comme je n’ai presque plus touché à iOS depuis 2016, j’imaginais naturellement que le nouveau SwiftUI intégrerait ce genre de chose de base, donc découvrir que non, c’est assez dingue
https://developer.apple.com/documentation/swiftui/link
À ce stade, je ne vois pas comment on pourrait faire plus simple
Il est normal qu’en sortant des écrans simples, le natif paraisse encore aussi immature
Si les gens n’y investissent pas suffisamment d’efforts, on ne peut pas s’attendre à ce que ça mûrisse
Comme plus d’efforts vont vers les technologies web, les gens s’y retrouvent enfermés. Ils regardent le natif, disent qu’il n’est « pas assez avancé », puis retournent faire encore plus de développement web, et le cycle se répète
Dans le navigateur, comme « ça marche tout simplement », presque plus personne n’a envie de faire l’effort d’améliorer le natif
Si le web est bien plus mûr, c’est notamment parce que les grands fabricants d’OS commerciaux n’ont pas voulu suivre leur époque. Les toolkits UI sous Windows sont vraiment affreux
J’ai eu presque exactement la même expérience dans mon app de chat IA. Rien ne fonctionne correctement
Le rendu Markdown est lent et saccadé, le streaming est lent et saccadé, et tout finit par bloquer l’UI
J’ai essayé au moins cinq composants d’édition de texte populaires sur GitHub pour UIKit et SwiftUI, et tous étaient cassés d’une façon ou d’une autre, buggés et lents. C’est absurde
C’est un problème difficile. J’ai écrit longuement sur la façon dont je l’ai abordé en construisant un éditeur par blocs de zéro avec Qt C++ et QML
J’ai rencontré des problèmes similaires : sélection à travers des blocs discontinus, affichage du Markdown source sous le curseur, tailles de delegates différentes
En m’appuyant sur ce que j’ai appris alors, je construis maintenant un client LLM natif avec parseur Markdown en streaming
[1] https://rubymamistvalove.com/block-editor
[2] https://www.get-vox.com
Commentaires sur Lobste.rs
Electron n’est au fond qu’un wrapper autour d’une WebView, mais comme il embarque tout le moteur Chromium, la contrepartie de cette commodité est une taille d’application beaucoup trop importante
En 2001~2002, j’avais implémenté la fameuse mise en page en bulles de chat d’iChat avec
NSTextViewet toutes sortes de bricolages ; même avec l’aide de Hideki Itamura, qui concevait le système de texte d’AppKit, ça avait été assez pénible. Aujourd’hui, c’est devenu assez simple avec HTML+CSSJ’ai travaillé sur une application qui utilisait Tauri, et une fois passée à Electron avec Chromium, elle fonctionnait bien mieux. Le fait de viser une plage très large, de win7 à win11, comptait aussi beaucoup
Les outils de la famille Tauri paraissent séduisants parce qu’ils utilisent la webview du système, mais sur Windows cela veut dire Chrome ou Edge, sur macOS Safari, et ailleurs c’est un peu la loterie. Au final, la prévisibilité et la maturité l’ont emporté, et pour une raison inconnue les performances étaient aussi meilleures
Au bout du compte, on veut surtout de meilleurs logiciels plutôt que de satisfaire les graphiques de
htopL’idée centrale du billet n’est pas de dire « tout le monde devrait choisir Electron », mais que je comprends désormais pourquoi même des entreprises qui ont des ressources et de l’argent continuent de choisir Electron ou les technologies web. Au moins de mon point de vue, cela permet de faire les bons compromis aux bons endroits tout en offrant une bonne expérience utilisateur
Beaucoup défendent TextKit 2 d’Apple ou d’autres frameworks de texte natifs, mais il n’existe pratiquement aucun éditeur de texte populaire, performant et construit uniquement avec les SDK Apple. Xcode s’en sort plutôt bien et est probablement le seul cas proche d’un usage réel à grande échelle. Zed, Sublime Text, Visual Studio Code et les IDE JetBrains utilisent tous leur propre solution de rendu de texte, et ce n’est pas pour rien
Du coup, même quelque chose conçu de la pire manière peut leur sembler acceptable dans leur propre environnement
Pendant ce temps, tous les autres, avec des appareils bien moins puissants, continuent de subir des logiciels lourds et lents
Cela dit, l’auteur n’a pas l’air d’avoir exploré cette piste jusqu’à ce niveau
Vu de l’extérieur, Flutter ressemble à une réponse à la question : « et si on gardait seulement Skia, le moteur de rendu de Chromium, pour en faire un outil d’applications GUI ? » Cela devrait être un outil multiplateforme plus léger qu’Electron tout en offrant des fonctionnalités similaires
contentEditable, et qu’il emploie une sous-classe deWKWebViewCe qui est ironique, c’est que le moteur de texte natif d’Apple utilise un modèle de données bien meilleur que l’arbre DOM HTML, à savoir une chaîne de caractères et des attributs de style encodés par plages d’exécution
Éditer du texte dans le DOM est presque un cauchemar, car la sélection traverse souvent plusieurs éléments sur plusieurs niveaux, ce qui oblige à faire des découpages et des fusions très complexes. Quand j’ai mis la main sur les premiers builds de Safari avec prise en charge de
contenteditable, j’ai envoyé énormément de rapports de bugs, et encore aujourd’hui beaucoup d’éditeurs de texte enrichi sur le web se cassent lorsqu’on coupe ou colle des éléments de listeAu final, on dirait qu’il s’est produit quelque chose d’analogue au débat CISC contre RISC des années 90~2000. Une architecture « inférieure » a reçu davantage de ressources et a fini par produire une implémentation supérieure