Skip to content
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

CLI has a big delay in starting Android apps in newer versions of React Native #2012

Closed
rodrigo-nexudus opened this issue Jul 11, 2023 · 32 comments · Fixed by #2014
Closed
Assignees

Comments

@rodrigo-nexudus
Copy link

Environment

System:
OS: macOS 13.3.1
CPU: (8) arm64 Apple M1
Memory: 54.14 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 16.19.1
path: /var/folders/79/d8l5t8f510j93_0rvtf6cdh40000gn/T/yarn--1689079820992-0.6055964608057027/node
Yarn:
version: 1.22.19
path: /var/folders/79/d8l5t8f510j93_0rvtf6cdh40000gn/T/yarn--1689079820992-0.6055964608057027/yarn
npm:
version: 8.19.3
path: ~/.nvm/versions/node/v16.19.1/bin/npm
Watchman:
version: 2022.12.05.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.12.1
path: /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 22.4
- iOS 16.4
- macOS 13.3
- tvOS 16.4
- watchOS 9.4
Android SDK: Not Found
IDEs:
Android Studio: 2022.2 AI-222.4459.24.2221.10121639
Xcode:
version: 14.3/14E222b
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.7
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.72.1
wanted: 0.72.1
react-native-macos: Not Found
npmGlobalPackages:
"react-native": Not Found
Android:
hermesEnabled: false
newArchEnabled: false
iOS:
hermesEnabled: false
newArchEnabled: false

Description

Follow up to issue opened here

Details and testing on link above. It seems CLI is adding a noticeable delay (can be upwards of several minutes in complex projects) when starting up an Android app. In our project this delay hangs the process several minutes before eventually starting the "installation". This was caused in our case by updating from react native 0.67.5 to 0.72.1. Likely a general issue with all apps, exacerbated by complexity.

Reproducible Demo

Any app running newer versions of React Native should suffer from this, but the delay seems to be worse on apps with more libraries/complexity. Please refer to link above for some of the testing already done to rule out a runtime issue.

@cortinico
Copy link
Member

For context on the CLI folks, I believe this happens also on the react-native repo.

Namely you can reproduce with:

  1. git clone react-native
  2. yarn
  3. yarn android

You will see that it takes several seconds before the bundler actually starts

@thymikee
Copy link
Member

thymikee commented Jul 11, 2023

Looks like some kind of regression with Metro server discovery or Android config resolution. @szymonrybczak is investigating this

@rodrigo-nexudus
Copy link
Author

Hey @cortinico @thymikee @szymonrybczak unfortunately the update to React Native 0.72.4 has not fixed the issue. Still a delay of several minutes between "Starting JS server..." and "Installing the app...".

Any chance this can be opened again and reviewed? Thanks in advance!

@rodrigo-nexudus
Copy link
Author

@cortinico @thymikee @szymonrybczak this continues to be an issue, reported by other user as well here

@thymikee
Copy link
Member

@rodrigo-nexudus would you mind sharing some repro that would help us pin down the root cause?

@thymikee thymikee reopened this Aug 30, 2023
@rodrigo-nexudus
Copy link
Author

Hey @thymikee apologies for the delay in getting back to you. I've seen this in every project I've worked on in version 0.72 of React Native. It seems the more complex the project is, dependencies wise, the longer the delay is. In the most complex app I work on, the delay is 2-3 minutes, and this particular application has a lot of dependencies, different flavours and native code, but unfortunately I cannot share that particular project. The issue did crop up after an upgrade to 0.72 though.

I can create a repo with a lot of random dependencies if you like, but as far as I can tell this is affecting all projects. I mentioned this in the initial issue that was created on the React Native project here, and did some initial testing for @cortinico, who narrowed it down to the CLI and asked me to open this issue here.

@adamTrz
Copy link
Collaborator

adamTrz commented Sep 5, 2023

Hi @rodrigo-nexudus thanks for reporting
A while ago we've added interactive mode and are parsing all gradle tasks here:

export const getGradleTasks = (
taskType: 'install' | 'build',
sourceDir: string,
) => {
const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew';
const out = execa.sync(cmd, ['tasks'], {
cwd: sourceDir,
}).stdout;
return parseTasksFromGradleFile(taskType, out);
};

In an essence, we are running ./gradlew tasks command and then parsing it with RegExp to extract list of all available build and install tasks.
Do you think this could impact the build time and cause a delay?
Maybe you could check how long tasks command is taking in your project? 🙏

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 5, 2023

Hey @adamTrz thanks for your reply! I was under the impression this happened after the app begins the install process, and it actually outputs the tasks it needs to run on the console? The delay on our app is prior to the info Installing the app... output, so I don't think it's related?

The ./gradlew tasks command took just over 4 minutes to run, and showed the same output we usually see after the app begins installing, and therefore after the delay. Let me know if I misunderstood, but I don't think this is the cause.

As I mentioned before, the delay is between info Starting JS server... and info Installing the app... outputs on the console, with no output in between, so it almost seems like the command has frozen for those several minutes, as no feedback is shown

@adamTrz
Copy link
Collaborator

