One of the big challenges on the T3 Chat mobile app is rendering Markdown performantly. We want everything in T3 Chat to be rendered buttery smooth, and Markdown is the format that essentially every LLM uses to communicate.
It's not just rendering a single Markdown instance, either. This is a chat app, so it's a list (potentially very long list) with potentially really long LLM messages full of GFM (Github-flavored markdown).
Using Remark (via react-native-remark) is unfortunately really slow in this scenario. Remark is a good JS-only library, but this just pushes its capabilities beyond what it can do.
In our tests, long complex Markdown messages cause the UI to drop frames ("jank") -- often many frames. You can see in the screenshot of our custom in-app profiler that the Remark test was at 185 ms for a single Markdown render, which would drop 11 frames. Not all of that was Remark itself, but it would be hard to optimize to a reasonable level.
We tried writing a highly optimized Remark AST to React Native component renderer. (That's the "Fast" column in the screenshot.) Still fully JS, but with a lot of care put into making it as fast as possible. It was more than 2X (sometimes drastically more) as fast. But we were still dropping frames.
I've long said that in targeted situations, if you can't achieve the performance you need with React Native and JS, you should drop into native and let RN orchestrate the result rather than struggling to squeeze more perf out of it or worse yet giving up and shipping something that doesn't perform well.
So it was time to move to native code. We integrated a native Markdown parser (written in C) and wrote a custom Expo Module that runs the parser and then renders iOS and Android native UI components using the resulting AST. It's all orchestrated by React Native and its layout engine Yoga.
With this combination, even the most lengthy, complex Markdown components render an order of magnitude faster and in the vast majority of cases, we aren't dropping a single frame. Something like 11X faster than the Remark implementation. We're literally getting to the point where the native UI components have become the bottleneck.
I don't want to oversell it, but this is pretty exciting. We have more testing to do and we need to make sure that the long-term maintainability of this native C library and the custom Expo Module is sustainable, but I thought I'd share some of the hard work being done by the team. I'm pretty pumped about this in particular!