react-native-worklets 0.3.0 → 0.4.0-bundle-mode-preview-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp +532 -0
  2. package/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h +88 -0
  3. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.cpp +40 -122
  4. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h +16 -40
  5. package/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h +2 -1
  6. package/Common/cpp/worklets/Resources/ValueUnpacker.cpp +1 -1
  7. package/Common/cpp/worklets/SharedItems/Shareables.cpp +200 -24
  8. package/Common/cpp/worklets/SharedItems/Shareables.h +108 -7
  9. package/Common/cpp/worklets/Tools/JSLogger.cpp +56 -4
  10. package/Common/cpp/worklets/Tools/JSLogger.h +17 -0
  11. package/Common/cpp/worklets/Tools/JSScheduler.cpp +12 -0
  12. package/Common/cpp/worklets/Tools/JSScheduler.h +10 -2
  13. package/Common/cpp/worklets/Tools/SingleInstanceChecker.h +3 -1
  14. package/Common/cpp/worklets/Tools/WorkletsJSIUtils.cpp +19 -1
  15. package/Common/cpp/worklets/Tools/WorkletsJSIUtils.h +12 -3
  16. package/Common/cpp/worklets/Tools/WorkletsSystraceSection.h +136 -0
  17. package/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.cpp +4 -4
  18. package/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h +1 -1
  19. package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.cpp +85 -0
  20. package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.h +55 -0
  21. package/Common/cpp/worklets/WorkletRuntime/WorkletHermesRuntime.h +8 -4
  22. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +70 -24
  23. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +24 -4
  24. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.cpp +53 -1
  25. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h +2 -1
  26. package/RNWorklets.podspec +9 -4
  27. package/android/CMakeLists.txt +14 -36
  28. package/android/build.gradle +16 -33
  29. package/android/src/experimentalBundling/com/swmansion/worklets/WorkletsModule.java +149 -0
  30. package/android/src/{main/java → legacyBundling}/com/swmansion/worklets/WorkletsModule.java +17 -2
  31. package/android/src/main/cpp/worklets/android/WorkletsModule.cpp +49 -8
  32. package/android/src/main/cpp/worklets/android/WorkletsModule.h +17 -2
  33. package/android/src/main/java/com/swmansion/worklets/WorkletsPackage.java +1 -1
  34. package/apple/worklets/apple/WorkletsMessageThread.mm +4 -0
  35. package/apple/worklets/apple/WorkletsModule.h +16 -1
  36. package/apple/worklets/apple/WorkletsModule.mm +29 -2
  37. package/bundleMode/index.d.ts +3 -0
  38. package/bundleMode/index.js +55 -0
  39. package/lib/module/PlatformChecker/PlatformChecker.js +8 -0
  40. package/lib/module/PlatformChecker/PlatformChecker.js.map +1 -0
  41. package/lib/module/PlatformChecker/index.js +17 -0
  42. package/lib/module/PlatformChecker/index.js.map +1 -0
  43. package/lib/module/WorkletsError.js +2 -1
  44. package/lib/module/WorkletsError.js.map +1 -1
  45. package/lib/module/WorkletsModule/JSWorklets.js +36 -4
  46. package/lib/module/WorkletsModule/JSWorklets.js.map +1 -1
  47. package/lib/module/WorkletsModule/NativeWorklets.js +35 -15
  48. package/lib/module/WorkletsModule/NativeWorklets.js.map +1 -1
  49. package/lib/module/WorkletsModule/workletsModuleInstance.js +2 -2
  50. package/lib/module/WorkletsModule/workletsModuleInstance.js.map +1 -1
  51. package/lib/module/bundleUnpacker.js +47 -0
  52. package/lib/module/bundleUnpacker.js.map +1 -0
  53. package/lib/module/callGuard.js +30 -0
  54. package/lib/module/callGuard.js.map +1 -0
  55. package/lib/module/errors.js +30 -11
  56. package/lib/module/errors.js.map +1 -1
  57. package/lib/module/index.js +10 -7
  58. package/lib/module/index.js.map +1 -1
  59. package/lib/module/initializers.js +123 -103
  60. package/lib/module/initializers.js.map +1 -1
  61. package/lib/module/logger.js +15 -0
  62. package/lib/module/logger.js.map +1 -0
  63. package/lib/module/privateGlobals.d.js +0 -1
  64. package/lib/module/privateGlobals.d.js.map +1 -1
  65. package/lib/module/publicGlobals.js +5 -0
  66. package/lib/module/publicGlobals.js.map +1 -0
  67. package/lib/module/runLoop/mockedRequestAnimationFrame.js.map +1 -0
  68. package/lib/module/runLoop/requestAnimationFrame.js +50 -0
  69. package/lib/module/runLoop/requestAnimationFrame.js.map +1 -0
  70. package/lib/module/runLoop/setImmediatePolyfill.js +15 -0
  71. package/lib/module/runLoop/setImmediatePolyfill.js.map +1 -0
  72. package/lib/module/runLoop/setIntervalPolyfill.js +26 -0
  73. package/lib/module/runLoop/setIntervalPolyfill.js.map +1 -0
  74. package/lib/module/runLoop/setTimeoutPolyfill.js +32 -0
  75. package/lib/module/runLoop/setTimeoutPolyfill.js.map +1 -0
  76. package/lib/module/runtimes.js +6 -10
  77. package/lib/module/runtimes.js.map +1 -1
  78. package/lib/module/shareableMappingCache.js +1 -3
  79. package/lib/module/shareableMappingCache.js.map +1 -1
  80. package/lib/module/shareables.js +116 -34
  81. package/lib/module/shareables.js.map +1 -1
  82. package/lib/module/specs/index.js +2 -2
  83. package/lib/module/specs/index.js.map +1 -1
  84. package/lib/module/threads.js +49 -54
  85. package/lib/module/threads.js.map +1 -1
  86. package/lib/module/valueUnpacker.js +3 -3
  87. package/lib/module/valueUnpacker.js.map +1 -1
  88. package/lib/module/workletRuntimeEntry.js +30 -0
  89. package/lib/module/workletRuntimeEntry.js.map +1 -0
  90. package/lib/typescript/PlatformChecker/PlatformChecker.d.ts +5 -0
  91. package/lib/typescript/PlatformChecker/PlatformChecker.d.ts.map +1 -0
  92. package/lib/typescript/PlatformChecker/index.d.ts +10 -0
  93. package/lib/typescript/PlatformChecker/index.d.ts.map +1 -0
  94. package/lib/typescript/WorkletsError.d.ts.map +1 -1
  95. package/lib/typescript/WorkletsModule/JSWorklets.d.ts.map +1 -1
  96. package/lib/typescript/WorkletsModule/NativeWorklets.d.ts +1 -3
  97. package/lib/typescript/WorkletsModule/NativeWorklets.d.ts.map +1 -1
  98. package/lib/typescript/WorkletsModule/workletsModuleInstance.d.ts +1 -1
  99. package/lib/typescript/WorkletsModule/workletsModuleInstance.d.ts.map +1 -1
  100. package/lib/typescript/WorkletsModule/workletsModuleInstance.web.d.ts +1 -1
  101. package/lib/typescript/WorkletsModule/workletsModuleInstance.web.d.ts.map +1 -1
  102. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts +12 -2
  103. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts.map +1 -1
  104. package/lib/typescript/bundleUnpacker.d.ts +7 -0
  105. package/lib/typescript/bundleUnpacker.d.ts.map +1 -0
  106. package/lib/typescript/callGuard.d.ts +4 -0
  107. package/lib/typescript/callGuard.d.ts.map +1 -0
  108. package/lib/typescript/errors.d.ts +13 -5
  109. package/lib/typescript/errors.d.ts.map +1 -1
  110. package/lib/typescript/index.d.ts +1 -2
  111. package/lib/typescript/index.d.ts.map +1 -1
  112. package/lib/typescript/initializers.d.ts +16 -5
  113. package/lib/typescript/initializers.d.ts.map +1 -1
  114. package/lib/typescript/logger.d.ts +5 -0
  115. package/lib/typescript/logger.d.ts.map +1 -0
  116. package/lib/typescript/publicGlobals.d.ts +22 -0
  117. package/lib/typescript/publicGlobals.d.ts.map +1 -0
  118. package/lib/typescript/runLoop/mockedRequestAnimationFrame.d.ts.map +1 -0
  119. package/lib/typescript/runLoop/requestAnimationFrame.d.ts.map +1 -0
  120. package/lib/typescript/runLoop/setImmediatePolyfill.d.ts +2 -0
  121. package/lib/typescript/runLoop/setImmediatePolyfill.d.ts.map +1 -0
  122. package/lib/typescript/runLoop/setIntervalPolyfill.d.ts +2 -0
  123. package/lib/typescript/runLoop/setIntervalPolyfill.d.ts.map +1 -0
  124. package/lib/typescript/runLoop/setTimeoutPolyfill.d.ts +2 -0
  125. package/lib/typescript/runLoop/setTimeoutPolyfill.d.ts.map +1 -0
  126. package/lib/typescript/runtimes.d.ts.map +1 -1
  127. package/lib/typescript/shareableMappingCache.d.ts.map +1 -1
  128. package/lib/typescript/shareables.d.ts +3 -2
  129. package/lib/typescript/shareables.d.ts.map +1 -1
  130. package/lib/typescript/specs/NativeWorkletsModule.d.ts +1 -1
  131. package/lib/typescript/specs/NativeWorkletsModule.d.ts.map +1 -1
  132. package/lib/typescript/specs/index.d.ts +2 -2
  133. package/lib/typescript/specs/index.d.ts.map +1 -1
  134. package/lib/typescript/threads.d.ts.map +1 -1
  135. package/lib/typescript/workletRuntimeEntry.d.ts +14 -0
  136. package/lib/typescript/workletRuntimeEntry.d.ts.map +1 -0
  137. package/lib/typescript/workletTypes.d.ts +14 -3
  138. package/lib/typescript/workletTypes.d.ts.map +1 -1
  139. package/package.json +17 -8
  140. package/plugin/index.js +145 -52
  141. package/scripts/worklets_utils.rb +9 -0
  142. package/src/PlatformChecker/PlatformChecker.ts +7 -0
  143. package/src/PlatformChecker/index.ts +29 -0
  144. package/src/WorkletsError.ts +2 -1
  145. package/src/WorkletsModule/JSWorklets.ts +71 -4
  146. package/src/WorkletsModule/NativeWorklets.ts +83 -21
  147. package/src/WorkletsModule/workletsModuleInstance.ts +2 -2
  148. package/src/WorkletsModule/workletsModuleProxy.ts +49 -1
  149. package/src/bundleUnpacker.ts +75 -0
  150. package/src/callGuard.ts +33 -0
  151. package/src/errors.ts +35 -18
  152. package/src/index.ts +12 -12
  153. package/src/initializers.ts +143 -113
  154. package/src/logger.ts +16 -0
  155. package/src/privateGlobals.d.ts +22 -6
  156. package/src/publicGlobals.ts +26 -0
  157. package/src/runLoop/requestAnimationFrame.ts +67 -0
  158. package/src/runLoop/setImmediatePolyfill.ts +20 -0
  159. package/src/runLoop/setIntervalPolyfill.ts +38 -0
  160. package/src/runLoop/setTimeoutPolyfill.ts +40 -0
  161. package/src/runtimes.ts +6 -11
  162. package/src/shareableMappingCache.ts +1 -3
  163. package/src/shareables.ts +179 -65
  164. package/src/specs/NativeWorkletsModule.ts +1 -1
  165. package/src/specs/index.ts +5 -2
  166. package/src/threads.ts +75 -65
  167. package/src/valueUnpacker.ts +3 -3
  168. package/src/workletRuntimeEntry.ts +30 -0
  169. package/src/workletTypes.ts +22 -5
  170. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.cpp +0 -139
  171. package/Common/cpp/worklets/NativeModules/WorkletsModuleProxySpec.h +0 -61
  172. package/android/src/paper/com/swmansion/worklets/NativeWorkletsModuleSpec.java +0 -26
  173. package/lib/module/PlatformChecker.js +0 -26
  174. package/lib/module/PlatformChecker.js.map +0 -1
  175. package/lib/module/animationFrameQueue/mockedRequestAnimationFrame.js.map +0 -1
  176. package/lib/module/animationFrameQueue/requestAnimationFrame.js +0 -36
  177. package/lib/module/animationFrameQueue/requestAnimationFrame.js.map +0 -1
  178. package/lib/module/logger/LogBox.js +0 -15
  179. package/lib/module/logger/LogBox.js.map +0 -1
  180. package/lib/module/logger/index.js +0 -5
  181. package/lib/module/logger/index.js.map +0 -1
  182. package/lib/module/logger/logger.js +0 -137
  183. package/lib/module/logger/logger.js.map +0 -1
  184. package/lib/typescript/PlatformChecker.d.ts +0 -6
  185. package/lib/typescript/PlatformChecker.d.ts.map +0 -1
  186. package/lib/typescript/animationFrameQueue/mockedRequestAnimationFrame.d.ts.map +0 -1
  187. package/lib/typescript/animationFrameQueue/requestAnimationFrame.d.ts.map +0 -1
  188. package/lib/typescript/logger/LogBox.d.ts +0 -32
  189. package/lib/typescript/logger/LogBox.d.ts.map +0 -1
  190. package/lib/typescript/logger/index.d.ts +0 -3
  191. package/lib/typescript/logger/index.d.ts.map +0 -1
  192. package/lib/typescript/logger/logger.d.ts +0 -52
  193. package/lib/typescript/logger/logger.d.ts.map +0 -1
  194. package/src/PlatformChecker.ts +0 -30
  195. package/src/animationFrameQueue/requestAnimationFrame.ts +0 -41
  196. package/src/logger/LogBox.ts +0 -55
  197. package/src/logger/index.ts +0 -3
  198. package/src/logger/logger.ts +0 -155
  199. /package/lib/module/{animationFrameQueue → runLoop}/mockedRequestAnimationFrame.js +0 -0
  200. /package/lib/typescript/{animationFrameQueue → runLoop}/mockedRequestAnimationFrame.d.ts +0 -0
  201. /package/lib/typescript/{animationFrameQueue → runLoop}/requestAnimationFrame.d.ts +0 -0
  202. /package/src/{animationFrameQueue → runLoop}/mockedRequestAnimationFrame.ts +0 -0
