Cover image by Phil Roeder on Flickr
UPDATE 02.06.2019: Expo v33 pre-view came out! Now Web builds work alongside Android and iOS builds, so I updated this post.
I'm currently working on my next video course called MVPs with AWS. It's about building Minimal Viable Software Products with AWS technology with a focus on serviceful serverless approaches.
I did customer interviews for that course; they revealed that people want to build cross-platform apps right at the start, so the front-end tech I choose was Expo. Expo lets us build Android and iOS apps with the JavaScript and React skills we already have from the web. In the v33 release, they also allow building PWAs with the help of react-native-web. This universal app approach allows having one front-end code-base for three platforms.
Customers also care about continuous delivery and tooling that eases the interaction with AWS, so I choose AWS Amplify with its SDK, CLI, and Console. Amplify offers a JavaScript SDK which integrates nicely with Expo and the CLI helps to build serverless backends without the need to get too deep into CloudFormation right from the start. With the Amplify Console, we can automate the deployment of backend and frontend on every push to our repository.
If you want to get updates to this project just follow me on Twitter
What
We will set up an Expo project configured for Android, iOS and Web builds with an Amplify controlled backend.
We need the following tools:
AWS Cloud9
A cloud-based IDE that can be accessed via a browser. It comes with Node.js, npm and the AWS SDK pre-installed. We could install these tools manually on our own if we want to use another editor.
GitHub Repository
The continuous delivery is triggered by Git commits, so we need a repository the Amplify Console can watch.
Expo
We use the Expo CLI to init a project and build an Android, iOS and Web client from it later.
AWS Amplify
We will use the Amplify CLI and Console. The CLI is used to add Amplify features to our Expo project, and the Console is used to watch our Git repository for commits that will trigger builds and deploys.
How
Prerequisites
An AWS account and a Cloud9 environment. This is pretty straight forward to set up, but people who struggle with it can look at the first five steps of this article.
A GitHub account.
The setup will consist of seven steps:
- Create an Expo Account and Login
- Initialize Expo Project
- Add Script and Dependencies
- Initialize Amplify Project
- Commit Amplify files to Git
- Set up and push changes GitHub Repository
- Set up and run Amplify Console Build
1. Create an Expo Account and Login
First, step is to create an Expo account, so our published Android and iOS projects will be automatically available on the Expo-Client.
Account Creation
An Expo account is totally free and can be created here.
Download and Login with Expo Client
We need to install the Expo client for the mobile platform of our choosing. The Android client can be found in the Play Store
After the install, we need to log in with our freshly created Expo account. This will make projects we published with the Expo-CLI available in the client automatically.
Login with the Expo-CLI
To log in with the Expo-CLI, we just need to run the login command, this will create some files in our ~/.expo
that keeps track of our login state.
npx expo-cli login -u <USERNAME> -p <PASSWORD>
2. Initialize Expo Project
Next, we create a new project with the help of the Expo CLI tool.
npx expo-cli init universal-app --template blank@next
We give the project the name "Universal App".
3. Add Scripts and Dependencies
We need to install the expo-cli
package as devDependency
. Installing global dependencies locally in the package.json
makes them available as if they were global inside the npm scripts.
cd universal-app
npm i -D expo-cli
At the moment of writing, Expo projects come without a build or publish script; we need to add this to our package.json
.
Adding a build
script to the package.json
s scripts
section:
{
...
"scripts": {
"login": "expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD",
"build": "expo build:web",
"publish": "expo publish --non-interactive",
...
},
...
}
The build script is needed for the web build, so Amplify Console can build and deploy it to AWS.
The publish script is needed for the Android and iOS build, so Expo will build and publish to the Expo clients on these platforms.
Since it uses the Expo infrastructure, it needs username and password.
We use environment variables for this, so the Expo credentials don't show up in the logs.
4. Initialize Amplify Project
Next, we have to add Amplify support to our project. Cloud9 uses a different file-name to store AWS credentials than the Amplify CLI expects, so we have to create a symlink before we can initialize the project.
ln -s ~/.aws/credentials ~/.aws/config
npx @aws-amplify/cli init
This will ask us a few questions. We choose these answers:
? Enter a name for the project universal-app
? Enter a name for the environment dev
? Choose your default editor: None
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using react-native
? Source Directory Path: /
? Distribution Directory Path: /web-build
? Build Command: npm run-script build
? Start Command: npm run-script start
Using default provider awscloudformation
? Do you want to use an AWS profile? Yes
? Please choose the profile you want to use default
This will create a basic Amplify backend infrastructure in the cloud; IAM roles, S3 buckets for the deployment of generated CloudFormation templates, etc.
5. Commit Amplify files to Git
The Amplify Console will build our project when we push any changes to a remote Git repository, so we need to get our changes into Git before we move on.
Then we can add all our new files and do an initial commit:
git add -A
git commit -m "Init"
6. Set up and push changes to GitHub Repository
A new GitHub repository can be set up here. Let's call it like our project universal-app. To keep it simple, we create a public repository.
We also need to set up SSH authentication for our Cloud9 machine on Github.
A key-pair can be generated with:
ssh-keygen
We can look it up at our Cloud9 machine with:
tail /home/ec2-user/.ssh/id_rsa.pub
The public key needs to be given a title and pasted here.
After the creation, we can push our local changes:
git remote add origin git@github.com:<GITHUB_USERNAME>/expo-web-app.git
git push -u origin master
7. Set up and run Amplify Console Build
Now that we have our project created, configured and up on GitHub, we can set up the Amplify Console to do our build.
To connect we need to go here.
I use eu-west-1
here, but you can use whatever region you like.
Choose GitHub as a provider and the universal-app
repository we created, with branch master
.
In the following form, we get asked a few things for the setup.
Would you like Amplify Console to deploy changes to these resources with your frontend?
Yes, we want. Let's choose the dev
environment we created with the Amplify CLI. This is necessary if we wanted to add other Amplify features.
Select an existing service role or create a new one so Amplify Console may access your resources.
We need to create a new IAM role for this, but the process is done via a wizard. Only clicking Next until finished. Then we go back to the form, refresh the roles and add our newly created amplifyconsole-backend-role
The build settings need to be edited. They were created automatically, but need to be tweaked a bit for Expo Web builds.
version: 0.1
backend:
phases:
build:
commands:
- amplifyPush --simple
frontend:
phases:
preBuild:
commands:
- echo fs.inotify.max_user_watches=524288 | tee -a /etc/sysctl.conf && sysctl -p
- npm ci
- npm run login &
- sleep 2s
build:
commands:
- npm run publish --non-interactive
- npm run build
artifacts:
baseDirectory: web-build
files:
- '**/*'
cache:
paths:
- node_modules/**/*
- $(npm root --global)/**/*
- Increase the file watchers for the system, otherwise
expo publish
will fail later. -
npm ci
runs so all dependencies (includingexpo-cli
) are installed. - Run the login script but don't wait for it to finish (&), otherwise the build will freeze.
- Sleep two seconds, so the login script has some time to do its thing.
- Build and publish the Android and iOS versions to the Expo Client
- Build the Web version to Amplify
We also need to set up the Environment Variables for the Expo CLI login. We have to add variables named EXPO_USERNAME
and EXPO_PASSWORD
here filled with the corresponding values we used when we created an Expo account.
After this, we can click on Next and then Save and Deploy.
Bonus: Push a Change to Trigger Build
Now that everything is up and running, we can change a file and push it to our remote repository at GitHub and watch the Amplify Console magic happen.
Let's change the text in our App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Awesome universal Expo app backed by AWS Amplify!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Add the changes, commit, and push it.
git add -A
git commit -m "Change text"
git push
We can watch the builds here.
Conclusion
When Expo version 33 is released we will be able to leverage Expo on iOS, Android and the Web with one code-base without sacrificing the power of native UI widgets.
Amplify accelerates this development even more by easing the pain of managing AWS services and leveraging the full force of serviceful serverless computing and providing one back-end for Android, iOS and Web clients.
I believe this stack to become a solid foundation to build apps for years to go.
Here is the project code