You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: proposals/0012-introduce-reactNativeMetadata.md
+83-25
Original file line number
Diff line number
Diff line change
@@ -3,6 +3,7 @@ title: DRAFT | Introducing `reactNativeManifest` to `package.json` for React Nat
3
3
author:
4
4
- Lorenzo Sciandra
5
5
- Nicola Corti
6
+
- Riccardo Cipolleschi
6
7
date: 25-01-2021
7
8
---
8
9
@@ -14,24 +15,33 @@ date: 25-01-2021
14
15
15
16
This RFC introduces and formally discuss the concept of _React Native Manifest_, a set of metadata about a React Native project (either app or library). This metadata can be consumed by tooling to enhance the developer experience and support the React Native ecosystem.
16
17
18
+
This would be the entry point for all the official configurations supported by the core of React Native. Examples (not an exhaustive list) of these configurations could be:
19
+
* Whether the New Architecture is enabled or not.
20
+
* Which JS Engine should run in the app.
21
+
This will not be the place where we can add any kind of configuration.
22
+
17
23
Practically, this RFC proposes to add a `reactNativeManifest` section to the `package.json` file of a React Native app or library.
18
24
This new section will allow developers to follow a declarative approach to express capabilities of apps and libraries in a more formalized manner.
19
25
20
26
## Rationale
21
27
22
-
The need to specify **capabilities and metadata** for a react-native library is inherent to the React Native ecosystem.
28
+
The need to specify **capabilities and metadata** for a react-native library is inherent to the React Native ecosystem. This need is so evident that various frameworks provided their own ways to specify those values. Look at `react-native.config.js` for the CLI or `expo.config.js` for Expo.
23
29
24
-
As of today, there is no simple programmatic way to know if a NPM package is a React Native library. Good indicators could be:
30
+
Another issue is that, as of today, there is no simple programmatic way to know if a NPM package is a React Native library.
31
+
We have some heuristics, though:
25
32
* Presence of a `react-native:*` dependency in the `peerDependencies` section of the `package.json` ([example](https://github.com/RonRadtke/react-native-blob-util/blob/80628d418a5c81439dc2c1a1f05fae6406f0ba7f/package.json#L46C10-L49))
26
33
* Presence of React Native specific files such as `react-native.config.js` files
27
-
Those indicators are all non-exhaustive.
34
+
Those indicators are all non-exhaustive.
28
35
29
-
Similarly, there is no easy way to understand if a library is exposing a native moduleor not.
30
-
The React Native CLI is facing this difficulty and tries to circumvent it by inspecting the native code and searching for subclasses of `*ReactPackage` using complex regular expressions ([example](https://github.com/react-native-community/cli/blob/605c542d18efcb02f217d3c85726fa73a79054c2/packages/cli-platform-android/src/config/findPackageClassName.ts#L35)) due to the lack of a declarative way to express this information.
36
+
Similarly, there is no easy way to understand if a library is exposing a native module, a native component or not.
37
+
The lack of this information pushed the community to create workarounds to understand that. For Example, the React Native CLI tries to circumvent it by inspecting the native code and searching for subclasses of `*ReactPackage` using complex regular expressions ([example](https://github.com/react-native-community/cli/blob/605c542d18efcb02f217d3c85726fa73a79054c2/packages/cli-platform-android/src/config/findPackageClassName.ts#L35)) due to the lack of a declarative way to express this information.
31
38
32
39
Another practical example of this need is the [React Native Directory](https://reactnative.directory/) attempting to [programmatically infer](https://github.com/react-native-community/directory/pull/870) the New Architecture support from the presence of the `codegenConfig` fields in the `package.json` of a library. The `codegenConfig` field is not intended to carry semantic information about New Architecture support, and is definitely a non-exhaustive solution for this problem.
33
40
34
-
While we can continue to build tooling that tries to infer metadata and capabilities of a library, providing a declarative way to describe such capabilities yields a series of benefit:
41
+
While we can continue to build tooling that tries to infer metadata and capabilities of a library, all these approach would never be precise and could provide misleading information.
42
+
43
+
We suggest to provide a declarative way to describe such capabilities.
44
+
This approach would yield several benefits:
35
45
***predictability**: developers can easily understand what a library is capable of doing and if such capability matches their app.
36
46
***tooling**: tooling can easily consume this information and provide a better experience to developers.
37
47
***single source of thruth**: a single manifest will act as a source of truth for all those capabilities and flag definition, that can easily be consumed by different platforms to provide a unified way to enable/disable capabilities.
@@ -56,30 +66,32 @@ We're proposing to declare if a project is either a library or an app by adding
56
66
}
57
67
```
58
68
69
+
This is a mandatory field that needs to be specified in all the apps and libraries.
70
+
59
71
### New Architecture support
60
72
61
73
One of the primary driver of this proposal is the [New React Native Architecture support](https://reactnative.dev/docs/the-new-architecture/landing-page). Specifically we believe that the ecosystem is currently affected by:
62
74
* Lack of a declarative way to define if a library is compatible with the New Architecture
63
75
* As described in the [rationale](#rationale), tooling needs to infer this information from the presence of the `codegenConfig` field in the `package.json` of a library. Libraries might decide not to use Codegen and still be compatible with the New Architecture, so this method is not exhaustive.
64
76
* The alternative at this stage is to inspect the code and check whether the API callsites are New Architecture or Old Architecture compatible.
65
77
* Lack of a declarative way to enable the New Architecture on both platforms
66
-
* Currently the New Architecture is enabled by a Gradle Property `newArchEnabled` on Android in the `gradle.properties` file and by invoking `RCT_NEW_ARCH_ENABLED=1 bundle exec pod install` on iOS.
78
+
* Currently the New Architecture is enabled by a Gradle Property `newArchitectureEnabled` on Android in the `gradle.properties` file and by invoking `RCT_NEW_ARCH_ENABLED=1 bundle exec pod install` on iOS.
67
79
* As of today, there is no way to enable the New Architecture for an app project for both platforms
68
80
* Moreover, the difference in how the New Architecture is enabled leads to a scenario where you can't statically know if an app supports New Architecture or not (as the New Architecture support is known at `pod install` time and is not codified in the codebase)
69
81
70
-
Therefore we propose to add the `newArch` section to the `reactNativeManifest.capabilities` of **both apps and libraries** with the following semantic:
71
-
* For Apps: `newArch.enabled==true` means that the app wants to use the New Architecture.
72
-
* For Libraries: `newArch.enabled==true` means that the library is compatible with the New Architecture.
82
+
Therefore we propose to add the `newArchitecture` section to the `reactNativeManifest.capabilities` of **both apps and libraries** with the following semantic:
83
+
* For Apps: `newArchitecture.enabled==true` means that the app wants to use the New Architecture.
84
+
* For Libraries: `newArchitecture.enabled==true` means that the library is compatible with the New Architecture.
73
85
74
-
Tools can be built on top of this information to check that an app with `newArch.enabled==true` is not accepting libraries with `newArch.enabled==false` and to warn against library that don't have the key specified.
86
+
Tools can be built on top of this information to check that an app with `newArchitecture.enabled==true` is not accepting libraries with `newArchitecture.enabled==false` and to warn against library that don't have the key specified.
75
87
76
88
The setup would look as follows for both apps and libraries:
77
89
78
90
```json
79
91
{
80
92
"reactNativeManifest": {
81
93
"capabilities": {
82
-
"newArch": {
94
+
"newArchitecture": {
83
95
"enabled": true
84
96
}
85
97
}
@@ -94,14 +106,14 @@ This section will allow also for split configuration between platforms:
94
106
"reactNativeManifest": {
95
107
"android": {
96
108
"capabilities": {
97
-
"newArch": {
109
+
"newArchitecture": {
98
110
"enabled": true
99
111
}
100
112
}
101
113
},
102
114
"ios": {
103
115
"capabilities": {
104
-
"newArch": {
116
+
"newArchitecture": {
105
117
"enabled": true
106
118
}
107
119
}
@@ -110,10 +122,35 @@ This section will allow also for split configuration between platforms:
110
122
}
111
123
```
112
124
125
+
If omitted, the `newArchitecture.enabled` would have a value of `false` (this may change in the future).
126
+
127
+
The precedence rules are that platform-specific settings override general settings. So, for example:
128
+
129
+
```json
130
+
{
131
+
"reactNativeManifest": {
132
+
"capabilities": {
133
+
"newArchitecture": {
134
+
"enabled": true
135
+
}
136
+
},
137
+
"android": {
138
+
"capabilities": {
139
+
"newArchitecture": {
140
+
"enabled": false
141
+
}
142
+
}
143
+
},
144
+
}
145
+
}
146
+
```
147
+
148
+
would means that, in general, the app/library support the New Architecture, but not for Android.
149
+
113
150
#### `codegenConfig` support
114
151
115
152
Similarly to the New Architecture support metadata, the `codegenConfig` is a key metadata of the New Architecture build pipeline.
116
-
Currently the `codegenConfig` is a **top-level** key in the `package.json` of a project.
153
+
Currently the `codegenConfig` is a **top-level** key in the `package.json` of a project.
117
154
118
155
We propose to move this key under the `reactNativeManifest.capabilites` section as follows:
119
156
```json
@@ -174,9 +211,34 @@ which will also allow for split configuration between platforms as follows:
174
211
}
175
212
```
176
213
214
+
If omitted, the `hermes.enabled` would have a value of `true`.
215
+
216
+
The precedence rules are that platform-specific settings override general settings. So, for example:
217
+
218
+
```json
219
+
{
220
+
"reactNativeManifest": {
221
+
"capabilities": {
222
+
"hermes": {
223
+
"enabled": true
224
+
}
225
+
},
226
+
"android": {
227
+
"capabilities": {
228
+
"hermes": {
229
+
"enabled": false
230
+
}
231
+
}
232
+
},
233
+
}
234
+
}
235
+
```
236
+
237
+
would means that the app will run with Hermes for all the platforms it supports but not for Android.
238
+
177
239
### React Native Release feature flagging
178
240
179
-
We currently have a numer of different files where capabilities of React Native can be toggled to enable/disable features in the runtime.
241
+
We currently have a number of different files where capabilities of React Native can be toggled to enable/disable features in the runtime.
180
242
For example we have:
181
243
*[android/gradle.properties](https://github.com/facebook/react-native/blob/main/packages/react-native/template/android/gradle.properties) to specify key-value build time properties for Android
182
244
*[android/app/build.gradle](https://github.com/facebook/react-native/blob/main/packages/react-native/template/android/app/build.gradle) to specify build time configuration for Android
@@ -200,7 +262,7 @@ For the time being, we're not planning to add a `version` section to the `reactN
200
262
201
263
### TurboModule/Fabric toggles
202
264
203
-
At the time of writing, we prefer not to offer a dedicated section to toggle Fabric/TurboModule capability inside `reactNativeManifest`. The rationale is that we believe that the `newArch` section is sufficient to expose the New Architecture to users.
265
+
At the time of writing, we prefer not to offer a dedicated section to toggle Fabric/TurboModule capability inside `reactNativeManifest`. The rationale is that we believe that the `newArchitecture` section is sufficient to expose the New Architecture to users.
204
266
Selectively toggling Fabric/TurboModule is a more advanced feature. We believe we'll still be offering a more advanced way to enable or disable those pieces of the New Architecture infrastructure, but at the current state, our preference is not to expose such capability in the top level `reactNativeManifest` section.
205
267
206
268
## Proposed Tooling
@@ -215,7 +277,6 @@ Build tools such as Gradle/CocoaPods or others should account for the `reactNati
215
277
1. If the user is **also** specifying the capability `foo` in the build tool specific configuration (e.g. inside `gradle.properties` for Android) behave as follows:
216
278
1. If the two values are **compatible**, use them without notifying the user.
217
279
1. If the two values are **incompatible**, notify the user and use the value specified in the `reactNativeManifest.capabilities.foo` section will prevail and the value specified in the build tool specific configuration will be ignored.
218
-
1. If the user is **not** specifying the capability `foo` in the build tool specific configuration, honor the value specified in the `reactNativeManifest.capabilities.foo` section.
219
280
1. If the capability `foo` is **not** specificed in the `reactNativeManifest.capabilities` section, honor the value specified in the build tool specific configuration or the default value if not specified.
220
281
221
282
### `align-deps` support
@@ -254,7 +315,7 @@ Specifically, we envision to evolve `reactNativeManifest` or `reactNativeManifes
254
315
Here we present a full example of how a `reactNativeManifest` section could look like for a library and an app.
255
316
256
317
For an app the section will look as follows:
257
-
318
+
258
319
```json
259
320
{
260
321
"name": "my-awesome-app",
@@ -266,7 +327,7 @@ For an app the section will look as follows:
266
327
"hermes": {
267
328
"enabled": true
268
329
},
269
-
"newArch": {
330
+
"newArchitecture": {
270
331
"enabled": true
271
332
},
272
333
"codegenConfig": {
@@ -292,10 +353,7 @@ For a library the section will look as follows:
292
353
"schema": "1.0.0",
293
354
"type": "library",
294
355
"capabilities": {
295
-
"hermes": {
296
-
"enabled": true
297
-
},
298
-
"newArch": {
356
+
"newArchitecture": {
299
357
"enabled": true
300
358
},
301
359
"codegenConfig": {
@@ -324,7 +382,7 @@ The JSON Schema will be published as soon as we find an agreement on the key nam
324
382
If we decide to adopt this proposal, we'll have to broadcast this change to the ecosystem.
325
383
Ideally, we'll start by adding the `reactNativeManifest` section to the app template and to `create-react-native-library`.
326
384
327
-
We foresee a phase in which only a part of the userbase has this section configured, and tool and developers need to account for the absence of this section.
385
+
We foresee a phase in which only a part of the user base has this section configured, and tool and developers need to account for the absence of this section.
328
386
329
387
Once the v1.0.0 version of the shape is finalised, we can start integrating it across the board in various tools mentioned in [Proposed Tooling](#proposed-tooling) section. This first wave of support would have to be aligned around a given React Native release, say in 0.73 (which branch has not been cut).
0 commit comments