package/src/shareables.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  import { registerWorkletStackDetails } from './errors';
3
3
  import { logger } from './logger';
4
- import { shouldBeUseWeb } from './PlatformChecker';
4
+ import { SHOULD_BE_USE_WEB } from './PlatformChecker';
5
5
  import {
6
6
  shareableMappingCache,
7
7
  shareableMappingFlag,
@@ -13,13 +13,13 @@ import type {
13
13
  FlatShareableRef,
14
14
  ShareableRef,
15
15
  WorkletFunction,
16
+ WorkletImport,
16
17
  } from './workletTypes';
17
18
 
18
19
  // for web and jest environments this file provides a stub implementation
19
20
  // where no shareable references are used. Instead, the objects themselves are used
20
21
  // instead of shareable references, because of the fact that we don't have to deal with
21
22
  // running the code on separate VMs.
22
- const SHOULD_BE_USE_WEB = shouldBeUseWeb();
23
23
 
24
24
  const MAGIC_KEY = 'REANIMATED_MAGIC_KEY';
25
25
 
@@ -33,9 +33,14 @@ function isHostObject(value: NonNullable<object>) {
33
33
  }
34
34
 
35
35
  function isPlainJSObject(object: object): object is Record<string, unknown> {
36
+ 'worklet';
36
37
  return Object.getPrototypeOf(object) === Object.prototype;
37
38
  }
38
39
 
40
+ function isTurboModuleLike(object: object): object is Record<string, unknown> {
41
+ return isHostObject(Object.getPrototypeOf(object));
42
+ }
43
+
39
44
  function getFromCache(value: object) {
40
45
  const cached = shareableMappingCache.get(value);
41
46
  if (cached === shareableMappingFlag) {
@@ -159,11 +164,30 @@ function makeShareableCloneRecursiveNative<T>(
159
164
  if (Array.isArray(value)) {
160
165
  return cloneArray(value, shouldPersistRemote, depth);
161
166
  }
167
+ if (
168
+ globalThis._WORKLETS_BUNDLE_MODE &&
169
+ isFunction &&
170
+ (value as WorkletImport).__bundleData
171
+ ) {
172
+ return cloneImport(value as WorkletImport) as ShareableRef<T>;
173
+ }
162
174
  if (isFunction && !isWorkletFunction(value)) {
163
- return cloneRemoteFunction(value, shouldPersistRemote);
175
+ return cloneRemoteFunction(value);
176
+ }
177
+ // RN has introduced a new representation of TurboModules as a JS object whose prototype is the host object
178
+ // More details: https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/nativemodule/core/ReactCommon/TurboModuleBinding.cpp#L182
179
+ if (isTurboModuleLike(value)) {
180
+ return cloneTurboModuleLike(value, shouldPersistRemote, depth);
164
181
  }
165
182
  if (isHostObject(value)) {
166
- return cloneHostObject(value, shouldPersistRemote);
183
+ return cloneHostObject(value);
184
+ }
185
+ if (isPlainJSObject(value) && value.__init) {
186
+ return cloneInitializer(
187
+ value,
188
+ shouldPersistRemote,
189
+ depth
190
+ ) as ShareableRef<T>;
167
191
  }
168
192
  if (isPlainJSObject(value) && value.__workletContextObjectFactory) {
169
193
  return cloneContextObject(value);
@@ -174,6 +198,12 @@ function makeShareableCloneRecursiveNative<T>(
174
198
  if (isPlainJSObject(value) || isFunction) {
175
199
  return clonePlainJSObject(value, shouldPersistRemote, depth);
176
200
  }
201
+ if (value instanceof Set) {
202
+ return cloneSet(value);
203
+ }
204
+ if (value instanceof Map) {
205
+ return cloneMap(value);
206
+ }
177
207
  if (value instanceof RegExp) {
178
208
  return cloneRegExp(value);
179
209
  }
@@ -190,7 +220,16 @@ function makeShareableCloneRecursiveNative<T>(
190
220
  return inaccessibleObject(value);
191
221
  }
192
222
 
193
- export interface MakeShareableClone {
223
+ if (globalThis._WORKLETS_BUNDLE_MODE) {
224
+ // TODO: Do it programatically.
225
+ makeShareableCloneRecursiveNative.__bundleData = {
226
+ imported: 'makeShareableCloneRecursive',
227
+ // @ts-expect-error resolveWeak is defined by Metro
228
+ source: require.resolveWeak('./index'),
229
+ };
230
+ }
231
+
232
+ interface MakeShareableClone {
194
233
  <T>(value: T, shouldPersistRemote?: boolean, depth?: number): ShareableRef<T>;
195
234
  }
196
235
 
@@ -248,6 +287,41 @@ function cloneNull(): ShareableRef<null> {
248
287
  return WorkletsModule.makeShareableNull();
249
288
  }
250
289
 
290
+ function cloneObjectProperties<T extends object>(
291
+ value: T,
292
+ shouldPersistRemote: boolean,
293
+ depth: number
294
+ ): Record<string, unknown> {
295
+ const clonedProps: Record<string, unknown> = {};
296
+ for (const [key, element] of Object.entries(value)) {
297
+ // We don't need to clone __initData field as it contains long strings
298
+ // representing the worklet code, source map, and location, and we will
299
+ // serialize/deserialize it once.
300
+ if (key === '__initData' && clonedProps.__initData !== undefined) {
301
+ continue;
302
+ }
303
+ clonedProps[key] = makeShareableCloneRecursive(
304
+ element,
305
+ shouldPersistRemote,
306
+ depth + 1
307
+ );
308
+ }
309
+ return clonedProps;
310
+ }
311
+
312
+ function cloneInitializer(
313
+ value: object,
314
+ shouldPersistRemote = false,
315
+ depth = 0
316
+ ): ShareableRef<object> {
317
+ const clonedProps: Record<string, unknown> = cloneObjectProperties(
318
+ value,
319
+ shouldPersistRemote,
320
+ depth
321
+ );
322
+ return WorkletsModule.makeShareableInitializer(clonedProps);
323
+ }
324
+
251
325
  function cloneArray<T extends unknown[]>(
252
326
  value: T,
253
327
  shouldPersistRemote: boolean,
@@ -256,10 +330,9 @@ function cloneArray<T extends unknown[]>(
256
330
  const clonedElements = value.map((element) =>
257
331
  makeShareableCloneRecursive(element, shouldPersistRemote, depth + 1)
258
332
  );
259
- const clone = WorkletsModule.makeShareableClone(
333
+ const clone = WorkletsModule.makeShareableArray(
260
334
  clonedElements,
261
- shouldPersistRemote,
262
- value
335
+ shouldPersistRemote
263
336
  ) as ShareableRef<T>;
264
337
  shareableMappingCache.set(value, clone);
265
338
  shareableMappingCache.set(clone);
@@ -268,15 +341,10 @@ function cloneArray<T extends unknown[]>(
268
341
  return clone;
269
342
  }
270
343
 
271
- function cloneRemoteFunction<T extends object>(
272
- value: T,
273
- shouldPersistRemote: boolean
274
- ): ShareableRef<T> {
275
- const clone = WorkletsModule.makeShareableClone(
276
- value,
277
- shouldPersistRemote,
278
- value
279
- );
344
+ function cloneRemoteFunction<TArgs extends unknown[], TReturn>(
345
+ value: (...args: TArgs) => TReturn
346
+ ): ShareableRef<TReturn> {
347
+ const clone = WorkletsModule.makeShareableFunction(value);
280
348
  shareableMappingCache.set(value, clone);
281
349
  shareableMappingCache.set(clone);
282
350
 
@@ -284,18 +352,11 @@ function cloneRemoteFunction<T extends object>(
284
352
  return clone;
285
353
  }
286
354
 
287
- function cloneHostObject<T extends object>(
288
- value: T,
289
- shouldPersistRemote: boolean
290
- ): ShareableRef<T> {
355
+ function cloneHostObject<T extends object>(value: T): ShareableRef<T> {
291
356
  // for host objects we pass the reference to the object as shareable and
292
357
  // then recreate new host object wrapping the same instance on the UI thread.
293
358
  // there is no point of iterating over keys as we do for regular objects.
294
- const clone = WorkletsModule.makeShareableClone(
295
- value,
296
- shouldPersistRemote,
297
- value
298
- );
359
+ const clone = WorkletsModule.makeShareableHostObject(value);
299
360
  shareableMappingCache.set(value, clone);
300
361
  shareableMappingCache.set(clone);
301
362
 
@@ -327,33 +388,27 @@ function cloneWorklet<T extends WorkletFunction>(
327
388
  // seems more elegant to handle it this way.
328
389
  delete (value as WorkletFunction).__stackDetails;
329
390
  }
391
+ const clonedProps: Record<string, unknown> = cloneObjectProperties(
392
+ value,
393
+ true,
394
+ depth
395
+ );
330
396
  // to save on transferring static __initData field of worklet structure
331
397
  // we request shareable value to persist its UI counterpart. This means
332
- // that the __initData field that contains long strings represeting the
398
+ // that the __initData field that contains long strings representing the
333
399
  // worklet code, source map, and location, will always be
334
400
  // serialized/deserialized once.
335
- const clonedProps: Record<string, unknown> = {};
336
401
  clonedProps.__initData = makeShareableCloneRecursive(
337
402
  value.__initData,
338
403
  true,
339
404
  depth + 1
340
405
  );
341
406
 
342
- for (const [key, element] of Object.entries(value)) {
343
- if (key === '__initData' && clonedProps.__initData !== undefined) {
344
- continue;
345
- }
346
- clonedProps[key] = makeShareableCloneRecursive(
347
- element,
348
- shouldPersistRemote,
349
- depth + 1
350
- );
351
- }
352
- const clone = WorkletsModule.makeShareableClone(
407
+ const clone = WorkletsModule.makeShareableWorklet(
353
408
  clonedProps,
409
+ // TODO: Check after refactor if we can remove shouldPersistRemote parameter (imho it's redundant here since worklets are always persistent)
354
410
  // retain all worklets
355
- true,
356
- value
411
+ true
357
412
  ) as ShareableRef<T>;
358
413
  shareableMappingCache.set(value, clone);
359
414
  shareableMappingCache.set(clone);
@@ -362,10 +417,28 @@ function cloneWorklet<T extends WorkletFunction>(
362
417
  return clone;
363
418
  }
364
419
 
420
+ /**
421
+ * TurboModuleLike objects are JS objects that have a TurboModule as their
422
+ * prototype.
423
+ */
424
+ function cloneTurboModuleLike<T extends object>(
425
+ value: T,
426
+ shouldPersistRemote: boolean,
427
+ depth: number
428
+ ): ShareableRef<T> {
429
+ const proto = Object.getPrototypeOf(value);
430
+ const clonedProps = cloneObjectProperties(value, shouldPersistRemote, depth);
431
+ const clone = WorkletsModule.makeShareableTurboModuleLike(
432
+ clonedProps,
433
+ proto
434
+ ) as ShareableRef<T>;
435
+ return clone;
436
+ }
437
+
365
438
  function cloneContextObject<T extends object>(value: T): ShareableRef<T> {
366
439
  const workletContextObjectFactory = (value as Record<string, unknown>)
367
440
  .__workletContextObjectFactory as () => T;
368
- const handle = makeShareableCloneRecursive({
441
+ const handle = cloneInitializer({
369
442
  __init: () => {
370
443
  'worklet';
371
444
  return workletContextObjectFactory();
@@ -380,18 +453,12 @@ function clonePlainJSObject<T extends object>(
380
453
  shouldPersistRemote: boolean,
381
454
  depth: number
382
455
  ): ShareableRef<T> {
383
- const clonedProps: Record<string, unknown> = {};
384
- for (const [key, element] of Object.entries(value)) {
385
- if (key === '__initData' && clonedProps.__initData !== undefined) {
386
- continue;
387
- }
388
- clonedProps[key] = makeShareableCloneRecursive(
389
- element,
390
- shouldPersistRemote,
391
- depth + 1
392
- );
393
- }
394
- const clone = WorkletsModule.makeShareableClone(
456
+ const clonedProps: Record<string, unknown> = cloneObjectProperties(
457
+ value,
458
+ shouldPersistRemote,
459
+ depth
460
+ );
461
+ const clone = WorkletsModule.makeShareableObject(
395
462
  clonedProps,
396
463
  shouldPersistRemote,
397
464
  value
@@ -403,10 +470,43 @@ function clonePlainJSObject<T extends object>(
403
470
  return clone;
404
471
  }
405
472
 
473
+ function cloneMap<T extends Map<unknown, unknown>>(value: T): ShareableRef<T> {
474
+ const clonedKeys: unknown[] = [];
475
+ const clonedValues: unknown[] = [];
476
+ for (const [key, element] of value.entries()) {
477
+ clonedKeys.push(makeShareableCloneRecursive(key));
478
+ clonedValues.push(makeShareableCloneRecursive(element));
479
+ }
480
+ const clone = WorkletsModule.makeShareableMap(
481
+ clonedKeys,
482
+ clonedValues
483
+ ) as ShareableRef<T>;
484
+ shareableMappingCache.set(value, clone);
485
+ shareableMappingCache.set(clone);
486
+
487
+ freezeObjectInDev(value);
488
+ return clone;
489
+ }
490
+
491
+ function cloneSet<T extends Set<unknown>>(value: T): ShareableRef<T> {
492
+ const clonedElements: unknown[] = [];
493
+ for (const element of value) {
494
+ clonedElements.push(makeShareableCloneRecursive(element));
495
+ }
496
+ const clone = WorkletsModule.makeShareableSet(
497
+ clonedElements
498
+ ) as ShareableRef<T>;
499
+ shareableMappingCache.set(value, clone);
500
+ shareableMappingCache.set(clone);
501
+
502
+ freezeObjectInDev(value);
503
+ return clone;
504
+ }
505
+
406
506
  function cloneRegExp<T extends RegExp>(value: T): ShareableRef<T> {
407
507
  const pattern = value.source;
408
508
  const flags = value.flags;
409
- const handle = makeShareableCloneRecursive({
509
+ const handle = cloneInitializer({
410
510
  __init: () => {
411
511
  'worklet';
412
512
  return new RegExp(pattern, flags);
@@ -419,7 +519,7 @@ function cloneRegExp<T extends RegExp>(value: T): ShareableRef<T> {
419
519
 
420
520
  function cloneError<T extends Error>(value: T): ShareableRef<T> {
421
521
  const { name, message, stack } = value;
422
- const handle = makeShareableCloneRecursive({
522
+ const handle = cloneInitializer({
423
523
  __init: () => {
424
524
  'worklet';
425
525
  // eslint-disable-next-line reanimated/use-worklets-error
@@ -454,7 +554,7 @@ function cloneArrayBufferView<T extends ArrayBufferView>(
454
554
  ): ShareableRef<T> {
455
555
  const buffer = value.buffer;
456
556
  const typeName = value.constructor.name;
457
- const handle = makeShareableCloneRecursive({
557
+ const handle = cloneInitializer({
458
558
  __init: () => {
459
559
  'worklet';
460
560
  if (!VALID_ARRAY_VIEWS_NAMES.includes(typeName)) {
@@ -472,6 +572,18 @@ function cloneArrayBufferView<T extends ArrayBufferView>(
472
572
  return handle;
473
573
  }
474
574
 
575
+ function cloneImport<TValue extends WorkletImport>(
576
+ value: TValue
577
+ ): ShareableRef<TValue> {
578
+ const { source, imported } = value.__bundleData;
579
+ const clone = WorkletsModule.makeShareableImport(source, imported);
580
+
581
+ shareableMappingCache.set(value, clone);
582
+ shareableMappingCache.set(clone);
583
+
584
+ return clone as ShareableRef<TValue>;
585
+ }
586
+
475
587
  function inaccessibleObject<T extends object>(value: T): ShareableRef<T> {
476
588
  // This is reached for object types that are not of plain Object.prototype.
477
589
  // We don't support such objects from being transferred as shareables to
@@ -550,7 +662,7 @@ function freezeObjectInDev<T extends object>(value: T) {
550
662
  Object.preventExtensions(value);
551
663
  }
552
664
 
553
- export function makeShareableCloneOnUIRecursive<T>(
665
+ function makeShareableCloneOnUIRecursiveLEGACY<T>(
554
666
  value: T
555
667
  ): FlatShareableRef<T> {
556
668
  'worklet';
@@ -568,10 +680,7 @@ export function makeShareableCloneOnUIRecursive<T>(
568
680
  if (isHostObject(value)) {
569
681
  // We call `_makeShareableClone` to wrap the provided HostObject
570
682
  // inside ShareableJSRef.
571
- return global._makeShareableClone(
572
- value,
573
- undefined
574
- ) as FlatShareableRef<T>;
683
+ return global._makeShareableHostObject(value) as FlatShareableRef<T>;
575
684
  }
576
685
  if (isRemoteFunction<T>(value)) {
577
686
  // RemoteFunctions are created by us therefore they are
@@ -580,9 +689,8 @@ export function makeShareableCloneOnUIRecursive<T>(
580
689
  return value.__remoteFunction;
581
690
  }
582
691
  if (Array.isArray(value)) {
583
- return global._makeShareableClone(
584
- value.map(cloneRecursive),
585
- undefined
692
+ return global._makeShareableArray(
693
+ value.map(cloneRecursive)
586
694
  ) as FlatShareableRef<T>;
587
695
  }
588
696
  const toAdapt: Record<string, FlatShareableRef<T>> = {};
@@ -621,6 +729,12 @@ export function makeShareableCloneOnUIRecursive<T>(
621
729
  return cloneRecursive(value);
622
730
  }
623
731
 
732
+ export const makeShareableCloneOnUIRecursive = (
733
+ globalThis._WORKLETS_BUNDLE_MODE
734
+ ? makeShareableCloneRecursive
735
+ : makeShareableCloneOnUIRecursiveLEGACY
736
+ ) as typeof makeShareableCloneOnUIRecursiveLEGACY;
737
+
624
738
  function makeShareableJS<T extends object>(value: T): T {
625
739
  return value;
626
740
  }
@@ -2,7 +2,7 @@
2
2
  import type { TurboModule } from 'react-native';
3
3
  import { TurboModuleRegistry } from 'react-native';
4
4
 
5
- interface Spec extends TurboModule {
5
+ export interface Spec extends TurboModule {
6
6
  installTurboModule: () => boolean;
7
7
  }
8
8
 
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
- import WorkletsTurboModule from './NativeWorkletsModule';
3
+ import type { Spec } from './NativeWorkletsModule';
4
+ import RNWorkletsTurboModule from './NativeWorkletsModule';
4
5
 
5
- export { WorkletsTurboModule };
6
+ export const WorkletsTurboModule: Spec | null = globalThis._WORKLET
7
+ ? null
8
+ : RNWorkletsTurboModule;
package/src/threads.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
- import { isJest, shouldBeUseWeb } from './PlatformChecker';
2
+ import { IS_JEST, SHOULD_BE_USE_WEB } from './PlatformChecker';
3
+ import { shareableMappingCache } from './shareableMappingCache';
3
4
  import {
4
5
  makeShareableCloneOnUIRecursive,
5
6
  makeShareableCloneRecursive,
@@ -7,15 +8,15 @@ import {
7
8
  import { isWorkletFunction } from './workletFunction';
8
9
  import { WorkletsError } from './WorkletsError';
9
10
  import { WorkletsModule } from './WorkletsModule';
10
- import type { WorkletFunction } from './workletTypes';
11
+ import type { WorkletFunction, WorkletImport } from './workletTypes';
11
12
 
12
- const IS_JEST = isJest();
13
- const SHOULD_BE_USE_WEB = shouldBeUseWeb();
13
+ type UIJob<Args extends unknown[] = unknown[], ReturnValue = unknown> = [
14
+ worklet: WorkletFunction<Args, ReturnValue>,
15
+ args: Args,
16
+ resolve?: (value: ReturnValue) => void,
17
+ ];
14
18
 
15
- /** An array of [worklet, args, resolve (optional)] pairs. */
16
- let _runOnUIQueue: Array<
17
- [WorkletFunction<unknown[], unknown>, unknown[], ((value: unknown) => void)?]
18
- > = [];
19
+ let runOnUIQueue: UIJob[] = [];
19
20
 
20
21
  export function setupMicrotasks() {
21
22
  'worklet';
@@ -84,13 +85,12 @@ export function runOnUI<Args extends unknown[], ReturnValue>(
84
85
  export function runOnUI<Args extends unknown[], ReturnValue>(
85
86
  worklet: WorkletFunction<Args, ReturnValue>
86
87
  ): (...args: Args) => void {
87
- 'worklet';
88
- if (__DEV__ && !SHOULD_BE_USE_WEB && globalThis._WORKLET) {
89
- throw new WorkletsError(
90
- '`runOnUI` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
91
- );
92
- }
93
- if (__DEV__ && !SHOULD_BE_USE_WEB && !isWorkletFunction(worklet)) {
88
+ if (
89
+ __DEV__ &&
90
+ !SHOULD_BE_USE_WEB &&
91
+ !isWorkletFunction(worklet) &&
92
+ !(worklet as unknown as WorkletImport).__bundleData
93
+ ) {
94
94
  throw new WorkletsError('`runOnUI` can only be used with worklets.');
95
95
  }
96
96
  return (...args) => {
@@ -121,26 +121,23 @@ export function runOnUI<Args extends unknown[], ReturnValue>(
121
121
  makeShareableCloneRecursive(worklet);
122
122
  makeShareableCloneRecursive(args);
123
123
  }
124
- _runOnUIQueue.push([worklet as WorkletFunction, args]);
125
- if (_runOnUIQueue.length === 1) {
126
- queueMicrotask(() => {
127
- const queue = _runOnUIQueue;
128
- _runOnUIQueue = [];
129
- WorkletsModule.scheduleOnUI(
130
- makeShareableCloneRecursive(() => {
131
- 'worklet';
132
- // eslint-disable-next-line @typescript-eslint/no-shadow
133
- queue.forEach(([worklet, args]) => {
134
- worklet(...args);
135
- });
136
- callMicrotasks();
137
- })
138
- );
139
- });
140
- }
124
+
125
+ enqueueUI(worklet, args);
141
126
  };
142
127
  }
143
128
 
129
+ if (__DEV__) {
130
+ function runOnUIWorklet(): void {
131
+ 'worklet';
132
+ throw new WorkletsError(
133
+ '`runOnUI` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
134
+ );
135
+ }
136
+
137
+ const shareableRunOnUIWorklet = makeShareableCloneRecursive(runOnUIWorklet);
138
+ shareableMappingCache.set(runOnUI, shareableRunOnUIWorklet);
139
+ }
140
+
144
141
  // @ts-expect-error Check `executeOnUIRuntimeSync` overload above.
145
142
  export function executeOnUIRuntimeSync<Args extends unknown[], ReturnValue>(
146
143
  worklet: (...args: Args) => ReturnValue
@@ -239,10 +236,7 @@ export function runOnJS<Args extends unknown[], ReturnValue>(
239
236
  fun as
240
237
  | ((...args: Args) => ReturnValue)
241
238
  | WorkletFunction<Args, ReturnValue>,
242
- args.length > 0
243
- ? // TODO TYPESCRIPT this cast is terrible but will be fixed
244
- (makeShareableCloneOnUIRecursive(args) as unknown as unknown[])
245
- : undefined
239
+ args.length > 0 ? makeShareableCloneOnUIRecursive(args) : undefined
246
240
  );
247
241
  };
248
242
  }
@@ -269,12 +263,6 @@ export function runOnJS<Args extends unknown[], ReturnValue>(
269
263
  export function runOnUIAsync<Args extends unknown[], ReturnValue>(
270
264
  worklet: (...args: Args) => ReturnValue
271
265
  ): (...args: Args) => Promise<ReturnValue> {
272
- 'worklet';
273
- if (__DEV__ && !SHOULD_BE_USE_WEB && globalThis._WORKLET) {
274
- throw new WorkletsError(
275
- '`runOnUIAsync` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
276
- );
277
- }
278
266
  if (__DEV__ && !SHOULD_BE_USE_WEB && !isWorkletFunction(worklet)) {
279
267
  throw new WorkletsError('`runOnUIAsync` can only be used with worklets.');
280
268
  }
@@ -308,29 +296,51 @@ export function runOnUIAsync<Args extends unknown[], ReturnValue>(
308
296
  makeShareableCloneRecursive(args);
309
297
  }
310
298
 
311
- _runOnUIQueue.push([
312
- worklet as WorkletFunction,
313
- args,
314
- resolve as (value: unknown) => void,
315
- ]);
316
- if (_runOnUIQueue.length === 1) {
317
- queueMicrotask(() => {
318
- const queue = _runOnUIQueue.slice();
319
- _runOnUIQueue = [];
320
- WorkletsModule.scheduleOnUI(
321
- makeShareableCloneRecursive(() => {
322
- 'worklet';
323
- queue.forEach(([workletFunction, workletArgs, jobResolve]) => {
324
- const result = workletFunction(...workletArgs);
325
- if (jobResolve) {
326
- runOnJS(jobResolve)(result);
327
- }
328
- });
329
- callMicrotasks();
330
- })
331
- );
332
- });
333
- }
299
+ enqueueUI(worklet as WorkletFunction<Args, ReturnValue>, args, resolve);
334
300
  });
335
301
  };
336
302
  }
303
+
304
+ if (__DEV__) {
305
+ function runOnUIAsyncWorklet(): void {
306
+ 'worklet';
307
+ throw new WorkletsError(
308
+ '`runOnUIAsync` cannot be called on the UI runtime. Please call the function synchronously or use `queueMicrotask` or `requestAnimationFrame` instead.'
309
+ );
310
+ }
311
+
312
+ const shareableRunOnUIAsyncWorklet =
313
+ makeShareableCloneRecursive(runOnUIAsyncWorklet);
314
+ shareableMappingCache.set(runOnUIAsync, shareableRunOnUIAsyncWorklet);
315
+ }
316
+
317
+ function enqueueUI<Args extends unknown[], ReturnValue>(
318
+ worklet: WorkletFunction<Args, ReturnValue>,
319
+ args: Args,
320
+ resolve?: (value: ReturnValue) => void
321
+ ): void {
322
+ const job = [worklet, args, resolve] as UIJob<Args, ReturnValue>;
323
+ runOnUIQueue.push(job as unknown as UIJob);
324
+ if (runOnUIQueue.length === 1) {
325
+ flushUIQueue();
326
+ }
327
+ }
328
+
329
+ function flushUIQueue(): void {
330
+ queueMicrotask(() => {
331
+ const queue = runOnUIQueue;
332
+ runOnUIQueue = [];
333
+ WorkletsModule.scheduleOnUI(
334
+ makeShareableCloneRecursive(() => {
335
+ 'worklet';
336
+ queue.forEach(([workletFunction, workletArgs, jobResolve]) => {
337
+ const result = workletFunction(...workletArgs);
338
+ if (jobResolve) {
339
+ runOnJS(jobResolve)(result);
340
+ }
341
+ });
342
+ callMicrotasks();
343
+ })
344
+ );
345
+ });
346
+ }
@@ -1,8 +1,6 @@
1
- /* eslint-disable reanimated/use-worklets-error */
2
1
  'use strict';
3
2
  import type { WorkletFunction } from './workletTypes';
4
3
 
5
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
6
4
  function __valueUnpacker(
7
5
  objectToUnpack: ObjectToUnpack,
8
6
  category?: string,
@@ -62,14 +60,16 @@ function __valueUnpacker(
62
60
  const label = remoteFunctionName
63
61
  ? `function \`${remoteFunctionName}\``
64
62
  : 'anonymous function';
63
+ // eslint-disable-next-line reanimated/use-worklets-error
65
64
  throw new Error(`[Worklets] Tried to synchronously call a non-worklet ${label} on the UI thread.
66
65
  See https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#tried-to-synchronously-call-a-non-worklet-function-on-the-ui-thread for more details.`);
67
66
  };
68
67
  fun.__remoteFunction = objectToUnpack;
69
68
  return fun;
70
69
  } else {
70
+ // eslint-disable-next-line reanimated/use-worklets-error
71
71
  throw new Error(
72
- `[Worklets] Data type in category "${category}" not recognized by value unpacker: "${_toString(
72
+ `[Worklets] Data type in category "${category}" not recognized by value unpacker: "${globalThis._toString(
73
73
  objectToUnpack
74
74
  )}".`
75
75
  );
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ import { init } from './initializers';
4
+ import { WorkletsError } from './WorkletsError';
5
+
6
+ /**
7
+ * This function is an entry point for Worklet Runtimes. We can use it to setup
8
+ * necessary tools, like the ValueUnpacker.
9
+ *
10
+ * We must throw an error at the end of this function to prevent the bundle to
11
+ * continue executing. This is because the next module to be ran would be the
12
+ * React Native one, and it would break the Worklet Runtime if initialized. The
13
+ * error is caught in C++ code.
14
+ *
15
+ * This function has no effect on the RN Runtime beside setting the
16
+ * `_WORKLETS_BUNDLE_MODE` flag.
17
+ */
18
+ export function bundleModeInit() {
19
+ globalThis._WORKLETS_BUNDLE_MODE = true;
20
+ if (globalThis._WORKLET) {
21
+ /**
22
+ * We shouldn't call `init()` on RN Runtime here, as it would initialize our
23
+ * module before React Native has configured the RN Runtime.
24
+ */
25
+ init();
26
+ throw new WorkletsError('Worklets initialized successfully');
27
+ }
28
+ }
29
+
30
+ bundleModeInit();