adamTrz commented Sep 5, 2023

That would make sense actually, we gather information on all available build types with gradle tasks command and then proceed to building and installing the app. So the output you see in console info Installing the app is printed after those steps.

You've mentioned that ./gradlew tasks is taking about 4 minutes to run. Can you also provide info how much time whole run android command is taking?

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 5, 2023

run android took 7:20, 3:41 of which were the delay. If that step happens prior to the Installing the app output, then it could definitely be the root cause. Our app has over 100 flavours (white-labelling for clients) and tasks runs for every flavour as far as I can tell, so that could add the kind of substantial delay we are seeing.

As the output from ./gradlew tasks is the same as we are seeing after info Installing the app, does that mean the command is running before that output silently, and then verbose after that output? Or is it two different commands that happen to have the same output? This is the other thing we are looking to resolve with regards to our long build times, as the run android command seems to prepare every flavour when it's run, even if we are building a specific flavour.

@szymonrybczak
Copy link
Collaborator

Hey @rodrigo-nexudus together with @adamTrz we crafted solution, would you mind to test it on your own? 🙏 Here you have got instructions how to get this running locally.

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 5, 2023

Hey @szymonrybczak , no luck unfortunately. I cloned the cli project, added your fix, linked the packages to our project, ran the app, but the delay is still there, in this case after info Metro Bundler is already for this project on port 8081., and still with no output.

Once the app moved on to installing, we could still also see all our flavours being run through, although again, that's a separate issue, just thought your fix might also affect that. But everything seems to be as it was before. And in case this comes up, yes we are running React Native 0.72.3, yes we tried 0.72.4, but it didn't fix our issue so we stayed on the version we were on.

I'm attaching a couple of screenshots below of the changes I've made. The app also didn't build so it's possible I did something wrong, so I will run it all again to be sure, but I followed all the steps detailed on the instructions.

Screenshot 2023-09-05 at 14 44 35

Screenshot 2023-09-05 at 14 51 10

I also ran time on the run android command, you can see the output on the bottom right of the second screenshot, about the same as previously mentioned

@rodrigo-nexudus
Copy link
Author

Hey @szymonrybczak and @adamTrz I've re-run everything today with a bit more time and can confirm the above solution did not fix the delay. All as mentioned on my previous comment, about 4 minutes before info Installing the app... pops up on console. I re-linked all the packages to make sure I didn't miss something last time, I can see the change within node_modules, and running everything as per the link provided.

@cortinico
Copy link
Member

Just a little side note:

The ./gradlew tasks command took just over 4 minutes to run, and showed the same output we usually see after the app begins installing, and therefore after the delay. Let me know if I misunderstood, but I don't think this is the cause.

@rodrigo-nexudus if ./gradlew tasks takes more than say, 20/30 seconds, there is something really odd going on with your build. That should not be the case.

Also @adamTrz, we should not be running ./gradlew tasks at all, unless the user is in interactive mode.

@rodrigo-nexudus
Copy link
Author

Hey @cortinico as I've mentioned before, our app is pretty complex. We have a lot of native code and SDKs and over 100 flavours. When I run ./gradlew tasks, it seems to run the tasks for all of the flavours on our app, which looks to be a sizeable chunk of the time, but still only half of the about 4 minutes it takes (I've just run it again, 4:53).

This didn't happen to us on previous versions of React Native, we went from 0.69 to 0.72 and that is when this delay started happening.

@robhogan
Copy link
Collaborator

robhogan commented Sep 7, 2023

When I run ./gradlew tasks, it seems to run the tasks for all of the flavours on our app

Has that changed since previous versions?

(I wonder whether this could be task cache invalidation caused by a shelling out to node for resolution)

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 7, 2023

@robhogan from my side I can't tell if that has changed, as I never ran ./gradlew tasks explicitly before running into this issue. But the delay, whatever it is caused by, was not there.

(I wonder whether this could be task cache invalidation caused by a shelling out to node for resolution)

I tried enabling org.gradle.caching=true in gradle.properties, no difference.

One thing that has made a difference was commenting out all flavours from build.gradle, other than the one I am explicitly building. The delay goes down from around 4 minutes to about 20 seconds. Build as a whole down from 7-8 minutes to about 1 minute. So it seems the flavours are the culprit, which I thought might be the case, but commenting them out is not a great fix, and we already had this number of flavours with no delay in prior versions of React Native. Ideally the run-android command should only run tasks that are relevant to the flavour that has been passed to it.

@robhogan
Copy link
Collaborator

robhogan commented Sep 8, 2023

@robhogan from my side I can't tell if that has changed, as I never ran ./gradlew tasks explicitly before running into this issue.

Are you able to go back via source control to before the upgrade and try it? That'd also help confirm that the upgrade is the cause.

