-
Notifications
You must be signed in to change notification settings - Fork 136
React Native Test App as a Package #204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
tido64
wants to merge
3
commits into
react-native-community:main
Choose a base branch
from
tido64:tido/test-app-as-package
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
--- | ||
title: React Native Test App as a Package | ||
author: | ||
- Tommy Nguyen | ||
date: February 2020 | ||
--- | ||
|
||
# RFC0000: React Native Test App as a Package | ||
|
||
## Summary | ||
|
||
Provide a React Native test app for all platforms as a package. | ||
|
||
A working prototype of this can be found here: | ||
https://github.com/microsoft/react-native-test-app | ||
|
||
## Motivation | ||
|
||
Maintaining and keeping React Native up to date with the latest version can be | ||
time consuming. Things can break if you're not careful, even with | ||
[React Native upgrade helper](https://react-native-community.github.io/upgrade-helper/). | ||
Not all developers have much experience in native development on a single | ||
platform, let alone _all_ platforms they want to support. Adding support for | ||
another platform, such as Windows or macOS, can be overwhelming. | ||
|
||
Consider the following scenarios: | ||
|
||
- As maintainers of a community package in our spare time, we don't have the | ||
capacity to create and maintain test apps. | ||
|
||
- Our inner development loop consists of using `npx react-native init`, and | ||
testing things manually. | ||
- Alternatively, we have set up CI for iOS and Android, and would love to add | ||
support for Windows and macOS but lack the resources. | ||
|
||
- We have a monorepo with multiple separate experiences that all need test apps. | ||
It is a pain having to upgrade all of the test apps individually with every | ||
release. Our upgrade process can sometimes take weeks to perform. | ||
|
||
- As a consumer of React Native, we should try out release candidates to find | ||
issues early and contribute back, but due to one of the scenarios above, there | ||
is simply too much friction. | ||
|
||
The proposed package will, at minimum, provide a customizable test app for all | ||
the major platforms that React Native currently runs on, i.e. iOS, Android, | ||
Windows, and macOS. The ultimate goal of this package is to make adding support | ||
for a platform as simple as `npm add --save-dev`, and upgrading to latest React | ||
Native is just a version bump. | ||
|
||
We expect the package will: | ||
|
||
- Help developers set up a consistent native environment for both local | ||
development and CI agents | ||
- Reduce or eliminate the friction to upgrade React Native, and try out release | ||
candidates | ||
- Reduce or eliminate the overhead of adding support for new platforms | ||
|
||
With common test apps, we will also be able to provide additional value for | ||
everyone simultanously. For instance: | ||
|
||
- We will handle upgrading of the test apps to support the latest mobile SDK | ||
- We can provide a common infrastructure for native testing | ||
- We can provide optional modules for commonly used services, such as auth or | ||
App Center integration | ||
|
||
## Detailed design | ||
|
||
Given an existing React Native app/library, we imagine the ideal flow for | ||
**initial integration** with the native test apps should be: | ||
|
||
1. Create folder/package for the test app to live in. | ||
- This package should have a dependency on the app/library to be tested, and | ||
on the test app package. | ||
2. Create a manifest to declare entry points. Optionally, it should also be | ||
possible to declare initial props, native source files and resources. | ||
- This is a **one-time cost**, and should be stable across versions. | ||
- If there is a single entry point, the app may boot directly into this app. | ||
- Otherwise, if there are multiple entry points, we will show them in a list. | ||
- It should still be possible to have the app boot into one of these via | ||
deep linking. | ||
- Native dependencies should be taken care of by auto-linking behind the | ||
scenes. | ||
3. Run `npm install` inside this folder as one would usually do. | ||
4. Depending on the desired target platforms, the next steps are: | ||
- Android: | ||
- Make minimal changes to `build.gradle` (one-time cost) | ||
- Open the project in Android Studio | ||
- iOS: | ||
- Make minimal changes to `Podfile` (one-time cost) | ||
- Run `pod install` | ||
- Open the newly generated Xcode workspace | ||
- Windows: | ||
- <@afoxman or @acoates-ms to fill in> | ||
- macOS: | ||
- See steps for iOS | ||
|
||
A hypothetical package should end up looking something like below: | ||
|
||
``` | ||
my-awesome-component | ||
├── example | ||
│ ├── App.js | ||
│ ├── build.gradle (new/modified) | ||
│ ├── package.json | ||
│ ├── Podfile (new/modified) | ||
│ └── yarn.lock | ||
├── my-awesome-component.podspec | ||
├── my-awesome-component-dev.podspec (new, optional) | ||
├── package.json | ||
├── src | ||
└── yarn.lock | ||
``` | ||
|
||
For a hypothetical monorepo: | ||
|
||
``` | ||
my-monorepo | ||
├── package.json | ||
├── packages | ||
│ ├── my-awesome-component-android | ||
│ │ ├── build.gradle (new/modified) | ||
│ │ ├── package.json | ||
│ │ └── src | ||
│ ├── my-awesome-component-core | ||
│ │ ├── package.json | ||
│ │ └── ... | ||
│ └── my-awesome-component-ios | ||
│ ├── my-awesome-component.podspec | ||
│ ├── my-awesome-component-dev.podspec (new, optional) | ||
│ ├── package.json | ||
│ ├── Podfile (new/modified) | ||
│ └── src | ||
└── yarn.lock | ||
``` | ||
|
||
Platform specific project files should no longer be checked in. They are either | ||
provided by React Native Test App package or are generated at build time. | ||
|
||
Once the test app package is configured, **adding an additional platform** | ||
should only require doing one of the platform specific substeps of step 4. | ||
|
||
**Upgrading React Native** to the latest version, or any desired version, should | ||
only require bumping the version of this package. | ||
|
||
This package should not require additional tools other than the ones required by | ||
React Native itself, and should not fundamentally change how a package is | ||
structured. | ||
|
||
### The Manifest | ||
|
||
The manifest will be the file where we declare all our entry points, and | ||
resources that should be included. | ||
|
||
We haven't decided what this manifest looks like. Our initial thought is to use | ||
React Native CLI's | ||
[configuration format](https://github.com/react-native-community/cli/blob/master/docs/configuration.md) | ||
as a starting point. This is what | ||
[auto-linking](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md#how-does-it-work) | ||
uses today, and we can extend it to support our scenarios. | ||
|
||
For iOS (and macOS), we will need to extend the format to include additional | ||
native source files and assets. An Xcode project generated today, will include a | ||
main app target, and two test targets: One for "normal" tests, and one for UI | ||
tests. We will need to be able to generate `.podspec` files that can support | ||
all. | ||
|
||
Entry points will also be declared in the manifest. Entry points tell the test | ||
app how to launch your app. For instance, given the declaration below: | ||
tido64 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```js | ||
module.exports = { | ||
... | ||
"entryPoints": [ | ||
{ | ||
"name": "MyFeature", | ||
"entryPoint": "MyFeatureTestScreen", | ||
"initialProps": { | ||
"showStatus": true | ||
} | ||
}, | ||
{ | ||
"name": "MySecondFeature", | ||
"entryPoint": "MySecondFeatureTestScreen", | ||
"presentationStyle": "popover" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
The mobile test app could look like this: | ||
|
||
``` | ||
┌──────────────────────┐ | ||
│ │ | ||
│RN Test App │ | ||
├──────────────────────┤ | ||
│ MyFeature >│ | ||
│ ─────────────────────┤ | ||
│ MySecondFeature >│ | ||
├──────────────────────┤ | ||
│ │ | ||
│ │ | ||
│ │ | ||
│ │ | ||
│╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲│ | ||
``` | ||
|
||
Tapping on one of these cells will launch the corresponding app. If defined, | ||
`initialProps` will be passed to the appropriate method call, and | ||
`presentationStyle` will tell the test app how to present the new view. | ||
|
||
One could also forgo the name, in which case the `entryPoint` string will be | ||
used instead. If only one entry point is declared, the test app should launch | ||
directly into that app. | ||
|
||
All of this should be transparent to the consumer; they should only have to deal | ||
with the manifest. | ||
|
||
## Drawbacks | ||
|
||
- Package maintainers no longer have full control of the test app | ||
- Bugs in the test app may take longer to get fixed | ||
- Limitations in existing tools can cause confusions, e.g. files are not | ||
added/removed until `pod install`/`update` is run | ||
|
||
## Alternatives | ||
|
||
### Electrode | ||
|
||
[Electrode Native](https://www.electrode.io/) is a platform by Walmart Labs | ||
that provides an opinionated, batteries-included solution for integrating React | ||
Native components into existing apps. It includes everything you'll ever need | ||
such as React Native initialization code, code generators, code push, facilities | ||
to test individual components etc. | ||
|
||
From a cursory glance, it seems that Electrode decides which React Native | ||
version will be embedded, and which bundler to use. Whereas one of the main | ||
goals of React Native Test App is making it simpler to switch between React | ||
Native versions, and it doesn't care whether Metro or Haul is used. Because | ||
Electrode is all-inclusive, it seems to be overkill for single component | ||
packages. You just want a test app for development and run tests on CI. | ||
|
||
### Expo | ||
|
||
[Expo](https://github.com/facebook/react-native/tree/master/RNTester) is a great | ||
solution to get started, and you don't mind that it's including a lot of things | ||
that your app won't use. Once your app matures to a point where it needs better | ||
control over what's included, or it needs to consume native modules that aren't | ||
bundled in the SDK. Ejecting brings you back to the world of having to maintain | ||
React Native yourself. | ||
|
||
Expo also isn't aimed at core contributors/maintainers. Its main goal is to | ||
simplify getting started with your React Native app. If you're looking to | ||
implement a native module of your own, you'll need to eject and stay ejected. | ||
This defeats the purpose of using Expo in the first place. | ||
tido64 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### React Native CLI | ||
|
||
[This tool](https://github.com/react-native-community/cli) creates a new project | ||
with a specifiable React Native version. It can be further customized with | ||
templates. We can see this test app package being part of the default template, | ||
with a single entry point defined. | ||
|
||
### RNTester | ||
|
||
[RNTester](https://github.com/facebook/react-native/tree/master/RNTester) is an | ||
app that showcases React Native views and modules. It is currently tightly | ||
coupled to React Native and requires building the framework with the app. | ||
|
||
## Adoption strategy | ||
|
||
- Get buy-in from the community; we want to make sure that this package aligns | ||
with what package maintainers expect of a test app | ||
- Submit the first few PRs to volunteering react-native-community packages to | ||
show how it can be integrated | ||
|
||
## How we teach this | ||
|
||
- Point to real PRs showing how it can be integrated | ||
- Aim to become part of the default create-react-native-app template | ||
tido64 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Unresolved questions | ||
|
||
- Manifest format | ||
- Versioning scheme |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.