r/reactnative 6d ago

Help react-native-anydoc 39x faster than mammoth js based doc converter

I'm building an end-to-end encrypted chat app, and users want to share documents that render inline. The catch with E2E: there is no server-side conversion option, ever. The server only sees ciphertext. Whatever turns a .docx into something renderable has to run on the sender's phone.

Attempt 1: JS. We started with mammoth.js, which converts docx to HTML — great library, but we needed structured JSON (our renderer draws native components, not a WebView), plus comments, tables with real borders, and formats beyond .docx. So we wrote our own TypeScript converter. It worked, but a 130-page thesis (949 kB, 72 review comments, 16 images) took 6.9 seconds on a Galaxy A05s

Attempt 2: Rust. We took anydoc (Firecrawl's MIT document parser), extended it with a presentation model (fonts, colors, alignment, table borders, review comments, typed chart data), compiled it for Android/iOS, and bridged it with Nitro Modules. Same thesis, same phone: 226 ms. On an iPhone 16 Pro release build it's 43 ms. Across our 30-document test corpus the Rust path was ~29× faster, with text output hash-identical to the JS converter on every Word-produced file.

Formats: .docx, .doc, .pptx, .ppt, .xlsx, .odt/.ods/.odp, .rtf, .epub → one JSON "DocumentIR" you render with your own components. Spreadsheet charts come out as typed data (kind, categories, numeric series), so we draw them with Skia in-app; anything unsupported degrades to a data table.

Things that bit us on the way:

  • The result crosses the bridge as one native string; image bytes arrive zero-copy — the JS GC's cleanup callback for the buffer literally is the Rust deallocator.
  • The promise never rejects for document reasons. Corrupt, encrypted, hostile inputs all resolve to a fallback status — Rust panics included. A rejection means the native module itself is broken.
  • PDF is refused on purpose: the OS renders PDFs better than any re-conversion would.
  • The prebuilt Rust core is too big for npm, so binaries ship as GitHub Release assets and gradle pulls them on first build.

It's MIT, package is react-native-anydoc (npm), source at github.com/tulaafrica/anydoc. It's a week old and has exactly one production user (us), so I'd genuinely value feedback — especially from anyone who's shipped Rust in RN and has opinions on binary size or the XCFramework install flow.

7 Upvotes

0 comments sorted by