feat(Worklets): experimental public RNWorklets headers
Summary
Requires:
- #8678
- #8683
- #8684
- #8685
Currently we don't denote what headers are public and what are private in worklets. While the sole distinction is out of scope of this PR and something for the future, we could implement how the user is supposed to import them.
iOS (Cocoapods)
With Cocoapods the issue is quite straightforward. Running pod install will create a directory Pods/Headers with the following structure (only RNWorklets included), having Public and Private dirs:
.
├── Private
│ └── RNWorklets
│ └── worklets
│ ├── AnimationFrameQueue
│ │ └── AnimationFrameBatchinator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.h
│ ├── apple
│ │ ├── AnimationFrameQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AnimationFrameQueue.h
│ │ ├── AssertJavaScriptQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AssertJavaScriptQueue.h
│ │ ├── AssertTurboModuleManagerQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AssertTurboModuleManagerQueue.h
│ │ ├── IOSUIScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/IOSUIScheduler.h
│ │ ├── SlowAnimations.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/SlowAnimations.h
│ │ ├── WorkletsDisplayLink.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsDisplayLink.h
│ │ ├── WorkletsMessageThread.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsMessageThread.h
│ │ └── WorkletsModule.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsModule.h
│ ├── NativeModules
│ │ ├── JSIWorkletsModuleProxy.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h
│ │ └── WorkletsModuleProxy.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h
│ ├── Registries
│ │ ├── EventHandlerRegistry.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Registries/EventHandlerRegistry.h
│ │ └── WorkletRuntimeRegistry.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h
│ ├── Resources
│ │ └── Unpackers.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Resources/Unpackers.h
│ ├── RunLoop
│ │ ├── AsyncQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/AsyncQueue.h
│ │ ├── AsyncQueueImpl.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/AsyncQueueImpl.h
│ │ └── EventLoop.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/EventLoop.h
│ ├── SharedItems
│ │ ├── MemoryManager.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/MemoryManager.h
│ │ ├── Serializable.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h
│ │ ├── Synchronizable.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/Synchronizable.h
│ │ └── SynchronizableAccess.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/SynchronizableAccess.h
│ ├── Tools
│ │ ├── Defs.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/Defs.h
│ │ ├── FeatureFlags.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/FeatureFlags.h
│ │ ├── JSISerializer.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSISerializer.h
│ │ ├── JSLogger.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSLogger.h
│ │ ├── JSScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSScheduler.h
│ │ ├── PlatformLogger.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/PlatformLogger.h
│ │ ├── SingleInstanceChecker.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/SingleInstanceChecker.h
│ │ ├── ThreadSafeQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/ThreadSafeQueue.h
│ │ ├── UIScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/UIScheduler.h
│ │ ├── VersionUtils.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/VersionUtils.h
│ │ ├── WorkletEventHandler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletEventHandler.h
│ │ ├── WorkletsJSIUtils.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsJSIUtils.h
│ │ ├── WorkletsSystraceSection.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsSystraceSection.h
│ │ └── WorkletsVersion.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsVersion.h
│ └── WorkletRuntime
│ ├── RNRuntimeWorkletDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h
│ ├── RuntimeBindings.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeBindings.h
│ ├── RuntimeData.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeData.h
│ ├── RuntimeHolder.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeHolder.h
│ ├── RuntimeKind.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeKind.h
│ ├── RuntimeManager.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeManager.h
│ ├── UIRuntimeDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/UIRuntimeDecorator.h
│ ├── WorkletHermesRuntime.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletHermesRuntime.h
│ ├── WorkletRuntime.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h
│ ├── WorkletRuntimeCollector.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeCollector.h
│ └── WorkletRuntimeDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h
└── Public
└── RNWorklets
└── worklets
├── AnimationFrameQueue
│ └── AnimationFrameBatchinator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.h
├── apple
│ ├── AnimationFrameQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AnimationFrameQueue.h
│ ├── AssertJavaScriptQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AssertJavaScriptQueue.h
│ ├── AssertTurboModuleManagerQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/AssertTurboModuleManagerQueue.h
│ ├── IOSUIScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/IOSUIScheduler.h
│ ├── SlowAnimations.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/SlowAnimations.h
│ ├── WorkletsDisplayLink.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsDisplayLink.h
│ ├── WorkletsMessageThread.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsMessageThread.h
│ └── WorkletsModule.h -> ../../../../../../../../../node_modules/react-native-worklets/apple/worklets/apple/WorkletsModule.h
├── NativeModules
│ ├── JSIWorkletsModuleProxy.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.h
│ └── WorkletsModuleProxy.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/NativeModules/WorkletsModuleProxy.h
├── Registries
│ ├── EventHandlerRegistry.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Registries/EventHandlerRegistry.h
│ └── WorkletRuntimeRegistry.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Registries/WorkletRuntimeRegistry.h
├── Resources
│ └── Unpackers.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Resources/Unpackers.h
├── RunLoop
│ ├── AsyncQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/AsyncQueue.h
│ ├── AsyncQueueImpl.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/AsyncQueueImpl.h
│ └── EventLoop.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/RunLoop/EventLoop.h
├── SharedItems
│ ├── MemoryManager.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/MemoryManager.h
│ ├── Serializable.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/Serializable.h
│ ├── Synchronizable.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/Synchronizable.h
│ └── SynchronizableAccess.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/SharedItems/SynchronizableAccess.h
├── Tools
│ ├── Defs.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/Defs.h
│ ├── FeatureFlags.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/FeatureFlags.h
│ ├── JSISerializer.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSISerializer.h
│ ├── JSLogger.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSLogger.h
│ ├── JSScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/JSScheduler.h
│ ├── PlatformLogger.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/PlatformLogger.h
│ ├── SingleInstanceChecker.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/SingleInstanceChecker.h
│ ├── ThreadSafeQueue.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/ThreadSafeQueue.h
│ ├── UIScheduler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/UIScheduler.h
│ ├── VersionUtils.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/VersionUtils.h
│ ├── WorkletEventHandler.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletEventHandler.h
│ ├── WorkletsJSIUtils.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsJSIUtils.h
│ ├── WorkletsSystraceSection.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsSystraceSection.h
│ └── WorkletsVersion.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/Tools/WorkletsVersion.h
└── WorkletRuntime
├── RNRuntimeWorkletDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RNRuntimeWorkletDecorator.h
├── RuntimeBindings.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeBindings.h
├── RuntimeData.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeData.h
├── RuntimeHolder.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeHolder.h
├── RuntimeKind.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeKind.h
├── RuntimeManager.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/RuntimeManager.h
├── UIRuntimeDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/UIRuntimeDecorator.h
├── WorkletHermesRuntime.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletHermesRuntime.h
├── WorkletRuntime.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h
├── WorkletRuntimeCollector.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeCollector.h
└── WorkletRuntimeDecorator.h -> ../../../../../../../../../node_modules/react-native-worklets/Common/cpp/worklets/WorkletRuntime/WorkletRuntimeDecorator.h
You can see that all of the headers are actual symlinks to the source files - this is crucial for #pragma once, I will explain it later on.
Reading CocoaPods documentation:
If no public headers are specified then all the headers in source_files are considered public.
This is why all the headers are in the Public dir. AFAIK the Private dir always has all the headers.
The Public dir is in the include list, therefore to import i.e. AsyncQueue.h the user has to do #include <RNWorklets/worklets/WorkletRuntime/WorkletRuntime.h>.
We can easily turn this import to <RNWorklets/AsyncQueue.h> by specifying flattened, public headers as done in this PR.
react-native-reanimated doesn't do <RNWorklets/...> for import because it adds '"$(PODS_ROOT)/Headers/Public/RNWorklets"', to HEADER_SEARCH_PATHS for compilation - but it would be better if the user didn't have to do it.
Android
If the user consumes Worklets as a prefab (which is the preferred way) he automatically has access to the includes in the prefabs, with the following structure:
.
└── worklets
├── android
│ ├── AndroidUIScheduler.h
│ ├── AnimationFrameCallback.h
│ └── WorkletsModule.h
├── AnimationFrameQueue
│ └── AnimationFrameBatchinator.h
├── NativeModules
│ ├── JSIWorkletsModuleProxy.h
│ └── WorkletsModuleProxy.h
├── Registries
│ ├── EventHandlerRegistry.h
│ └── WorkletRuntimeRegistry.h
├── Resources
│ └── Unpackers.h
├── RunLoop
│ ├── AsyncQueue.h
│ ├── AsyncQueueImpl.h
│ └── EventLoop.h
├── SharedItems
│ ├── MemoryManager.h
│ ├── Serializable.h
│ ├── Synchronizable.h
│ └── SynchronizableAccess.h
├── Tools
│ ├── Defs.h
│ ├── FeatureFlags.h
│ ├── JSISerializer.h
│ ├── JSLogger.h
│ ├── JSScheduler.h
│ ├── PlatformLogger.h
│ ├── SingleInstanceChecker.h
│ ├── ThreadSafeQueue.h
│ ├── UIScheduler.h
│ ├── VersionUtils.h
│ ├── WorkletEventHandler.h
│ ├── WorkletsJSIUtils.h
│ ├── WorkletsSystraceSection.h
│ └── WorkletsVersion.h
└── WorkletRuntime
├── RNRuntimeWorkletDecorator.h
├── RuntimeBindings.h
├── RuntimeData.h
├── RuntimeHolder.h
├── RuntimeKind.h
├── RuntimeManager.h
├── UIRuntimeDecorator.h
├── WorkletHermesRuntime.h
├── WorkletRuntime.h
├── WorkletRuntimeCollector.h
└── WorkletRuntimeDecorator.h
To import, i.e. AsyncQueue.h the user has to do #include <worklets/WorkletRuntime/WorkletRuntime.h> and this way can also access all other "private" headers.
This include can be changed to <RNWorklets/...> only if we modify this header directory structure.
One option here would be to copy the public headers to the root of the inclusion tree, so it would look like
.
├── RNWorklets
│ ├── AsyncQueue.h
│ ├── Serializable.h
│ ├── Synchronizable.h
│ └── WorkletRuntime.h
└── worklets
├── ...
...
However, this will break compilation as #pragma once inclusion guards are based on the file path. Therefore RNWorklets/AsyncQueue.h and worklets/RunLoop/AsyncQueue.h would be treated as different headers and re-compiled, resulting in duplicated symbols. Cocoapods resolves this issue by using symlinks everywhere.
We have two options to solve this problem:
- Change the
#pragma onceguards to
which is path-agnostic.#ifndef HEADER_GUARD #define HEADER_GUARD // code #endif // HEADER_GUARD - Use symlinks just like Cocapods - by symlinking public headers in the prefab headers to the private headers.
The latter is less invasive for the time being - that's why I decided to opt into it.
Test plan
CI
Windows build CI: https://github.com/software-mansion/react-native-reanimated/actions/runs/19826776715