onnxruntime/js
Yulong Wang 036fcd93d4
[js/web] optimize module export and deployment (#20165)
### Description

This PR make numbers of optimizations to onnxruntime-web's module export
and deployment.

See each section below for more details.

#### Preview

>
[onnxruntime-web@1.19.0-esmtest.20240513-a16cd2bd21](https://www.npmjs.com/package/onnxruntime-web/v/1.19.0-esmtest.20240513-a16cd2bd21)

> ~~onnxruntime-web@1.19.0-esmtest.20240430-c7edbcc63d~~

> ~~onnxruntime-web@1.18.0-esmtest.20240428-624c681c83~~

> ~~onnxruntime-web@1.18.0-esmtest.20240411-1abb64e894~~

<details>
<summary><h4>Breaking changes</h4></summary>

There is no code change required, but there are a few differences
regarding **code import**, **flags**, **bundler config** and
**deployment steps**.

#### Importing:

Import table is changed. See following for details.

<details>
<summary><h5>Current import table:</h5></summary>

| Target Name | Path for "import" or "require" | WebGL | JSEP | wasm |
Proxy | Training |
  |------|-----|-----|-----|-----|-----|-----|
  | `ort` (default) | `onnxruntime-web` | ✔️ |  | ✔️ | ✔️ |  |
  | `ort.all` | `onnxruntime-web/experimental` | ✔️ | ✔️ | ✔️ | ✔️ |  |
  | `ort.node` | `onnxruntime-web` |  |  | ✔️ |  |  |
| `ort.training` | `onnxruntime-web/training` |  |  | ✔️ |
✔️<sup>\[1]</sup> | ✔️ |
  | `ort.wasm` | `onnxruntime-web/wasm` |  |  | ✔️ | ✔️ |  |
  | `ort.wasm-core` | `onnxruntime-web/wasm-core` |  |  | ✔️ |  |  |
| `ort.webgl` | `onnxruntime-web/webgl` | ✔️ |  |  | ✔️<sup>\[2]</sup>
|  |
  | `ort.webgpu` | `onnxruntime-web/webgpu` |  | ✔️ | ✔️ | ✔️ |  |

* [1] didn't test. may not actually work.
* [2] not working. this is a mistake in build config.

</details>

<details>
<summary><h5>Proposed update:</h5></summary>

| Target Name | Path for "import" or "require" | WebGL | JSEP | wasm |
Proxy | Training |
  |------|-----|-----|-----|-----|-----|-----|
  | `ort` (default) | `onnxruntime-web` | ✔️ |  | ✔️ | ✔️ |  |
| `ort.all` |
~~`onnxruntime-web/experimental`~~<br/>`onnxruntime-web/all` | ✔️ | ✔️ |
✔️ | ✔️ |  |
  | `ort.node` | `onnxruntime-web` |  |  | ✔️ |  |  |
  | `ort.training` | `onnxruntime-web/training` |  |  | ✔️ | ✔️ | ✔️ |
  | `ort.wasm` | `onnxruntime-web/wasm` |  |  | ✔️ | ✔️ |  |
| ~~`ort.wasm-core`~~ | ~~`onnxruntime-web/wasm-core`~~ | ~~~~ | ~~~~
| ~~✔️~~ | ~~~~ | ~~~~ |
  | `ort.webgl` | `onnxruntime-web/webgl` | ✔️ |  |  | ~~✔️~~  |  |
  | `ort.webgpu` | `onnxruntime-web/webgpu` |  | ✔️ | ✔️ | ✔️ |  |

</details>

#### Flags:

The following flags are deprecated:
- `env.wasm.simd` (boolean): will be ignored. SIMD is always enabled in
build.

The following flags changed their type:
- `env.wasm.wasmPaths`: When using this flag as a string ( for the URL
prefix ), nothing is changed. When using this flag as an object ( for
per-file path override ), the type changed:
  ```diff
  -  export interface Old_WasmFilePaths{
  -    'ort-wasm.wasm'?: string;
  -    'ort-wasm-threaded.wasm'?: string;
  -    'ort-wasm-simd.wasm'?: string;
  -    'ort-training-wasm-simd.wasm'?: string;
  -    'ort-wasm-simd-threaded.wasm'?: string;
  -  };
  +  export interface New_WasmFilePaths {
  +    /**
  +     * Specify the override path for the main .wasm file.
  +     *
  +     * This path should be an absolute path.
  +     *
  +     * If not modified, the filename of the .wasm file is:
  +     * - `ort-wasm-simd-threaded.wasm` for default build
+ * - `ort-wasm-simd-threaded.jsep.wasm` for JSEP build (with WebGPU and
WebNN)
  +     * - `ort-training-wasm-simd-threaded.wasm` for training build
  +     */
  +    wasm?: URL|string;
  +    /**
  +     * Specify the override path for the main .mjs file.
  +     *
  +     * This path should be an absolute path.
  +     *
  +     * If not modified, the filename of the .mjs file is:
  +     * - `ort-wasm-simd-threaded.mjs` for default build
+ * - `ort-wasm-simd-threaded.jsep.mjs` for JSEP build (with WebGPU and
WebNN)
  +     * - `ort-training-wasm-simd-threaded.mjs` for training build
  +     */
  +    mjs?: URL|string;
  +  }
  ```

#### Bundler compatibility:

Config changes are need for bundlers. See usage example in
/js/web/test/e2e/ for Webpack, parcel and rollup.

#### Deployment:

- if consuming from a CDN, there is no breaking change.
- if consuming from a local server, need to copy all `ort-*.wasm` and
`ort-*.mjs` files (totally 6 files) in the dist folder. (previously only
need to copy `ort-*.wasm` files.)

</details>
<details>
<summary><h4>Problems</h4></summary>

There are a few problems with the current module export and deployment:

- Script URL cannot be correctly inferred when imported as ESM.
- Workers are forcefully encoded using Blob URL, which makes
onnxruntime-web not working in CSP environment and Node.js, when using
proxy or multi-threading feature.
- Generated JS code (by Emscripten) is encoded using
`function.toString()`, which is unstable and error-prone.
- When running with a different Emscripten build, always need the build
step. Making it difficult to swap artifacts in deveopment/debug.
</details>
<details>
<summary><h4>Goals</h4></summary>

- Full ESM support
- Support variances of ways to import. Including:
- import from HTML's `<script>` tag (IIFE format, exporting to global
variable `ort`)
    ```html
<script
src="https://example.com/cdn-path-to-onnxruntime-web/dist/ort.min.js"></script>
    ```
  - import from source code inside `<script type="module">` tag (ESM)
    ```html
    <script type="module">
import * as ort from
"https://example.com/cdn-path-to-onnxruntime-web/dist/ort.min.mjs";

      // using 'ort'
    </script>
    ```
- import in a CommonJS project (CJS format, resolve from package.json
"exports" field)
    ```js
    // myProject/main.js
    const ort = require('onnxruntime-web');
    ```
- import in an ESM project (ESM format, resolve from package.json
"exports" field)
    ```js
    // myProject/main.js (or main.mjs)
    import * as ort from 'onnxruntime-web';
    ```
- Support popular bundlers when importing onnxruntime-web into a CJS/ESM
project.
  - webpack (esm requires extra post-process step)
  - rollup
  - parcel (esm requires extra post-process step)
  - More bundlers **TBD**
- Multi-threading support for Node.js

NOTE: keeping single JavaScript file (the all-in-one bundle) is no
longer a goal. This is because technically there is a conflict with the
other requirements.
</details>

<details>
<summary><h4>Important Design Decisions</h4></summary>

- Drop support of single JavaScript output.
- The current onnxruntime-web distribution uses a single JavaScript file
to include all code. While there are a few benefits, it also creates
problems as mentioned above. Since ESM is being used more and more
widely, and browsers are making more restricted security checks and
requirement, the old Blob based solution is going to be replaced.
- To achieve the requirement, specifically, the CSP environment support,
we have to offer a non Blob based solution. Therefore, we have to
distribute multiple files and drop the single file solution.

- Do not run parser/postprocess on Emscripten generated JavaScript.
- Emscripten is evolving quickly so we should only depends on what's in
its documentation instead of a certain implementation details. (for
example, currently we patch on its code to deal with a special variable
`_scriptDir`)
  - Keep the generated files as-is also helps to:
    - reduce the size of ort.min.js
- make it easier to replace build artifacts when in development/debug

- Drop support for non-SIMD and non-MultiThread. This helps to reduce
the number of artifacts in distribution.
  - (fixed-sized) SIMD is supported in any mainstream JS environment.
- Multi-thread as WebAssembly feature is supported in any mainstream JS
environment. In some environment the feature is guarded with cross
origin policy, but it can still work if not trying to create any worker.

- Use ESM output for Emscripten generated JavaScript.
- There are 2 ways to dynamically import classic (umd) modules and
neither of them are recommended:
- dynamically creating a <script> tag. This changes the HTML structure
and have quite a lot of compatibility issue
- use `fetch()` and `eval()`. However `eval` is strongly suggested to be
avoid because there is a great perf hit.
- importing ESM is super easy - just use the `import()` call.
Considering ESM is widely supported in modern browsers and Node.js this
is the better option.

- Add Blob based solution as a fallback for cross-origin workers.
- There are still wide use case of importing onnxruntime-web from CDN.
In this usage, make it able create worker by using `fetch()`+`Blob` to
create a same-origin Blob URL.

</details>

<details>
<summary><h4>Distribution File Manifest</h4></summary>

The distribution folder contains the following files:

- WebAssembly artifacts. These files are the result of compiling the
ONNX Runtime C++ code to WebAssembly by Emscripten.

  | File Name | Build Flags |
  |------|-----|
| ort-wasm-simd-threaded.mjs <br/> ort-wasm-simd-threaded.wasm |
`--enable_wasm_simd` <br/> `--enable_wasm_threads` |
| ort-training-wasm-simd-threaded.mjs <br/>
ort-training-wasm-simd-threaded.wasm | `--enable_training_apis` <br/>
`--enable_wasm_simd` <br/> `--enable_wasm_threads` |
| ort-wasm-simd-threaded.jsep.mjs <br/> ort-wasm-simd-threaded.jsep.wasm
| `--enable_wasm_simd` <br/> `--enable_wasm_threads` <br/> `--use_jsep`
<br/> `--use_webnn` |

- onnxruntime-web JavaScript artifacts. These files are generated by
ESBuild as the entry point for onnxruntime-web.

  There are multiple build targets for different use cases:
  | Target Name | Path for "import" or "require" | Description |
  |------|-----|-----|
  | `ort` | `onnxruntime-web` | The default target. |
  | `ort.all` | `onnxruntime-web/all` | The target including webgl. |
  | `ort.node` | `onnxruntime-web` | The default target for Node.js. |
| `ort.training` | `onnxruntime-web/training` | The target including
training APIs |
| `ort.wasm` | `onnxruntime-web/wasm` | The target including only
WebAssembly (CPU) EP |
| `ort.webgl` | `onnxruntime-web/webgl` | The target including only
WebGL EP |


  For each target, there are multiple files generated:
  | File Name | Description |
  |------|-----|
| [target].js | The entry point for the target. IIFE and CommonJS
format. |
  | [target].mjs | The entry point for the target. ESM format. |
| [target].min.js <br/> [target].min.js.map | The entry point for the
target. Minimized with sourcemap. IIFE and CommonJS format. |
| [target].min.mjs <br/> [target].min.mjs.map | The entry point for the
target. Minimized with sourcemap. ESM format. |
| [target].proxy.mjs | (if appliable) The proxy ESM module for the
target. |
| [target].proxy.min.mjs <br/> [target].proxy.min.mjs.map | (if
appliable) The proxy ESM module for the target. Minimized with
sourcemap. |

</details>

<details>
<summary><h4>Dynamic Import Explained</h4></summary>

- Local Served | No Proxy:
  ```
  [Bundle or ort.min.js]
    |
    + import()--> [ort-wasm-simd-threaded.mjs]
                    |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
                    |
+ new Worker()--> [ort-wasm-simd-threaded.mjs (worker)]
                                        |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
  ```
- Local Served | Proxy:
  ```
  [Bundle or ort.min.js]
    |
    + import()--> [ort.proxy.min.mjs]
                    |
                    + new Worker()--> [ort.proxy.min.mjs (worker)]
                                        |
+ import()--> [ort-wasm-simd-threaded.mjs]
                                                        |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
                                                        |
+ new Worker()--> [ort-wasm-simd-threaded.mjs (worker)]
|
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
  ```
- Cross Origin | No Proxy:
  ```
  [Bundle or ort.min.js]
    |
    + fetch('ort-wasm-simd-threaded.mjs')
        |
        + URL.createObjectURL(res.blob())
        |
        + import()--> [blob:... (ort-wasm-simd-threaded)]
                        |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
                        |
+ new Worker()--> [blob:... (ort-wasm-simd-threaded) (worker)]
                                            |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
  ```

- Cross Origin | Proxy
  ```
  [Bundle or ort.min.js]
    |
    + fetch('ort.proxy.min.mjs')
        |
        + URL.createObjectURL(res.blob())
        |
        + import()--> [blob:... (ort.proxy)]
                        |
+ new Worker()--> [blob:... (ort.proxy) (worker)]
                                            |
+ fetch('ort-wasm-simd-threaded.mjs')
                                                |
+ URL.createObjectURL(res.blob())
                                                |
+ import()--> [blob:... (ort-wasm-simd-threaded)]
                                                                |
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
                                                                |
+ new Worker()--> [blob:... (ort-wasm-simd-threaded) (worker)]
|
+ WebAssembly.instantiateStreaming()--> [ort-wasm-simd-threaded.wasm]
  ```
</details>
2024-05-20 09:51:16 -07:00
..
.vscode [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
common [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
node Enable QNN HTP support for Node (#20576) 2024-05-09 13:11:07 -07:00
react_native [js/rn] Fix some bugs (#20242) 2024-05-15 10:32:08 -07:00
scripts [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
web [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
.clang-format
.eslintrc.js [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
.gitignore
.prettierignore
.prettierrc
build_jsep.bat [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
package-lock.json [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
package.json [js/web] optimize module export and deployment (#20165) 2024-05-20 09:51:16 -07:00
README.md Add MacOS build to ORT C Pod (#18550) 2023-11-28 10:11:53 -08:00
tsconfig.json
tsconfig.tools.json

ONNX Runtime JavaScript API

This directory contains multiple NPM projects:

Development

This folder contains a .vscode folder for Visual Studio Code workspace configs. Using VSCode to open this folder will allow code-formatting and linting features on typescript and C/C++ source code inside this folder. Following files are used for code-formatting and linting features for developers:

  • .vscode/**
  • package.json
  • packages-lock.json
  • .eslintrc.js
  • .clang-format

Please follow the steps described below to setup development environment.

Prerequisites

Setup TypeScript development environment

In <ORT_ROOT>/js, run:

npm ci

This will install Clang-format and ESLint for code-formatting and linting features. This is a one-time setup unless a git clean is performed or folder <ORT_ROOT>/js/node_modules is removed manually.

Using VSCode:

Use VSCode to open folder <ORT_ROOT>/js.

Make sure to open the correct folder to allow VSCode to load workspace configuration. Otherwise typescript and code formatter may not work as expected.

To populate typescript type declarations, in each project folder, run npm ci.

Run code formatter and linter manually

In <ORT_ROOT>/js, use npm run lint to run ESLint , and use npm run format to run clang-format.

onnxruntime-common

language: typescript

dependency:

folder: <ORT_ROOT>/js/common

This project is designed to include all "common" code, which are pure javascript that can run in both Node.js and browsers.

Requirements

Node.js v12+ (recommended v14+)

Build

Use following command in folder <ORT_ROOT>/js/common to install NPM packages, build typescript files and generate bundles:

npm ci

Distribution

It should be able to consumed by both from projects that uses NPM packages (through a Node.js folder structure of node_modules folder that generated by npm install onnxruntime-common) and from a CDN service that serves a .min.js bundle file.

Features

Following features are included in onnxruntime-common:

  • InferenceSession interfaces
  • Tensor/OnnxValue interfaces, implementation and a set of utility functions
  • Backend interfaces and a set of functions for backend registration

Generate API reference document

Use following command in folder <ORT_ROOT>/js/common to generate API reference document:

npx typedoc

Document will be generated in folder <ORT_ROOT>/js/common/docs.

onnxruntime-node

language: typescript/C++

dependency: onnxruntime-common, ONNXRuntime.dll

folder: <ORT_ROOT>/js/node

This project is designed to be used as a NPM package to enable Node.js users to consume ONNX Runtime via Node.js binding, in Node.js or any Node.js compatible environment.

Requirements

Node.js v12+ (recommended v14+)

Build

Build ONNX Runtime and Node.js binding

Follow instructions for building ONNX Runtime Node.js binding

Build Node.js binding only

Use following command in folder <ORT_ROOT>/js/node to install NPM packages and build typescript files:

npm ci

This will download the latest pre-built ONNX Runtime binaries for the current platform.

Distribution

It should be able to consumed by from projects that uses NPM packages (through a Node.js folder structure of node_modules folder that generated by npm install onnxruntime-node).

onnxruntime-web

language: typescript

dependency: onnxruntime-common, ONNXRuntime WebAssembly

folder: <ORT_ROOT>/js/web

This project is a library for running ONNX models on browsers. It is the successor of ONNX.js.

Build

onnxruntime-web build instructions

Test

We use command npm test (test runner) and npm run test:e2e (E2E test) for tests in ONNXRuntime Web.

test runner

In folder <ORT_ROOT>/js/web,

  • Run npm test -- --help for a full CLI instruction.
  • Run npm test -- <your-args> --debug to run one or more test cases.

There are multiple levels of tests for ONNXRuntime Web:

  • unit test: tests for individual components written in TypeScript. Launch unit test by:

    npm test -- unittest
    
  • model test: run a single model. The model folder should contains one .onnx model file and one or more folders for test cases, each folder contains several input**.pb and output**.pb as test data. Launch model test by:

    npm test -- model <model_folder>
    
  • op test: test a single operator. An op test is described in a .jsonc file which specify the operator type, its attributes and one or more test case(s), each includes a list of expected input tensor(s) and output tensor(s). The .jsonc file is located at <ORT_ROOT>/js/web/test/data/ops. Launch op test by:

    npm test -- op <file_name>
    
  • suite test: suite test includes unit test, a list of model tests and op tests. Launch suite test by:

    npm test
    

E2E test

E2E test is for testing end-to-end package consuming. In this test, NPM packages for onnxruntime-common and onnxruntime-web are generated and a clean folder is used for installing packages. Then a simple mocha test is performed to make sure package can be consumed correctly.

To launch E2E test:

npm run test:e2e

Debugging

Debugging TypeScript on Desktop/Chrome

To debug the code from test-runner on Chrome:

  • Launch npm test -- <your_args> --debug. It opens an instance of Chrome browser.
  • In the open Chrome browser, click the DEBUG button on the top-right of the page.
  • In VSCode, click [side bar]->Run and Debug->select [Attach to Chrome]->click [Start Debugging] to attach.
  • put breakpoints in source code, and Refresh the page to reload.

Debugging TypeScript on iOS/Safari

To debug on an Apple iOS device, please refer to the following steps:

  • install RemoteDebug iOS WebKit Adapter by following its instructions.
  • launch the adapter in commandline: remotedebug_ios_webkit_adapter --port=9000.
  • in VSCode, select debug configuration Remote Browser via Webkit Adaptor.
  • follow the steps above to debug.

Debugging TypeScript on Android/Chrome

To debug on an Android device, please refer to the following steps:

  • Install Android SDK Platform Tools and make sure adb is ready to use.
  • Follow instructions in Remote Debugging on Android to launch adb. Make sure to use port 9000 so that the existing debug configuration works.
  • in VSCode, select debug configuration Remote Browser via Webkit Adaptor.
  • follow the steps above to debug.

Debugging C/C++ for ONNX Runtime WebAssembly

To debug C/C++ code for ONNX Runtime WebAssembly, you need to build ONNX Runtime with debug info (see Build).

Currently debugging C/C++ code in WebAssembly is not supported in VSCode yet. Please follow this instruction to debug in browser devtool using extension C/C++ DevTools Support (DWARF).

Generating Document

This section describes how to generate the latest document for ONNX Runtime Web.

The document contains information about operators WebGL backend supports. It should align with the operator resolve rules in code and spec definition from ONNX.

In folder <ORT_ROOT>/js/web, use command npm run build:doc to generate the latest documents.

Distribution

It should be able to consumed by both from projects that uses NPM packages (through a Node.js folder structure of node_modules folder that generated by npm install onnxruntime-web) and from a CDN service that serves a ort.min.js file and one or multiple .wasm file(s).

Reduced WebAssembly artifacts

By default, the WebAssembly artifacts from onnxruntime-web package allows use of both standard ONNX models (.onnx) and ORT format models (.ort). There is an option to use a minimal build of ONNX Runtime to reduce the binary size, which only supports ORT format models. See also ORT format model for more information.

Reduced JavaScript bundle file fize

By default, the main bundle file ort.min.js of ONNX Runtime Web contains all features. However, its size is over 500kB and for some scenarios we want a smaller sized bundle file, if we don't use all the features. The following table lists all available bundles with their support status of features.

bundle file name file size file size (gzipped) WebGL WASM-core WASM-proxy WASM-threads ES5 backward compatibility
ort.es5.min.js 594.15KB 134.25KB O O O O O
ort.min.js 526.02KB 125.07KB O O O O X
ort.webgl.min.js 385.25KB 83.83KB O X X X X
ort.wasm.min.js 148.56 44KB X O O O X
ort.wasm-core.min.js 40.56KB 12.74KB X O X X X

Build ONNX Runtime as a WebAssembly static library

When --build_wasm_static_lib is given instead of --build_wasm, it builds a WebAssembly static library of ONNX Runtime and creates a libonnxruntime_webassembly.a file at a build output directory. Developers who have their own C/C++ project and build it as WebAssembly with ONNX Runtime, this build option would be useful. This static library is not published by a pipeline, so a manual build is required if necessary.

onnxruntime-react-native

language: typescript, java, objective-c

dependency: onnxruntime-common

folder: <ORT_ROOT>/js/react_native

This project provides an ONNX Runtime React Native JavaScript library to run ONNX models on React Native Android and iOS app.

Requirements

  • Yarn
  • Android SDK and NDK, which can be installed via Android Studio or sdkmanager command line tool
  • A Mac computer with the latest macOS
  • Xcode
  • CMake
  • Python 3

Models with ORT format

Prior to ORT v1.13, the ONNX Runtime React Native package utilized the ONNX Runtime Mobile package, which required an ONNX model to be converted to ORT format. Follow these instructions to convert ONNX model to ORT format. Note that the ONNX Runtime Mobile package includes a reduced set of operators and types, so not all models are supported. See here for the list of supported operators and types.

From ORT v1.13 onwards the 'full' ONNX Runtime package is used. It supports both ONNX and ORT format models, and all operators and types.

Build

  1. Install NPM packages for ONNX Runtime common JavaScript library and required React Native JavaScript libraries

    • in <ORT_ROOT>/js/, run npm ci.
    • in <ORT_ROOT>/js/common/, run npm ci.
    • in <ORT_ROOT>/js/react_native/, run yarn.
  2. Acquire or build the Android ONNX Runtime package

    1. To use a published Android ONNX Runtime Mobile package from Maven, go to step 5.

    2. Set up an Android build environment using these instructions. Note that the dependencies are quite convoluted, so using the specified JDK and Gradle versions is important.

    3. In <ORT_ROOT>, run the below python script to build the ONNX Runtime Android archive file. On a Windows machine, this requires an admin account to build.

    You can build a 'full' package that supports all operators and types, or a reduced size 'mobile' package that supports a limited set of operators and types based on your model/s to miminize the binary size. See here for information about how the reduced build works, including creating the configuration file using your model/s.

    Full build:

    python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_full_aar_build_settings.json --config Release --android_sdk_path <ANDROID_SDK_PATH> --android_ndk_path <ANDROID_NDK_PATH> --build_dir <BUILD_DIRECTORY>
    

    Reduced size build with configuration file generated from your model/s. Note that either Release or MinSizeRel could be used as the config, depending on your priorities:

    python tools/ci_build/github/android/build_aar_package.py tools/ci_build/github/android/default_mobile_aar_build_settings.json --config MinSizeRel --android_sdk_path <ANDROID_SDK_PATH> --android_ndk_path <ANDROID_NDK_PATH> --build_dir <BUILD_DIRECTORY> --include_ops_by_config <required_ops_and_types_for_your_models.config> --enable_reduced_operator_type_support
    
    1. Move the generated ONNX Runtime Android archive file to <ORT_ROOT>/js/react_native/android/libs/.

      Full build: Copy <BUILD_DIRECTORY>/aar_out/Release/com/microsoft/onnxruntime/onnxruntime-android/<version>/onnxruntime-android-<version>.aar into <ORT_ROOT>/js/react_native/android/libs directory.

      Reduced size build: Copy <BUILD_DIRECTORY>/aar_out/MinSizeRel/com/microsoft/onnxruntime/onnxruntime-mobile/<version>/onnxruntime-mobile-<version>.aar into <ORT_ROOT>/js/react_native/android/libs directory and update to dependencies in js/react_native/android/build.gradle to use onnxruntime-mobile instead of onnxruntime-android.

    2. To verify, open the Android Emulator and run this command from <ORT_ROOT>/js/react_native/android

      ./gradlew connectedDebugAndroidTest
      
  3. Build iOS ONNX Runtime package

    1. To use the published C/C++ ONNX Runtime package from CocoaPods, skip all steps below.

    2. Set up iOS build environment using these instructions.

    3. Build a fat ONNX Runtime Mobile Framework for iOS and iOS simulator from <ORT_ROOT> using this command:

      Full build:

      python tools/ci_build/github/apple/build_apple_framework.py tools/ci_build/github/apple/default_full_apple_framework_build_settings.json --config Release
      

      Reduced size build:

      python tools/ci_build/github/apple/build_apple_framework.py tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json --config MinSizeRel --include_ops_by_config <required_ops_and_types_for_your_models.config> --enable_reduced_operator_type_support
      

      The build creates Headers, LICENSE, and onnxruntime.xcframework in build/iOS_framework/framework_out directory. From framework_out directory, create an archive file named onnxruntime-c.zip for a full build or onnxruntime-mobile-c.zip for a reduced size build and copy to <ORT_ROOT>/js/react_native/local_pods directory.

      Full build:

      zip -r onnxruntime-c.zip .
      

      Reduced size build:

      zip -r onnxruntime-mobile-c.zip .
      
    4. To verify, open the iOS Simulator and run the below command from <ORT_ROOT>/js/react_native/ios. Change the destination argument as needed to specify a running iOS Simulator.

      If using the reduced size build it is necessary to first update some configuration to use the mobile ORT package:

      • replace onnxruntime/onnxruntime.framework with onnxruntime-mobile/onnxruntime.framework in /js/react_native/ios/OnnxruntimeModule.xcodeproj/project.pbxproj
      • replace onnxruntime-c with onnxruntime-mobile-c in /js/react_native/ios/Podfile
      • For reference, this PR shows the changes made to switch from using the 'mobile' ORT package to the 'full' package.
      pod install
      xcodebuild test -workspace OnnxruntimeModule.xcworkspace -scheme OnnxruntimeModuleTest -destination 'platform=iOS Simulator,OS=latest,name=iPhone 13'
      
  4. Test Android and iOS apps. In Windows, open Android Emulator first.

    debug.keystore must be generated ahead for Android example.

    keytool -genkey -v -keystore <ORT_ROOT>/js/react_native/e2e/android/debug.keystore -alias androiddebugkey -storepass android -keypass android -keyalg RSA -keysize 2048 -validity 999999 -dname "CN=Android Debug,O=Android,C=US"
    

    From `<ORT_ROOT>/js/react_native,

    yarn bootstrap
    

    When testing with a custom built ONNX Runtime Android package, copy <BUILD_DIRECTORY>/aar_out/MinSizeRel/com/microsoft/onnxruntime/onnxruntime-{android|mobile}/<version>/onnxruntime-{android|mobile}-<version>.aar into the <ORT_ROOT>/js/react_native/e2e/android/app/libs directory.

    When testing with a custom built ONNX Runtime iOS package, copy onnxruntime-[mobile-]c.zip into the <ORT_ROOT>/js/react_native/local_pods directory.

    If using the reduced size build it is necessary to update some configuration to use the mobile ORT package:

    • replace com.microsoft.onnxruntime:onnxruntime-android with com.microsoft.onnxruntime:onnxruntime-mobile in /js/react_native/e2e/android/app/build.gradle
    • replace onnxruntime-c with onnxruntime-mobile-c in /js/react_native/e2e/ios/Podfile
  • Run E2E Testing with Detox framework

    When testing with integrated Detox framework for Android and iOS e2e apps:

    • Detox prerequisites:

      Install detox command line tools:

      yarn global add detox-cli
      

      Install applesimutils which is required by Detox to work with iOS simulators. (Requires a MacOS device)

      brew tap wix/brew
      brew install applesimutils
      

      Main Detox project files:

      • .detoxrc.js -Detox config file;
      • e2e/jest.config.js -Jest configuration;
      • e2e/OnnxruntimeModuleExample.test.js - initial react native onnxruntimemodule e2e detox test.
    • Build the detox e2e testing app.

      From <ORT_ROOT>/js/react_native/e2e, run the command to build the e2e testing app. Before that ensure you have android emulator/ios simulator started locally.

      iOS (Debug):

      detox build --configuration ios.sim.debug
      

      Android (Debug):

      detox build --configuration android.emu.debug
      
      • Note: If names of local testing android/ios devices do not match the default setting in .detoxrc.js file, modify the device name in config files accordingly to match local device name otherwise would cause a build failure.
    • Run the detox e2e tests.

      In a debug configuration, you need to have React Native packager running in parallel before you start Detox tests:

      npm start
      
      > react-native start
      

      From <ORT_ROOT>/js/react_native/e2e, run Detox tests using the following command:

      iOS (Debug):

      detox test --configuration ios.sim.debug
      

      Android (Debug):

      detox test --configuration android.emu.debug
      

      To record logs for testing results, add --record-logs. Output logs and test results will be produced in the e2e/artifacts/ folder. See: Detox/logger#artifacts

      yarn bootstrap changes packages.json and yarn.lock files. Once testing is done, restore changes to avoid unwanted commit.

  1. Run Android and iOS apps.

    yarn e2e android
    yarn e2e ios
    

NPM Packaging

  1. Update a version using npm version <version> from <ORT_ROOT>/js/react_native folder. If it's for a dev, use npm version <version>-dev.<subversion>

  2. Run npm pack and verify NPM package contents

  3. Run npm publish <tgz> --dry-run to see how it's going to be published

  4. Run npm publish <tgz> to publish to npmjs. If it's for a dev, add flag --tag dev.

Distribution

It should be able to consumed by React Native projects that uses Yarn packages through yarn add onnxruntime-react-native.