From bcd0e3fb157792463e76aab5786fc27c2f7d21e9 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 25 Mar 2024 15:26:29 -0700 Subject: [PATCH 1/7] [wip] Recommend using interop layer first, before migrating fully to TM/Fabric --- docs/enable-libraries-prerequisites.md | 5 +++- docs/enable-libraries.md | 40 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 docs/enable-libraries.md diff --git a/docs/enable-libraries-prerequisites.md b/docs/enable-libraries-prerequisites.md index fc67a5a..f463613 100644 --- a/docs/enable-libraries-prerequisites.md +++ b/docs/enable-libraries-prerequisites.md @@ -2,7 +2,10 @@ # Enable the New Architecture for Libraries: Prerequisites -The following steps are prerequisites to ensure your modules and components are ready for the New Architecture. +> [!IMPORTANT] +> Before proceeding to convert your library to natively use TurboModules/Fabric, you should [ensure that it is compatible with the interop layer](enable-libraries.md). This is the quickest way to make your library compatible today. + +This guide explains how to convert your library to use the TurboModules API and Fabric Component API natively, without the interop layer. The following steps are prerequisites to ensure your modules and components are ready for the New Architecture. 1. [Define Specs in JavaScript](#define-specs-in-javascript) 2. [Configure Codegen](#configure-codegen) diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md new file mode 100644 index 0000000..41a8203 --- /dev/null +++ b/docs/enable-libraries.md @@ -0,0 +1,40 @@ +[../README.md#Guides](../README.md#guides) + +# Enable the New Architecture for Libraries + +**The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [interop layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The interop layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. **You should do this before proceeding to convert your library to natively use TurboModules/Fabric.** Starting with React Native 0.74, the interop layer is enabled by default and, if your library is compatible, then no changes will be needed on the user's side in order to use your library. + +## Using the interop layer + +The interop layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the interop layer and fixing common issues that you encounter. + +> [!IMPORTANT] +> If you have already added a Codegen spec to your library, but the library is not fully converted to TurboModules/Fabric, we recommend that you delete it before proceeding. You can add this back when you are ready to convert your library to natively use TurboModules/Fabric without the interop layer. + +### Test your library + +Follow [the guide for testing your library against the latest version of React Native](https://gist.github.com/cipolleschi/82b7a9561b8861330efabbd3eb08c6f5). Be sure to test all of the functionality of your library to ensure that it works as expected. + +### Common issues (JavaScript) + +(list them here, along with solutions and links to pull requests) + +### Common issues (iOS) + +(list them here, along with solutions and links to pull requests) + +### Common issues (Android) + +(list them here, along with solutions and links to pull requests) + +### Get help + +Search the ["Libraries" discussion category](https://github.com/reactwg/react-native-new-architecture/discussions/categories/libraries) for similar issues, and if you can't find a solution, post a discussion with details about the issue you are facing. + +### Update library status + +(post to the discussion? add some metadata to the pkg.json?) + +## Next steps + +Once your library is compatible with the interop layer, release a new version for your users. You can proceed to [converting your library to natively use TurboModules/Fabric](enable-libraries-turbomodules.md) when convenient for you. \ No newline at end of file From 9d95738fccc55ed3daf0dbfa7cb66dd2053555fb Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Mon, 25 Mar 2024 15:31:12 -0700 Subject: [PATCH 2/7] Update links in README --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 581ae51..dc815b7 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ You can find New Architecture updates [here](https://github.com/reactwg/react-na ## Guides - How to enable the New Architecture - - [For Apps](./docs/enable-apps.md) + - For Apps + - [Enable the New Architecture for Apps](./docs/enable-apps.md) - For Libraries - - [Prerequisites](./docs/enable-libraries-prerequisites.md) - - [For Android](./docs/enable-libraries-android.md) - - [For iOS](./docs/enable-libraries-ios.md) + - [Make your library compatible with the New Architecture](./docs/enable-libraries.md) + - [Convert Library to TurboModules/Fabric APIs](./docs/enable-libraries-prerequisites.md) + - [Additional information for Android](./docs/enable-libraries-android.md) + - [Additional information for iOS](./docs/enable-libraries-ios.md) - New Architecture Workflows - [Create a Fabric Native Component](./docs/fabric-native-components.md) - [Create a Turbo Native Module](./docs/turbo-modules.md) From 87b171602d3980e071c317b6e65265af0dc3b399 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 26 Mar 2024 10:34:36 -0700 Subject: [PATCH 3/7] Update docs/enable-libraries.md Co-authored-by: Gabriel Donadel Dall'Agnol --- docs/enable-libraries.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md index 41a8203..4b7e277 100644 --- a/docs/enable-libraries.md +++ b/docs/enable-libraries.md @@ -17,7 +17,8 @@ Follow [the guide for testing your library against the latest version of React N ### Common issues (JavaScript) -(list them here, along with solutions and links to pull requests) + +- `XYZ is not a function (it is undefined)`. When accessing a module directly from `NativeModules` in the new architecture some operators won't work due to the fact of turbomodule using object prototypes now to lazily load methods. This includes things like the spread operator and `Object.keys`. You can find more details in https://github.com/facebook/react-native/issues/43221 ### Common issues (iOS) From 1cfa0e8148fff46179d3eb07a8ee156a133672cc Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 26 Mar 2024 11:09:28 -0700 Subject: [PATCH 4/7] Address feedback and copy over common problems from spreadsheet --- docs/enable-libraries-prerequisites.md | 2 +- docs/enable-libraries.md | 104 +++++++++++++++++++++---- 2 files changed, 90 insertions(+), 16 deletions(-) diff --git a/docs/enable-libraries-prerequisites.md b/docs/enable-libraries-prerequisites.md index f463613..f18fad9 100644 --- a/docs/enable-libraries-prerequisites.md +++ b/docs/enable-libraries-prerequisites.md @@ -3,7 +3,7 @@ # Enable the New Architecture for Libraries: Prerequisites > [!IMPORTANT] -> Before proceeding to convert your library to natively use TurboModules/Fabric, you should [ensure that it is compatible with the interop layer](enable-libraries.md). This is the quickest way to make your library compatible today. +> Before proceeding to convert your library to natively use TurboModules/Fabric, you should [ensure that it is compatible with the Interop Layer](enable-libraries.md). There is no known performance cost imposed by the Interop Layer, but it will be removed at some point in the future. Today, it's safe and recommended to use the Interop Layer as a first solution to make your library compatible with the New Architecture quickly, and then you can consider migrating to the native APIs in the near future. This guide explains how to convert your library to use the TurboModules API and Fabric Component API natively, without the interop layer. The following steps are prerequisites to ensure your modules and components are ready for the New Architecture. diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md index 4b7e277..cf7afa9 100644 --- a/docs/enable-libraries.md +++ b/docs/enable-libraries.md @@ -2,40 +2,114 @@ # Enable the New Architecture for Libraries -**The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [interop layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The interop layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. **You should do this before proceeding to convert your library to natively use TurboModules/Fabric.** Starting with React Native 0.74, the interop layer is enabled by default and, if your library is compatible, then no changes will be needed on the user's side in order to use your library. +**The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [Interop Layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The Interop Layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. **You should do this before proceeding to convert your library to natively use TurboModules/Fabric.** Starting with React Native 0.74, the Interop Layer is enabled by default and, if your library is compatible, then no changes will be needed on the user's side in order to use your library. -## Using the interop layer +## Using the Interop Layer -The interop layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the interop layer and fixing common issues that you encounter. +The Interop Layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the Interop Layer and fixing common issues that you encounter. > [!IMPORTANT] -> If you have already added a Codegen spec to your library, but the library is not fully converted to TurboModules/Fabric, we recommend that you delete it before proceeding. You can add this back when you are ready to convert your library to natively use TurboModules/Fabric without the interop layer. +> If you have already added a Codegen spec to your library, but the library is not fully converted to TurboModules/Fabric, we recommend that you delete it before proceeding. You can add this back when you are ready to convert your library to natively use TurboModules/Fabric without the Interop Layer. -### Test your library +## Test your library Follow [the guide for testing your library against the latest version of React Native](https://gist.github.com/cipolleschi/82b7a9561b8861330efabbd3eb08c6f5). Be sure to test all of the functionality of your library to ensure that it works as expected. -### Common issues (JavaScript) +## Issues that you may encounter +### [JavaScript] `XYZ is not a function (it is undefined)` -- `XYZ is not a function (it is undefined)`. When accessing a module directly from `NativeModules` in the new architecture some operators won't work due to the fact of turbomodule using object prototypes now to lazily load methods. This includes things like the spread operator and `Object.keys`. You can find more details in https://github.com/facebook/react-native/issues/43221 +When accessing a module directly from `NativeModules` in the new architecture some operators won't work due to the fact that TurboModule uses object prototypes now, in order to lazily load methods. So, if you used an operator like the spread operator or a function like `Object.keys` on `NativeModules.YourModule` then you will need to change to use `Object.create`. Learn more in [facebook/react-native#43221](https://github.com/facebook/react-native/issues/43221). -### Common issues (iOS) +
+Spread operator example -(list them here, along with solutions and links to pull requests) +```js +// Before: spread operator worked, but it will not with interop +export default { + ...NativeModules.RNCNetInfo, + get eventEmitter(): NativeEventEmitter { + ... + } +} +``` -### Common issues (Android) +```js +// After: use Object.create instead +Object.create(NativeModules.RNCNetInfo, { + eventEmitter: { + get: () => {...}, + enumerable: true, + }, +}) +``` -(list them here, along with solutions and links to pull requests) +
-### Get help +
+Object.keys example + +```js +// Before: Object.keys worked, but it will not with interop +Object.keys(NativeModules.RNCNetInfo).forEach((key) => { + ... +}) +``` + +```js +// After: use for ... in instead +for (const key in NativeModules.RNCNetInfo) { + ... +} +``` + +
+ +### [JavaScript] `global.nativeCallSyncHook` can't be used to detect legacy "Remote Debugging in Chrome" with JSC + +`global.nativeCallSyncHook === 'undefined'` is a common way to check if you're running in "Remote Debugging in Chrome" (which is not supported with Hermes, only JSC). This is often used to provide some fallback behavior for sync native functions, because they do not work in the legacy remote debugging environment. Use `"RN$Bridgeless" in global && RN$Bridgeless === true` to determine if you are running in bridgeless. Learn more in [LinusU/react-native-get-random-values#57](https://github.com/LinusU/react-native-get-random-values/pull/57). + +It is generally not recommended to fork behavior based on whether bridgeless is enabled — this is an escape hatch that should be used sparingly. + + +
+Example "isRemoteDebuggingInChrome()" function + +```js +function isRemoteDebuggingInChrome () { + // Remote debugging in Chrome is not supported in bridgeless + if ('RN$Bridgeless' in global && RN$Bridgeless === true) { + return false + } + + return __DEV__ && typeof global.nativeCallSyncHook === 'undefined' +} +``` + +
+ +### [iOS/Android] Interop Layer is not compatible with custom ShadowNodes + +The Interop Layer doesn't work on either Android or iOS if a legacy view is specifying a custom `ShadowNode`, i.e. in Android by overriding the method `getShadowNodeClass`, `createShadowNodeInstance` etc. Fabric won't call those methods and the widget will most likely be rendered incorrectly (i.e. wrong size, 0 height so unclickable, etc.). You can either work around this by not using custom `ShadowNode` or by converting your library to use TurboModules/Fabric without the Interop Layer. + +### [Android] `ThemedContext.getNativeModule()` does not behave the same with Interop Layer + +A native view manager used to have a `ThemedContext`, which is a class derived from `ReactContext`. It was common to call `ThemedContext.getNativeModule()` or other methods expected to be inherited from `ReactContext`. However, with the Interop Layer this will call to `ReactContext`'s implementation (the `CatalystInstance` one) but not `BridgelessReactContext`. Accessing the internals to the `CatalystInstance` will cause an exception. + +You can solve this by using `ThemedContext.getReactApplicationContext().getNativeModule()`. + +### [iOS] Cannot access CallInvoker from "RCTCxxBridge.callInvoker" + +In bridgeless mode, React Native does not support a fallback for `jsCallInvoker`, and the `bridge.jsCallInvoker` is `nil`. The app will crash when accessing null pointer. Instead, get `callInvoker` from `getTurboModule:`, e.g. [shopify/react-native-skia#2223](https://github.com/Shopify/react-native-skia/pull/2223). + +## Get help Search the ["Libraries" discussion category](https://github.com/reactwg/react-native-new-architecture/discussions/categories/libraries) for similar issues, and if you can't find a solution, post a discussion with details about the issue you are facing. -### Update library status +## Update library status -(post to the discussion? add some metadata to the pkg.json?) +Once you have verified that your library works with the Interop Layer, update the status of your library on [reactnative.directory](https://reactnative.directory/) to indicate that it is compatible with the New Architecture. If your library is already listed there, set `"newArchitecture": true` in [react-native-libraries.json](https://github.com/react-native-community/directory/blob/main/react-native-libraries.json), otherwise [add your library to the directory](https://github.com/react-native-community/directory?tab=readme-ov-file#how-do-i-add-a-library). ## Next steps -Once your library is compatible with the interop layer, release a new version for your users. You can proceed to [converting your library to natively use TurboModules/Fabric](enable-libraries-turbomodules.md) when convenient for you. \ No newline at end of file +Once your library is compatible with the Interop Layer, release a new version for your users. You can proceed to [converting your library to natively use TurboModules/Fabric](enable-libraries-turbomodules.md) when convenient for you. \ No newline at end of file From c820cf9c85b0a6e8d02d2bcf3ed0c78e7f0a6377 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 26 Mar 2024 11:31:11 -0700 Subject: [PATCH 5/7] Add more clear steps --- docs/enable-libraries.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md index cf7afa9..38760a1 100644 --- a/docs/enable-libraries.md +++ b/docs/enable-libraries.md @@ -2,20 +2,26 @@ # Enable the New Architecture for Libraries -**The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [Interop Layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The Interop Layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. **You should do this before proceeding to convert your library to natively use TurboModules/Fabric.** Starting with React Native 0.74, the Interop Layer is enabled by default and, if your library is compatible, then no changes will be needed on the user's side in order to use your library. +**The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [Interop Layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The Interop Layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. -## Using the Interop Layer +If your library is already fully converted to the TurboModules/Fabric APIs, then you can skip this guide. Otherwise, then **you should do ensure compatibiltiy with the Interop Layer before proceeding to convert your library to natively use TurboModules/Fabric.** -The Interop Layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the Interop Layer and fixing common issues that you encounter. +Starting with React Native 0.74, the Interop Layer is enabled by default. If your library works with it, then no changes will be needed on the user's side in order to use your library. > [!IMPORTANT] > If you have already added a Codegen spec to your library, but the library is not fully converted to TurboModules/Fabric, we recommend that you delete it before proceeding. You can add this back when you are ready to convert your library to natively use TurboModules/Fabric without the Interop Layer. -## Test your library +## Ensuring compatibility with the Interop Layer + +The Interop Layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the Interop Layer and fixing common issues that developers have encountered. + +## 1. Test your library with the New Architecture and the Interop Layer Follow [the guide for testing your library against the latest version of React Native](https://gist.github.com/cipolleschi/82b7a9561b8861330efabbd3eb08c6f5). Be sure to test all of the functionality of your library to ensure that it works as expected. -## Issues that you may encounter +## 2. Fix any compatibility issues you encounter + +The following is a non-exhaustive list of common issues that developers have encountered when testing their libraries with the Interop Layer. If you encounter any of these issues, follow the provided guidance to fix them. ### [JavaScript] `XYZ is not a function (it is undefined)` @@ -102,11 +108,11 @@ You can solve this by using `ThemedContext.getReactApplicationContext().getNativ In bridgeless mode, React Native does not support a fallback for `jsCallInvoker`, and the `bridge.jsCallInvoker` is `nil`. The app will crash when accessing null pointer. Instead, get `callInvoker` from `getTurboModule:`, e.g. [shopify/react-native-skia#2223](https://github.com/Shopify/react-native-skia/pull/2223). -## Get help +## 3. Stuck? Get help Search the ["Libraries" discussion category](https://github.com/reactwg/react-native-new-architecture/discussions/categories/libraries) for similar issues, and if you can't find a solution, post a discussion with details about the issue you are facing. -## Update library status +## 4. Update library status Once you have verified that your library works with the Interop Layer, update the status of your library on [reactnative.directory](https://reactnative.directory/) to indicate that it is compatible with the New Architecture. If your library is already listed there, set `"newArchitecture": true` in [react-native-libraries.json](https://github.com/react-native-community/directory/blob/main/react-native-libraries.json), otherwise [add your library to the directory](https://github.com/react-native-community/directory?tab=readme-ov-file#how-do-i-add-a-library). From 4b925da9c08770027cdec86a27e971ef007df335 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 26 Mar 2024 11:34:28 -0700 Subject: [PATCH 6/7] Small improvements --- docs/enable-libraries.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md index 38760a1..39af7db 100644 --- a/docs/enable-libraries.md +++ b/docs/enable-libraries.md @@ -4,7 +4,7 @@ **The first step for supporting the New Architecture in your library is to ensure that it is compatible with the [Interop Layer](https://github.com/reactwg/react-native-new-architecture/discussions/135)**. The Interop Layer makes it possible to use existing native modules written for the legacy architecture with the New Architecture. -If your library is already fully converted to the TurboModules/Fabric APIs, then you can skip this guide. Otherwise, then **you should do ensure compatibiltiy with the Interop Layer before proceeding to convert your library to natively use TurboModules/Fabric.** +If your library is already fully converted to the TurboModules/Fabric APIs, then you can skip this guide. Otherwise, then **you should ensure compatibiltiy with the Interop Layer before proceeding to convert your library to natively use TurboModules/Fabric.** Starting with React Native 0.74, the Interop Layer is enabled by default. If your library works with it, then no changes will be needed on the user's side in order to use your library. @@ -15,6 +15,9 @@ Starting with React Native 0.74, the Interop Layer is enabled by default. If you The Interop Layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the Interop Layer and fixing common issues that developers have encountered. +> [!NOTE] +> It is not necessary to test your library against the New Architecture with bridgeless _disabled_. It is expected that from React Native 0.74, developers should be using the New Architecture with bridgeless _enabled_. + ## 1. Test your library with the New Architecture and the Interop Layer Follow [the guide for testing your library against the latest version of React Native](https://gist.github.com/cipolleschi/82b7a9561b8861330efabbd3eb08c6f5). Be sure to test all of the functionality of your library to ensure that it works as expected. From 567b7f0431705b19a610362df3f6d2375b10d686 Mon Sep 17 00:00:00 2001 From: Brent Vatne Date: Tue, 26 Mar 2024 11:35:31 -0700 Subject: [PATCH 7/7] Minor wording tweak again --- docs/enable-libraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/enable-libraries.md b/docs/enable-libraries.md index 39af7db..ec811f6 100644 --- a/docs/enable-libraries.md +++ b/docs/enable-libraries.md @@ -16,7 +16,7 @@ Starting with React Native 0.74, the Interop Layer is enabled by default. If you The Interop Layer will generally work out of the box with simple libraries, but the more complex your library is, the more likely it is that you will need to make some changes. The following sections will guide you through the process of verifying that your library works with the Interop Layer and fixing common issues that developers have encountered. > [!NOTE] -> It is not necessary to test your library against the New Architecture with bridgeless _disabled_. It is expected that from React Native 0.74, developers should be using the New Architecture with bridgeless _enabled_. +> It is not necessary to test your library against the New Architecture with bridgeless _disabled_ — it is expected that from React Native 0.74, developers using the New Architecture will have bridgeless _enabled_. ## 1. Test your library with the New Architecture and the Interop Layer