arrow icon
REGISTER

How Can Continuous Integration (CI) Improve Your React Native Apps?

2023-02-13
Download your copy of the
Ultimate Guide to React Native Optimization

blog content

Need help with Performance Optimization? 
hire us
Need help with Super app development
hire us
Need help with React Native?
hire us
Need help with migration to React Native?
hire us
Our React Native EU Conference is back
register nowlearn more

The following article is a part of The Ultimate Guide to React Native Optimization and describes how to improve your apps through Continuous Integration (CI). It’s been co-authored by Expo, who shared their insights on setting up EAS Build and running your build on it.

Why is it important?

A lack of working Continuous Integration may seriously harm your apps on many different levels. It can slow down the development process and testing, and expose your final app to bugs and regressions that may decrease your income. In this article, I'll show you how to bulletproof your React Native app for such unpleasant situations with Continuous Integration.

In the previous parts of our guide, we have discussed:

Check them out later, and now let's jump into the main topic.

Many faces of feedback loop in app development

As you have already learned from our other article in this series, covering your code with tests can be very helpful for increasing the overall reliability of your app. However, while testing your product is vital, it is not the only prerequisite on your way to shipping faster and with more confidence.

Equally important is how quickly you detect the potential regressions and whether finding them is a part of your daily development lifecycle. In other words – it all comes down to the feedback loop.

How long feedback loop (and no CI) can harm your React Native project

For better context, let’s take a look at the early days of the development process. When you’re starting out, your focus is on shipping the first iteration (MVP) as fast as possible. Because of that, you may overlook the importance of the architecture itself. When you’re done with the changes, you submit them to the repository, letting other members of your team know that the feature is ready to be reviewed.

An example of workflow on Github where changes are proposed in a form of a PR graph
An example of workflow on Github where changes are proposed in the form of a PR.

While this technique can be very useful, it is potentially dangerous on its own, especially as your team grows in size. Before you’re ready to accept a PR, you should not only analyze the code, but also clone it to your environment and test it thoroughly. At the very end of that process, it may turn out that the proposed changes introduce a regression that the original author hasn’t spotted.

The reason for that is simple - we all have different configurations, environments, and ways of working.

concept of correct code
It’s harder to onboard new members to your organization. You can’t ship and test PRs and different contributions as they happen.

If you’re testing your changes manually, you’re not only increasing the chances of shipping regressions to production. You’re also slowing down the overall pace of the development. Thankfully, with the right set of methodologies and a bit of automation, you can overcome this challenge once and for all.

What is Continuous Integration and how does it work?

This is when Continuous Integration (CI) comes into play. CI is a development practice where proposed changes are checked-in to the upstream repository several times a day by the development team. Next, they are verified by an automated build, allowing the team to detect changes early.

The automated builds are performed by a dedicated cloud-based CI provider that usually integrates with the place where you store your code. Most cloud providers available these days support Github, a Microsoft-owned platform for collaborating on projects that use git as their version control system.

CI systems pull the changes in real-time and perform a selected set of tests, to give you early feedback on your results. This approach introduces a single source of truth for testing and allows developers with different environments to receive convenient and reliable information.

Using a CI service, you can not only test your code but also build a new version of documentation for your project, build your app, and distribute it among testers or releases. This technique is called Continuous Deployment and focuses on the automation of releases.

<p-bg-col>Following the Circle CI section, you'll find a section on EAS Build in this chapter. Why? We believe having a subsection about EAS Build also helps developers achieve results as with CircleCI.<p-bg-col>

Using a Continuous Integration provider to build your React Native app

There are a lot of CI providers to choose from, with the most popular being CircleCI, GitHub Actions, and Bitrise. For React Native applications, another option is EAS Build, a service created by Expo with first-class support for React Native.

We have selected CircleCI as our reference CI provider for the purpose of this section, as it has broad community adoption. In fact, there is an example project demonstrating the use of CI with React Native. You can learn more about it here. We will employ it later in this section to present different CI concepts.

