npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@jacobp100/react-native-webworker

v0.2.3

Published

WebWorkers for React Native

Downloads

23

Readme

react-native-webworker

WebWorkers for React Native

Work based off react-native-threads

Supports the new architecture, using either Hermes or JavaScriptCore

Currently only supports iOS

Usage

npm install @jacobp100/react-native-webworker
(cd ios; bundle exec pod install)

In your application code (React components, etc.):

import { WebWorker } from '@jacobp100/react-native-webworker';

// Start a new react native JS process
// The worker JS file has to be at the top level (where the package.json is)
// But you can call it anything you want - and have multiple
const worker = new WebWorker('/worker.js');

// Send a message, strings only
worker.postMessage('hello');

// Listen for messages
worker.onmessage = (e) => console.log(e.data);

// Listen for errors
worker.onerror = (e) => console.log(e.message);

// Stop the JS process
worker.terminate();

In your thread code (dedicated file such as worker.js):

import { self } from 'react-native-threads';

// Listen for messages
self.onmessage = (e) => {
  // Message is a string
  const message = e.data;
};

// Send a message, strings only
self.postMessage('hello');

Thread Lifecycle

  • Threads are paused when the app enters in the background
  • Threads are resumed once the app is running in the foreground
  • During development, when you reload the main JS bundle (shake device -> Reload) the threads are killed

Debugging

Instantiating Threads creates multiple react native JS processes and can make debugging remotely behave unpredictably. I recommend using a third party debugging tool like Reactotron to aid with this. Each process, including your main application as well as your thread code can connect to Reactotron and log debugging messages.

Building for Release

Depending on if you're using Hermes (the default) or JavaScript Core, the commands differ. For iOS, the commands you'll need to add are:-

# Bundle your worker JS
npx react-native bundle --dev false --assets-dest ./ios --entry-file worker.js --platform ios --bundle-output ./ios/worker.jsbundle
Hermes

If you're using Hermes, you'll also need to add the following command:-

# Convert bundled JS to Hermes ByteCode
./ios/Pods/hermes-engine/destroot/bin/hermesc -emit-binary ./ios/worker.jsbundle -out ./ios/worker.jsbundle

Once you have generated the bundle file in your ios folder, you will also need to add the bundle file to you project in Xcode. In Xcode's file explorer you should see a folder with the same name as your app, containing a main.jsbundle file as well as an AppDelegate.m file. Right click on that folder and select the 'Add Files to ' option, which will open up finder and allow you to select your ios/worker.jsbundle file. You will only need to do this once, and the file will be included in all future builds.

For convenience I recommend adding these thread building commands as npm scripts to your project.

Optimisations (Experimental)

By default, you can use most of React Native and it's related infrastructure in your workers. This includes globals like fetch, setTimeout etc. However, including this makes your worker file about 800kb larger.

If your worker does not use those globals - maybe it only does heavy computation that would lock the UI thread - you can run the worker using a lighter environment, and get the benefit of a smaller bundle.

The light environment will use will use either Hermes or JavaScriptCore - depending on what's used in your app.

When using Hermes, JS exceptions are caught and reported, but the message cannot (yet) be recovered, and are always reported as Unknown error.

import { WebWorker } from '@jacobp100/react-native-webworker';

const worker = new WebWorker('path/to/worker.js', {
  environment: 'light',
});

In your worker, do not import react-native or any react-native related packages - it'll cause a crash. The self variable is exposed as a global.

self.onmessage = (e) => {
  self.postMessage(`Hello ${e.data}`);
};

Infinite Loops

If you're using JavaScriptCore, there is no mechanism to terminate currently executing code. This means if your worker code goes into an infinite loop, calling worker.terminate() will not stop the execution.

Hermes does support this, and will do so automatically in development builds, but needs additional setup for release builds. In your build command, you'll need to add the -emit-async-break-check to the hermes compile command.

-./ios/Pods/hermes-engine/destroot/bin/hermesc -emit-binary ./ios/worker.jsbundle -out ./ios/worker.jsbundle
+./ios/Pods/hermes-engine/destroot/bin/hermesc -emit-binary -emit-async-break-check ./ios/worker.jsbundle -out ./ios/worker.jsbundle

In the case you are terminating the worker only to stop long running code, and intend on re-initializing the worker afterwards, you can skip some steps and just abort just the long running code, leaving the worker otherwise in-tact. This saves the need to re-parse the JavaScript and re-initialize the worker. Be cautious when doing this - you must be consider any global state in your worker, and if terminating half way through will cause correctness issues.

If this scenario is suitable for your use-case, you can call worker.terminate({ mode: 'execution' }). This will call the onerror handler. You can continue to call worker.postMessage, and you do not need to wait for the onerror handler to fire.