A few weeks ago, I joined a project with 6 developers working on a React-Native application. I quickly faced a problem that I decided to tackle.
The purposes of this article are the following :
I also assume that you already know the principle of codepush and how it works. If this is not the case, please check the documentation.
The standard process at BAM is once the developer has developed his ticket, he has to deploy it on App Center and then test it on a real device (both iOS & Android). Finally, they can send it to the product owner for validation.
Just a few hours after arriving on my new project, something caught my attention: they were not testing their features on devices. They had codepush so I did not understand why.
I asked and here are the answers I had :
We are working on a medical application purpose. I was very surprised that the testing process was not executed every time & that it was silently ignored by all the team behind the famous “I don’t know. It's not me. It’s the tool.”
This was enough to arouse my curiosity.
This is the process that the members of the team were following to download the new codepush version in the app :
I took this process and here is what happened to me :
I've just given up on the idea of having my app updated one day.
At this point the question was: Indeed, why is it not working?
My first idea was to use the 3rd parameter of the function Codepush.sync(). This parameter allows you to define a function that takes into parameter the download progress. It gives you two pieces of information:
⇒ More details in the documentation.
I used this information to display a progress bar :
And this is what I saw (sorry for the bad quality):
I was able now to understand my problem! Codepush was working just perfectly. It was just that the download was taking a lot of time (more than 3 minutes sometimes !).
When I showed this to my team they were really happy. They were able to visualize the update process and wait for the update to finish. After this everybody began testing their features on both iOS & Android. But it was not satisfying enough for me.
I was curious to understand why it was taking so much time.
I quickly knew that the network was not the problem. I listen to music 24h/24h on Spotify at the office.
Something caught my attention. The size of the download: 105648704 bytes. It’s more than 100 Mo. Oh wow.
This was the metric I decided to follow: the Codepush bundle’s size. My goal was to reduce it as much as possible with low effort.
The best way to answer why the bundle was so heavy was to look into it. To do so, you have go on App Center and download your bundle manually. Then add prefix .zip and unzip it;
Inside the folder, the command du -hs ./* gives me these inputs.
A Codepush bundle contains 2 things :
The first surprise was the presence of source map files :
When your bundle your application, the bundler combines all your javascript files in a minified one (the .bundle). This file is not “human readable”. This is why you generally generate a source map file that holds the information of the original ones to help you during debugging process. You use it in development when you are debugging, or you upload it on your monitoring tool (like Sentry, Instabug, etc …).
There is no reason to have it in the codepush bundle. We needed to delete it.
Secondly, I took a closer look at two folders :
These folders contain… the assets of your project. More precisely every asset (images, videos, etc…) that you bundle import with require(). Let’s analyze it.
First I searched for the size of all the image files :
It’s a lot but it was not explaining the majority of the space. I just ignored it.
Secondly, I searched for the size of the audio files :
That time it was different. I finally had a strong explanation. We needed to find a way to reduce it ✅
For the deployment part we are using Fastlane :
These two lines of code are doing 3 things :
The problem is located in step 2. Indeed, it was uploading all the Codepush folder content (i.e. the bundle & the source map). After a small research, I found that it was a known issue: https://github.com/microsoft/appcenter-cli/issues/1451. The App Center team is aware of that but, at the moment, they are focused on maintenance.
The solution I implemented was to change the source map folder destination to not upload it on App Center. Then put it back on the Codepush folder to upload it on Sentry. The final script looks like this :
In less than 0.5 days of work, I reached the following result :
Like we said before we had a lot of mp3 files because of all the require() statements we add to our code. Why do we have that many audio files? The response is simple. At the beginning of the project, we were only supporting one language. And months after months, we added new languages. At the same time, this proportion of files slowly grew. And nobody noticed the impact of that.
We had 2 ideas :
We decided to use https://github.com/unimonkiez/react-native-asset. I’m not going to go deeper, but in the short term, this library allows you to link your assets directly inside the iOS & Android assets. As a result, you can’t anymore load them with require(). Depending on the library you are using you have to use a specific path. Find here an example for the Image component of React-Native: https://reactnative.dev/docs/images#images-from-hybrid-apps-resources.
In 1.5 days of work, I reached the following result :
Here is the report with the impact of all countermeasures implemented :
With these 2 improvements we were able to :
Following the Kaizen method also helped me in differents ways :
I hope you enjoyed it, learned something & gave you the curiosity to test this framework on you next challenge !