Support React Native - #118
Conversation
|
Woah nice! There are a lot of people who are interested in doing stuff like this! Looking forward to reviewing this when you're ready! cc @pcuenca |
|
I'm investigating a performance issue with Whisper tiny.en, and it looks like the performance is not as expected in the example. I quickly add log for # Encode result
LOG ONNX session run finished 767 ms
# Decode result
LOG ONNX session run finished 4518 ms
# ... 4 runs ...
LOG ONNX session run finished 4856 ms
LOG Time: 40016
LOG Result: {"text": " (buzzing)"}Click to expandconst t0 = performance.now()
// this.#inferenceSession === NativeModules.Onnxruntime
const results: Binding.ReturnType = await this.#inferenceSession.run(this.#key, input, outputNames, options);
const output = this.decodeReturnType(results);
console.log('ONNX session run finished', performance.now() - t0)Also see logs of native part (added log to OnnxruntimeModule.java), it is significantly less than the time taken by JS part: # Encode result
09:47:59.203 ONNXRUNTIME_RN run() is finished, time: 273 ms
# Decode result
09:48:00.280 ONNXRUNTIME_RN run() is finished, time: 339 ms
# ... 4 runs ...
09:48:23.807 ONNXRUNTIME_RN run() is finished, time: 541 ms
EDIT: It seems the logger have some bugs leads me to think that the problem is from the native bridge. I add timeout await to the decodeReturnType call and found the issue is from this function. |
|
@TowhidKashem same as the fugood one, |
This should fixed. |
the 3.6.1-beta.1 release works for my app, thanks! |
|
Just curious, is this work integrated in the latest release (I see the PR is still open) or is this PR left hanging? |
|
@jhen0409 @kungfooman could one of you kindly merge this, sorry for the ping |
Does any of you could help on how they got to make it work on Expo? Im a newbie on mobile development and it seems to be impossible but saw you guys achieved it hahaha |
As far as I know, this tutorial may also works with Expo. And you need run local dev. |
Conflict resolutions: - package.json: take upstream version 4.1.0, merge RN deps (native-universal-fs, onnxruntime-react-native) with upstream's updated onnxruntime-web 1.26.0-dev - audio.js: keep read_audio as primary (RN convention), add load_audio alias for upstream API compat; remove duplicate JSDoc and stale deprecated alias referencing non-existent load_audio Also fixed: - audio.js: add missing `apis` import from env.js (used in save()) - audio.js: remove unused `fs` import - hub.js: use env.fetch consistently instead of bare fetch in RN path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Metro/RN bundler aliases path -> path-browserify at runtime; direct import of path-browserify is not needed and breaks the alias pattern. Use node:path (marked external in RN build, Metro resolves it). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ecated alias Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The 4.0.0-next.8 upstream merge (04faed2) dropped several React Native code paths, and 4.1.0-beta.0 shipped without them. In a real RN environment (navigator.product === 'ReactNative', and no process.release, so IS_NODE_ENV is false) loading any model threw: getCoreModelFile() -> "Cannot return path in a browser environment." ...with a progress_callback -> "Cannot read properties of null (reading 'getReader')" utils/model-loader.js asks getModelFile() for a path whenever IS_NODE_ENV || IS_REACT_NATIVE_ENV, but the three matching checks in utils/hub.js had been narrowed back to IS_NODE_ENV alone. They now share a single CAN_RETURN_PATH constant so they cannot drift apart again. Also fixed or restored: - readResponse() copes with a FileResponse that has no body stream. RN resolves file metadata up front and defers reading until the bytes are asked for, so the read happens there rather than eagerly in FileResponse.create(). - Local paths are handed back as file:// URIs on RN, matching how native-universal-fs is addressed everywhere else. - package.json exports listed "react-native" after "default". "default" always matches, so the condition was unreachable and React Native resolved to the web/node bundle instead of transformers.native.mjs. - fetchBinary(): RN's fetch is text-oriented and corrupts binary payloads, so requests go through XMLHttpRequest with responseType='arraybuffer'. - downloadFile(): model weights stream straight to disk through native-universal-fs rather than being buffered in the JS heap, which exhausts it on device. - FileCache.put() read response.body on RN, but whatwg-fetch responses expose no body stream, so nothing was ever written to the cache -- not even small config files. None of the RN branches had test coverage: native-universal-fs was mapped to node:fs/promises, which has no exists()/moveFile()/DocumentDirectoryPath, so they could not run under test. It now maps to a mock backed by the real filesystem, and tests/react_native.test.js exercises these paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- onnx.js: change RN defaultDevices from ['xnnpack', 'cpu'] to ['cpu'] xnnpack implementation is incomplete; aligns with Node.js behavior - env.js + FileCache.js: replace direct path-browserify import with node:path; Metro/RN bundler aliases path -> path-browserify at runtime - audio.js: add missing load_audio alias (required by transformers.js exports) - build/constants.mjs: add native-universal-fs, onnxruntime-react-native, buffer to web/node ignore lists; add buffer/native-universal-fs to RN external modules so Metro handles them - ignoreModulesPlugin.mjs: add buffer case to export Buffer from globalThis Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add aliasPlugin that rewrites node:path/path → path-browserify at build time, so RN consumers don't need to configure Metro aliases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… cast, configs subfolder type, revision default Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Deviations from upstream should only exist where React Native needs them.
These three did not:
- audio.js: RawAudio.save() had its own React Native branch writing through
native-universal-fs, but io.js's saveBlob() -- the function it delegates to
everywhere else -- already does exactly that. The duplicate pulled Buffer,
NativeFS and apis into a module that otherwise needs none of them. Dropping
it takes audio.js back to being byte-identical with upstream, RN included,
and tests/react_native.test.js now pins saveBlob's native path so the
duplicate does not come back.
- FileResponse.js: inserting create() consumed clone()'s doc comment.
- FileCache.js: match() had been restyled into a ternary; upstream's if/else
is back, so the only difference left is the RN branch itself.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Make it support React Native.
And I made a example for it.
https://github.com/hans00/react-native-transformers-example
Guide to get it start
TODO:
Check models are works fineResearch more efficiently image processing