Preview Branches for React Native with Expo
Mo Khazali6 min read
A Github Action to automatically generate preview branches using EAS (Expo Application Services) as part of a CI/CD workflow, creating live deployments that allow the reviewer to functionally check any changes in the app before the feature is merged into staging.
React Native developers often get the short end of the stick when it comes to DevEx tools. Due to the sheer number of web devs, the React ecosystem far exceeds that of its native counterpart. A couple of years ago when I first saw Netlify’s preview deployments, I was absolutely awestruck. I thought a CI step that automatically generated a link where you could preview the built code was the coolest thing since sliced bread. Over the years, this has become standard on pretty much all JAMStack hosting platforms, including Vercel, Cloudflare Pages, AWS Amplify,…
Using Preview Branches, you can avoid verifying that your app works after merging code into production, and bring forward the verification process into the code review stage. This comes with a whole host of benefits, namely:
- Shorter feedback cycles between code reviews and functionally checking changes.
- End-to-end visibility of changes as a reviewer.
- Fewer regressions being merged into actual SDLC environments (incl. staging and prod)
Recently, we’ve been using preview branches on our React Native projects and we’re excited to share our Github integration for React Native apps using Expo!
The tools is built on top of EAS and eas-cli
which hosts the build and update processes on Expo’s cloud platform.
What is EAS?
EAS stands for Expo Application Services - it’s a suite of cloud services built by the folks at Expo. One of the major components of EAS is the build service. It basically allows you to build your app binaries, while abstracting away a lot of the complexity. EAS Build also handles over-the-air (OTA) updates for you. This means that so long as your native dependencies haven’t changed, you can push your app’s latest JS bundle to users and avoid needing to re-build.
Since we started using it, EAS has opened many doors to DevEx nirvana, including the prospect of Preview Branches! 🤩
CI Workflow Steps
The Github Action has 4 main steps:
- Install Expo & EAS ⚙️
- Generate Preview Deployment 🚀
- Post-merge Cleanup 🧹
- Deploy to
main
📲
1. Install Expo & EAS ⚙️
This step is pretty simple, and installs the dependencies needed to generate the preview branches (namely eas-cli
).
Expo has docs on how this can be setup, which are linked here.
2. Generate Preview Deployment 🚀
At this stage, we create a new deployment environment (using an EAS branch) and update with the latest version of the code. This workflow is triggered when a PR is:
- Opened
- Reopened
- Updated (new commits are added)
We use the eas update
command and generate a new branch with the same name as the branch name of the pull request. The output from eas update
’s JSON includes information like the Update ID and URI that can be used to preview the update in the Expo Go app.
We extract the necessary values from the JSON response, and generate a comment on the pull request that includes:
- A QR code that can be scanned to open up the deployed app in Expo Go.
- This is generated using Expo’s QR Code endpoint, which is what you see on the EAS website (
https://qr.expo.dev
).
- This is generated using Expo’s QR Code endpoint, which is what you see on the EAS website (
- A link to the update URI, as a fallback for the QR code.
If the user pushes an update to the branch, we re-run the workflow, replacing the previous comment to avoid a stale update QR/URI being shown.
3. Post-merge Cleanup 🧹
It’s important to ensure that we’re not generating dead branches on every PR. We’ll want to teardown the branch we’ve generated with Expo after a PR gets merged onto the main
branch or is closed. In order to do this, we have another workflow that runs on merge to main and deletes the channel and branch created by the EAS CLI when we called eas update
.
- name: Delete Channel
run: eas channel:delete ${{ github.head_ref }} --non-interactive
- name: Delete Branch
run: eas branch:delete ${{ github.head_ref }} --non-interactive
⚠️ Note: it’s important to delete the channel before the branch as you can’t delete a branch that has a single channel associated with it. This has to do with how Expo define the relationship between channels and branches.
4. Deploy to main
📲
Once a PR gets merged, there will be new commits being added to the repo’s main branch. As a final step, we will run eas update
on the main branch to make sure the app is updated fully.
The Result 🎉
We have fully automated ephemeral environments that are spun up when needed and torn down after the changes have been reviewed. 🙌
As shown below, a comment is added to every PR, where the reviewer is able to use their phone to scan the QR code and access the preview deployment of the app:
How to setup on your repo?
Prerequisites
- Github Actions setup on your repo
- Have an Expo project setup and hosted on Expo’s cloud services (docs)
⚠️ Note: we use the default install step from Expo, which uses yarn
by default. If you use a different package manager (npm
or pnpm
), you will need to adjust the workflow inside .github/actions/install
accordingly.
Setup Steps
We’ve created a repository with our workflow YAML files that you can clone and use in your own repos.
- Follow the Expo docs on setting up EAS CLI within your Github actions (mentioned in Step 1). This will require you to add a secret called
EXPO_TOKEN
which is mentioned in the Expo docs above. - Copy the entirety of
.github
folder into your app and push the changes.
⚠️ Note: If you have your own workflow that deploys to the main
branch, you can omit the .github/workflow/main-update.yml
file.
And that’s pretty much it! 🙌
Next Steps
We have a barebones CI/CD pipeline for mobile apps - the next steps would be to extend the ephemerality to our backend and database deployments to get fully ephemeral environments.
Obviously, our yaml
files are specific to Github Actions, but the steps should largely be common for any CI/CD tool, and can easily be ported over. As we expand to other CI/CD tools (such as GitLab CI), we will start porting over the same pipeline steps to utilise preview branching.
Feel free to reach out
If you have any opinions or suggestions to improve our CI/CD workflow, feel free to reach out to me on Twitter @mo__javad or open up an issue on Github. 🙂