In the absence of a repo project any concrete difference (eg, tasks run now that didn't previously) that we might be able to reproduce would be super helpful.

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 8, 2023

Hey CLI team, I followed the suggestion by @robhogan and reverted to a commit with React Native 0.71.11. No delay there, immediately goes from info Starting JS server... to info Installing the app.... So it was definitely something changed for 0.72.

As for a repo project, I am happy to create a sample one, but I think all you would need to do is create a new react native app and add a lot of flavours to build.gradle, as removing those on the current version of our app eliminates the delay. Whatever the build process is doing during that delay, it is related to doing it for every flavour present on the codebase.

@robhogan
Copy link
Collaborator

robhogan commented Sep 8, 2023

@rodrigo-nexudus were you able to try ./gradlew tasks on a pre-update revision as well? Interested to know whether that's noticeably different.

Otherwise, now that you can repro the difference at the end-to-end build level, it'd be great if you can narrow it down to a bit further.

@rodrigo-nexudus
Copy link
Author

rodrigo-nexudus commented Sep 8, 2023

RN-0-71-11.txt
RN-0-72-3.txt

Here's the output of ./gradlew tasks on 0.71.11 and 0.72.3. To save you some time, they look really similar, the only major difference is the 0.72.3 version does the following on top of all 0.71.11 does:

Publishing tasks
--
  |   |   |   | 2791 | ----------------
  |   |   |   | 2792 | generateMetadataFileForMavenPublication - Generates the Gradle metadata file for publication 'maven'.
  |   |   |   | 2793 | generatePomFileForMavenPublication - Generates the Maven POM file for publication 'maven'.
  |   |   |   | 2794 | publish - Publishes all publications produced by this project.
  |   |   |   | 2795 | publishMavenPublicationToMavenLocal - Publishes Maven publication 'maven' to the local Maven repository.
  |   |   |   | 2796 | publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.

This is related to a custom repository for a new SDK we have added, and should not be the cause of the issue.

Other than the above, they take a similar amount of time and run tasks for every flavour within our application. @robhogan I'm not sure how you want me to narrow it down further, if tasks wasn't running before at that point and is now, and tasks is made much slower by having a lot of flavours.

@hungvu193
Copy link

I still have the delay issue with the react-native version 0.72.4.
A workaround can be using the native android command:

cd android && ./gradlew installdevelopmentDebug // replace installdevelopmentDebug with your flavor that you want

However with this, you need to start the metro bundler yourself.

@rodrigo-nexudus
Copy link
Author

Hey CLI team, any chance we can get an update on this? The initial fix provided did not resolve the issue, and the delay is very lengthy, meaning building takes close to 10 minutes. I would really appreciate a solution to this, as I'm sure others here and in the main React Native repo thread would.

Thanks in advance!

@thymikee
Copy link
Member

@rodrigo-nexudus we'd appreciate a reproducible example which we could inspect. Otherwise it's shooting in the dark

@hungvu193
Copy link

Hey @thymikee, I think here's great example I believe: https://github.com/Expensify/App
React native version: 0.72.4

@TMisiukiewicz
Copy link
Collaborator

hi @hungvu193 thanks for the repro, checked it by myself and I can confirm it takes ~10mins to build the app. Gonna take a look on this next week 👍

@TMisiukiewicz
Copy link
Collaborator

Hi @hungvu193 @rodrigo-nexudus I opened a PR #2144 , already tested it with Expensify, but if you have any other complex app to test it with, feel free to follow the contributing guide and give it a try. Let me know if you run into any issues

@hungvu193
Copy link

@TMisiukiewicz I'll test it and let you know! Thank you for your amazing work 🙇

@hungvu193
Copy link

@TMisiukiewicz I can confirm it worked 🚀

Screen.Recording.2023-10-31.at.16.41.49.mov

Dummy question, how do you test this PR within an existing project? I tried "resolutions" in my package json to override current react-native-community/cli version but it didn't seem to work.

  "resolutions": {
    "@react-native-community/cli": "git+https://github.com/react-native-community/cli.git#e17764a20951d5b9c2ba948cd2d8417c70a2c9e4"
  }

@TMisiukiewicz
Copy link
Collaborator

Amazing, happy it works!

Dummy question, how do you test this PR within an existing project? I tried "resolutions" in my package json to override current react-native-community/cli version but it didn't seem to work.

  "resolutions": {
    "@react-native-community/cli": "git+https://github.com/react-native-community/cli.git#e17764a20951d5b9c2ba948cd2d8417c70a2c9e4"
  }

You can clone my fork, checkout branch from the PR, then follow the Contributing guide and link local packages in your project. Alternatively, if you don't want to link them, you can just point to the main script using node, eg. node path/to/cli/packages/cli/build/bin.js run-android

@hungvu193
Copy link

Amazing, happy it works!

Dummy question, how do you test this PR within an existing project? I tried "resolutions" in my package json to override current react-native-community/cli version but it didn't seem to work.

  "resolutions": {
    "@react-native-community/cli": "git+https://github.com/react-native-community/cli.git#e17764a20951d5b9c2ba948cd2d8417c70a2c9e4"
  }

You can clone my fork, checkout branch from the PR, then follow the Contributing guide and link local packages in your project. Alternatively, if you don't want to link them, you can just point to the main script using node, eg. node path/to/cli/packages/cli/build/bin.js run-android

Awesome and I'll give it a try! 👍

Copy link

There hasn't been any activity on this issue in the past 3 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants