Key changes
Networking on Worklet Runtimes in Bundle Mode
Worklet Runtimes created in Bundle Mode now ship a standalone networking module: XMLHttpRequest, Blob, FileReader, fetch (whatwg), Headers, Request, Response, FormData, AbortController and AbortSignal. It replaces the earlier networking preview and its FETCH_PREVIEW_ENABLED feature flag. createWorkletRuntime accepts a new enableNetworking option, which defaults to true and is forced off on runtimes without the Event Loop.
- refactor(Worklets): remove the networking preview by @tjzel in #10250
- feat(Worklets): networking module with XMLHttpRequest by @tjzel in #10493
- feat(Worklets): add Blob and FileReader to the networking module by @tjzel in #10494
- feat(Worklets): add fetch to the networking module by @tjzel in #10495
- feat(Worklets): add FormData to the networking module by @tjzel in #10496
- feat(Worklets): add AbortController to the networking module by @tjzel in #10497
- feat(Worklets): add the enableNetworking runtime option by @tjzel in #10498
OXC port of the Worklets Babel plugin
The Worklets Babel plugin has a Rust port built on OXC for Bundle Mode. It is available as react-native-worklets/plugin-oxc/babel, with prebuilt binaries for macOS, Linux and Windows on x64 and arm64.
- feat(Worklets): port babel plugin to oxc by @tshmieldev in #9518
- chore(Worklets): publishing oxc plugin binaries by @tshmieldev in #10608
Fixed-type Synchronizable
createSynchronizable accepts a new fixedType option. A fixed-type Synchronizable holds a number or a boolean without serialization and exposes setDirty, a non-exclusive write that doesn't wait for other setDirty calls. On the C++ side Synchronizable is now an interface over std::variant values with a SynchronizableDynamic implementation, and several races on exotic architectors and lock leaks in the dynamic implementation are fixed.
- feat(Worklets): fixed-type Synchronizable by @tjzel in #10296
- feat(Worklets): add setDirty to the Synchronizable interface by @tjzel in #10295
- refactor(Worklets): operate on variant values in Synchronizable by @tjzel in #10294
- refactor(Worklets): extract SynchronizableDynamic from Synchronizable by @tjzel in #10293
- fix(Worklets): make Synchronizable value access atomic by @tjzel in #10292
- fix(Worklets): release the Synchronizable lock when a setter throws by @tjzel in #10331
- refactor(Worklets): identify the Synchronizable lock owner with std::thread::id by @tjzel in #10349
- docs(Worklets): document fixed-type Synchronizable by @tjzel in #10297
Faster startup
The native side of WorkletsModule is created on a background thread as soon as the module is created, so installTurboModule only attaches it to the RN Runtime. In Bundle Mode the bundle is evaluated on the UI Worklet Runtime on a background thread while the RN Runtime evaluates it, instead of on the JS thread in start.
- feat(Worklets): initialize the native module ahead of time by @tjzel in #10489
- feat(Worklets): start the UI runtime in Bundle Mode ahead of time by @tjzel in #10490
Hermes microtask queue on Worklet Runtimes
Worklet Runtimes use the built-in Hermes microtask queue instead of a custom JS implementation.
- refactor: migrate to Hermes microtaskQueue by @tjzel in #10199
- refactor: intertwine RAF queue with microtasks by @tjzel in #10237
Removed SerializableInitializer (SerializableHandle)
The Serializable handle is gone: SerializableInitializer, createSerializableInitializer and the __init clone path are removed, and makeShareable serializes its value eagerly into a retaining Serializable. RetainingSerializable caches its value per runtime. Serializable::ValueType::HandleType stays in the Compat Stable API enum for ABI compatibility and extractSerializable throws for it.
- refactor(Worklets): remove the Serializable Initializer type by @tjzel in #10414
- refactor(Worklets): implement
makeShareablewithout a handle by @tjzel in #10412 - feat(worklets): per-runtime cache in retainingSerializable by @tshmieldev in #10264
- refactor(Worklets): split Serializable classes into dedicated files by @tjzel in #10345
Leaner Babel plugin output
Worklet closures are stored as arrays instead of objects, closure-free worklets are exported directly in Bundle Mode without factory wrappers, and implicit worklet context objects are removed. navigator is a known global, so worklets resolve it on their own runtime instead of capturing the main runtime's object by closure.
- chore(worklets): __closure is now array instead of obj by @tshmieldev in #10506
- chore(worklets): fast path for closure-free worklets by @tshmieldev in #10517
- refactor(Worklets): remove implicit worklet context objects by @tjzel in #10411
- feat(Worklets): treat navigator as a known global in the Babel plugin by @wcandillon in #10364
- chore(rnre+worklets) - less worklets/serialization on run by @tshmieldev in #10466
iOS Swift Package Manager support
Worklets can be integrated on iOS through Swift Package Manager via Package.swift and SPM integration metadata in react-native.config.js. The nightly compatibility check builds the app via SPM on React Native >= 0.87.
- feat(rnre+worklets): add support for SPM by @kacperzolkiewski in #10472
- ci: add SPM build step to nightly compatibility check by @kacperzolkiewski in #10511
Safer Worklet Runtime teardown
Destroying a Worklet Runtime now acquires the runtime mutex first, so a synchronous call in flight on another thread finishes, discarded results of synchronous calls are destroyed under the lock, and pending jobs of the async queue and event loop are aborted under the lock instead of destroying their JSI handles on an unrelated thread.
- fix(Worklets): acquire the runtime mutex before destroying the JSI runtime by @tjzel in #10550
- fix(Worklets): destroy discarded sync call results under the runtime lock by @tjzel in #10552
- fix(Worklets): abort pending jobs under the runtime lock on teardown by @tjzel in #10580
React Native 0.88 support
- chore: upgrade React Native to 0.88.0-rc.1 by @pawicao in #10582
- Chore(rnre+worklets): reactutils header by @tshmieldev in #10536
Other changes
- feat(Worklets): getCurrentThreadId function by @tjzel in #10441
- refactor(Worklets): extract UI-thread check into UIScheduler::isOnUIThread by @bartlomiejbloniarz in #10265
- chore(worklets): New parameters for autoworkletization the
withTimingandwithSpringmethods by @piaskowyk in #10467 - fix(Worklets): pad missing native method arguments with undefined by @bartlomiejbloniarz in #10593
- fix(worklets): stop AnimationFrameQueue when WorkletsModule is invalidated by @shubhamdeol in #10278
- fix(Worklets): stop AnimationFrameQueue dispatch on reentrant invalidate by @tjzel in #10464
- fix: Serializable umbrella header for expo by @tjzel in #10390
- fix(Worklets): correct
RetainingSerializable.hinclude in umbrellaSerializable.hby @tjzel in #10406 - fix(Worklets): capture JSX element names into worklet closures by @tshmieldev in #10409
- fix(Worklets): dehoist module.exports assignments by @tshmieldev in #10408
- fix(Worklets): stop workletizing getters, setters and constructors by @tshmieldev in #10421
- fix(Worklets): Crash when handling proto by @tshmieldev in #10451
- fix(builds): too strict lint skip matcher by @tshmieldev in #10448
- refactor(Worklets): build nativeLoggingHook natively by @tjzel in #10488
- chore(Worklets): drop RCTEventEmitter base from WorkletsModule by @tjzel in #10485
- chore(worklets): marked unlikely branch as unlikely by @tshmieldev in #10465
- chore(Worklets): more predictable test snapshots by @tshmieldev in #10420
- chore(Worklets): docs updates by @tjzel in #10473
- docs(worklets): sync
isWorkletFunctiontype definitions with source by @tjzel in #10415 - docs: compare UI runtime scheduling functions and fix stale call tables by @0xyy in #9895
- docs: remove outdated plugin content by @tjzel in #10350
- add json-ld to the worklets docs by @halskiszymon in #10419
Full Changelog: worklets-0.12.2...worklets-0.13.0