The port of uWebSockets library for React Native. Inspired by the uWebSockets.js for Node.js and tailored for React Native app.
- uWebSockets is simple, secure & standards compliant web server for the most demanding of applications. See uWebSockets for more information
- uws-react-native is library that allows you to easily use uWebSockets in your React Native through new architecture with JSI to the native C++
⚠️ WebSocket server is not implemented yet
We provide three registry homes where this library is available for use in your project. You can use either it is from NPM registry, or GitHub Release, or GitHub Packages. It has absolutely no external JavaScript dependencies
npm
npm install uws-react-native
yarn
yarn add uws-react-native
pnpm
pnpm install uws-react-native
To install this library from GitHub release
- Go to this project's GitHub Release
- Find the
uws-react-native-X.X.X.tgzasset from one of the release versions - Copy the asset URL or link (Right click at the asset file name in your browser)
Finally, do the regular installation with the CLI, but with the asset URL
npm
npm install https://github.com/.../uws-react-native-X.X.X.tgz
yarn
yarn add https://github.com/.../uws-react-native-X.X.X.tgz
pnpm
pnpm install https://github.com/.../uws-react-native-X.X.X.tgz
You can also do an offline installation by downloading the tarball file first, and do the regular installation with the CLI, but with the local file path.
First, create your GitHub personal token (classic) with read:packages access
Skip if you already have it
- In the upper-right corner of any page on GitHub, click your profile picture, then click Settings
- In the left sidebar, click <> Developer settings
- In the left sidebar, under 🔑 Personal access tokens, click Tokens (classic)
- Select Generate new token, then click Generate new token (classic)
- Fill your descriptive note, fill / check the
read:packagesaccess, and click Generate token - Copy the generated token, or save it to somewhere else
After that, in the same directory as your package.json file, create or edit an .npmrc file with this snippet
@rakadoank:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_PERSONAL_TOKEN
Finally, do the regular installation with the CLI, but with the scope name
npm
npm install @rakadoank/uws-react-native
yarn
yarn add @rakadoank/uws-react-native
pnpm
pnpm install @rakadoank/uws-react-native
Since uws-react-native is a port of uWebSockets library for JavaScript, this library is really similar of how to use the uWebSockets in C++, or the uWebSockets.js for Node.js.
You can refer to the uWebSockets.js example, but we recommend to create a server in useEffect.
This repository does also contain the server example. You can also refer to it, but it is currently for library development playground rather than proper example.
A simple server example
import { useEffect } from "react"
import * as uWS from "uws-react-native"
export function Component() {
// useEffect is perfect tool for production and even in development mode.
// In the development mode, any changes below will restart the server automatically because of the useEffect cycle
useEffect(() => {
const app = uWS.App()
app.get("/data/:foo/:bar", (res, req) => {
const fooSlug = req.getParameter("foo")
const barSlug = req.getParameter("bar")
res.writeHeader("content-type", "application/json")
res.end(
JSON.stringify({
foo: fooSlug,
bar: barSlug,
});
)
})
app.get("/my-page", res => {
res.write("<html><body>")
res.write("<h2>Hello World</h2>
res.end("</body></html>")
});
app.listen("127.0.0.1", 5000, token => {
if(token) {
console.log("Listening at port 5000")
} else {
console.log("Failed to listen")
}
})
return () => {
app.close()
}
}, [])
}uws-react-native is only compatible for new architecture of React Native.
uws-react-native is supported in Android, iOS, and macOS. Windows is currently not supported, and Web is impossible.
- SSL options. We need to research how to provide .pem file in React Native app and its platform architecture regarding the SSL topic
- WebSocket server. Not implemented yet. It will be supported later.
There are some new APIs in uws-react-native. The most reason is because of the differentiation of React Native's architecture compared to the casual server program
- The route method handler like
any,get,postand others expects third argument as the handler options optionally. SeeHttpRouterOptions - In
HttpResponseobject,onFullData. This is an equivalent ofres.collectBodyfrom uWebSockets.js, but to set the max size, provide it through route method handler optionsonFullDataText. Same as theonFullData, but provides the body data in raw text instead of ArrayBuffer. This is useful if you are using React Native 0.84 version or older because TextDecoder is natively supported only in React Native 0.85 version
Thank you for your support to this project. See Contributing for more information to help you get started with your contributions.
uws-react-native is still in heavy development and research. All the uWebSockets instances are not fully implemented yet.
There are development and research things that you can read for your informations, especially if you are already familiar with uWebSockets. The most things are because of the React Native's architecture differentiation compared to the casual uWebSockets server program.
We are embracing the main chaos of supporting uWebSockets in React Native architecture, which is to prevent UI/Main thread from blocking.
Intentionally, we make the uWebSockets will runs in another thread, therefore we have to make sure the communication safety between uWebSockets runner thread to the JS thread and vice versa. In theory, we can make uWebSockets runs in the main thread, but the app will be unusable, and then force closing the app is the only way to stop the server.
Yet, we only use one dedicated thread per uWebSockets runner. I am in my own research to find better way to improve this by maximizing it to the hardware concurrency limit. Basically, if you run the App with two instance or more in JavaScript side, and with the same port listening number, you actually run the uWebSockets in multiple thread, but the JavaScript is still in single thread. It is single thread by default in React Native, we have no control of it.
We have another issue because of the uWebSockets runs in another thread. From the JSI C++ side, we have to assume any JavaScript functions as a callback especially the route method handler are asynchronous. We cannot make a sync call to the JavaScript function from an arbitrary thread to the JavaScript thread, and due to the asynchronous call, it makes the JavaScript call to the uWebSockets instances is late.
There some topics regarding the threading
For the threading case especially, we have to predefined two instances in the C++ uWebSockets route method handler because of the late call, and the late call would not be tolerated by the uWebSockets internally for some cases
res.onAborted
We have to predefined the onAborted callback in C++ side and prevent res.end call from JavaScript internally in C++ side. Normally, you would check if it is already aborted or not before calling the end method, but our predefined onAborted callback may also late to tell to the JavaScript side. If we are not predefining this method, uWebSockets assumes that you have not assign onAborted callback at the time due to the res.onAborted assignment from JavaScript is also late.
res.onDataV2
For the onData and onDataV2, we have predefined it with a single onDataV2 callback in C++ side. If this method is not predefined, uWebSockets will not collect any incoming body data. If a route method handler is sure that it doesn't expect any body data at all, a route method handler can disable the body reading through the third argument in any, get, post, and other route methods.
In theory, we can create another JavaScript runtime with react-native-worklets and tie with our uWebSockets runner. It would solve a lot of late communication problem between uWebSockets runner and JavaScript thread that we embrace right now, but it also introduces new major issue, which is making other native libraries unavailable.
Think of this sample case, you want to use uws-react-native server for a simple CRUD with a local database in an app. You probably know SQLite can be used in Android, iOS, macOS, even Windows app, with your own adapter or a known library that support SQLite integration in React Native such as op-sqlite, and Expo SQLite. If you want to use that known library, this case would not works at all, because op-sqlite and/or Expo SQLite is tied to the default JavaScript runtime. Even, you cannot use any React Native native libraries in arbitrary JavaScript thread that has created by react-native-worklets if the library you want to use is using the default JavaScript runtime. If you really want to achieve the goal of this case, you have to create your own library for the SQLite database by yourself and tie-up with the JavaScript runtime. Probably, in the future we would still provide that worker thread with react-native-worklets.
If the native library you want to use is using react-native-nitro-modules, you can use the library in arbitrary JavaScript thread that created by react-native-worklets, because the Nitro itself is fully runtime-agnostic. In short, our uWebSockets runner can run in truly multiple threads approach by making your JavaScript thread also run in multiple threads with react-native-worklets.