We will also dive into EAS Build, which is designed to make building and testing applications as easy as possible. It also helps with distributing app binaries to the stores and internally amongst your team.

<p-bg-col>Note: A good practice is to take advantage of what React Native / React Native Community projects already use. Going that route, you can ensure that it is possible to make your chosen provider work with React Native and that the most common challenges have been already solved by the Core Team.<p-bg-col>

‍How to set up CI with CircleCI

With most of the CI providers, it is extremely important to study their configuration files before you do anything else.

Let’s take a look at a sample configuration file for CircleCI, taken from the mentioned React Native example:

The structure is a standard Yaml syntax for text-based configuration files. You may want to learn about its basics before proceeding any further.

<p-bg-col>Note: Many CI services, such as CircleCI or Github Actions, are based on Docker containers and the idea of composing different jobs into workflows. Github and its Github Actions is an example of such provider. You may find many similarities between those services.<p-bg-col>

Commands, jobs, and workflows in CircleCI configuration

There are three most important building blocks of a CircleCI configuration: <rte-code>commands<rte-code>, <rte-code> jobs<rte-code>, and <rte-code>workflows<rte-code>.

<rte-code>command<rte-code> is nothing more but a shell script. It is executed within the specified environment. Also, it is what performs the actual job in the cloud. It can be anything, from a simple command to install your dependencies, such as <rte-code>yarn install<rte-code> (if you’re using Yarn) to a bit more complex one <rte-code>./gradlew assembleDebug <rte-code> that builds Android files.

<rte-code>job<rte-code> is a series of commands - described as steps - that is focused on achieving a single, defined goal. <rte-code>jobs<rte-code> can be run in different environments, by choosing an appropriate Docker container.

For example, you may want to use a Node container if you need to run only your React unit tests. As a result, the container will be smaller, have fewer dependencies, and will install faster. If you want to build a React Native application in the cloud, you may choose a different container, e.g. with Android NDK/SDK or the one that uses OS X to build Apple platforms.

To help you choose the container to use when running React Native tests, the team has prepared react-native-android Docker container that includes both Node and Android dependencies needed to perform the Android build and tests.

In order to execute a <rte-code>job<rte-code>, it has to be assigned to a <rte-code>workflow<rte-code>. By default, <rte-code>jobs<rte-code> will be executed parallelly within a workflow, but this can be changed by specifying requirements for a <rte-code>job<rte-code>.

Example of Workflow chart
Workflow contains jobs that can be grouped to run in a sequence or in parallel

You can also modify the job execution schedule by adding filters, so for instance a deploy job will run only if the changes in the code refer to a master branch.

You can define many workflows for different purposes, e.g. one for tests that would run once a PR is opened, and the other to deploy the new version of the app. This is what React Native does to automatically release its new versions every once in a while.

Setting up EAS Build

EAS stands for Expo Application Services. One of the services it provides is EAS Build. In contrast with a generic CI provider, it is designed for building and testing React Native applications, handles app-signing credentials and internal distribution amongst your team members, and also closely integrates with EAS Submit to automate app store submissions.

EAS Build is a managed service. This means many workflow steps that are traditionally manually defined in a generic CI provider are handled automatically. It also uses a new build environment for each build job with the tools such as the Java JDK, the Android SDK and NDK, Xcode, Fastlane, etc. already installed.

You can get started by following just a few steps below on your development computer. After these steps, you will have set up your project for EAS, configured your build profile, and started a build job.

‍Running an EAS Build

First, install the <rte-code>eas-cli<rte-code> package by running this command in your terminal:

Or, you can use <rte-code>npx eas-cli<rte-code> to run the commands if you’d like to avoid installing a global dependency.

Setting up EAS Build

Next, initialize a configuration file for EAS Build and run this command in the root directory of your project:

This command will create a file named <rte-code>eas.json<rte-code> in the root directory of your project. It contains the whole config for EAS to run properly.

Your project may need some additional configuration for cases like using a monorepo. Read this guide to see how to configure your build profile further.

<rte-code>eas.json<rte-code> is a text-based configuration file that uses standard JSON syntax. Inside, you will find a top-level field named <rte-code>build<rte-code>. This field contains a JSON object with all of the configuration that defines your app’s build profiles. A <rte-code>build profile<rte-code> is a named group of configuration options that describe the necessary parameters to create specific types of builds, like for internal distribution or an app store release.

The JSON object under <rte-code>build<rte-code> contains multiple profiles. By default, the <rte-code>development<rte-code>, <rte-code>preview<rte-code>, and <rte-code>production<rte-code> are the three build profiles provided. The <rte-code>development profile<rte-code> is for debug builds that include developer tools and is mainly used during development and testing. The <rte-code>preview<rte-code> profile doesn’t include developer tools and is for builds intended to be shared with your team when testing your app in a production-like environment. Finally, the production profile is for release builds that are submitted to app stores.

You can define additional custom profiles under the build field for specific types of builds to best fit your project and team’s needs. Additionally, each profile can also have platform-specific configuration for Android and iOS.

Running your build on EAS Build

Any type of build can be triggered from a single command. For example, you can use <rte-code>preview<rte-code> profile to share the app with your team for testing:

The <rte-code>--platform all<rte-code> option lets you build for Android and iOS at the same time.

A build profile that has its <rte-code>distribution<rte-code> field set to <rte-code>“internal”<rte-code> (as shown in the example <rte-code>eas.json<rte-code> configuration earlier) configures EAS Build to provide shareable URLs. Once the build is complete, this URL can be shared with your teammates for internal distribution. By using the URL, any member of your team can download the app to their device.

You can modify a build profile anytime during the development lifecycle of your project. In some cases, additional configuration may be required or useful, like when working on a project inside a monorepo or sharing configuration between different profiles.

With CI, you get early feedback on added features, swiftly spot the regressions, and save time

‍A properly configured and working CI provider can save you a lot of time when shipping a new version of an application.

GitHub UI reporting the status of CircleCI jobs, an example taken from React Native repository

By spotting errors beforehand, you can reduce the effort needed to review the PRs and protect your product against regressions and bugs that may directly decrease your income.  

With a managed service tailored to Expo and React Native like EAS Build, caching JavaScript, Android, and iOS dependencies is done automatically. There is no need to configure your build steps for caching and all build jobs are accelerated by default.

Interested in improving your React Native app?

We are the official Facebook partners on React Native. We’ve been working on React Native projects for over 5 years, delivering high-quality solutions for our clients and contributing greatly to the React Native ecosystem. Our Open Source projects help thousands of developers to cope with their challenges and make their work easier every day. Our React Native development company offers a wide range of services.

Contact us if you need help with React Native or cross-platform development. We will be happy to provide a free consultation.

Author:
Mike Grabowski
Co-founder & Supervisory Board Member
arrow icon
MORE posts from this author

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

learn more

More posts from this category

Ensure your React components perform as intended as your app grows

Discover Reassure - our open-source library that allows you to run performance tests measuring the average rendering time of the in-app components.

business benefits

Performance Optimization

To stay competitive, you need a high-performing app. Improving React Native performance can bring your company many business and tech benefits. To learn more about it, check the page entirely dedicated to React Native Performance Optimization. Discover a real-life example of React Native optimization we performed for Aaqua, a Singaporean platform that enables global users to share their passion through groups.

Bundle React Native apps using Webpack features

Discover Re.Pack – a Webpack-based toolkit that allows you to build a React Native app with the full support of the Webpack ecosystem.

business benefits

Why React Native?

Building an all-in-one platform can bring your company a lot of business and tech benefits like seamless UX experience, global reach, brand growth just to name a few. To learn more about the benefits of using React Native to develop super apps, check out the MoMo case study. Where we helped improve app's performance by migrating architecture to Re.Pack.

stay tuned

Subscribe to our newsletter

You may unsubscribe from these communications at any time. For details see the Privacy Policy.