Below are the objectives that drove the design of this solution.
-
Universal App (Mobile, Web, and eventually TV) - This app uses Expo to enable using a single code base to deploy mobile, web, and tv apps.
-
Offline First - This app should be capable of running offline as well as online with realtime updates streaming to the app when updates are made in other apps.
-
Container Based Development - The development environment is setup to run in a Docker container.
-
Scalable Development Model - The solution is designed to support the deployment of multiple environments that would be useful for a team based development model. This includes individual development environments, preview environments that can be used for external user testing, and a production environment.
-
Concept to Cash - While not achieved yet, ultimately the goal is to setup this repo as a starting point that provides a complete development pipeline for you. Designed to handle standard flows for:
- Initial Environment Setup for Local Dev, Shared Preview, and Production
- Local, offline development, testing, and debugging
- Source Control Management <-- Not Added Yet
- Continuous Integration and Continuous Deployment <-- Not Added Yet
- Production Monitoring <-- Not Added Yet
- Collecting Payments <-- Not Added Yet
-
IDE - VS Code - The development environment was built assuming the user is using VS Code. While we have avoided using VS Code specific flows (like using VS Code posts for development activities), we have not explicitly designed the code base or tested it to see if the flows work outside of VS Code. Instructions on performing setup activities will assume you are working in VS Code.
-
Containerization - Docker - Used to enable setting up development environments across multiple platforms: Windows, Mac, or Linux.
-
Source Code - Git - Used for source control with remotes hosted on GitHub.
-
Monorepo - Nx - Used for manage aspects of working in a monorepo.
-
Code - TypeScript - Used to provide type saftey.
-
Development Framework - Expo - Used to provide the universal app development model.
-
Mobile Framework - React Native - Foundation for mobile app development.
-
Transpilation - Babel - Used for transpiling typescript.
-
Bundling - Metro - Used for bundling the web and mobile app.
-
Static Code Analysis - ESLint & Prettier -
-
Mobile Builds and Deployments - EAS - Expo's EAS services are used to build and deploy IOS and Andriod mobile apps.
-
Backend, Web Hosting, & Offline Storage - Amplify - Used for providing backend services for authentication and data sync. This also includes enabling offline storage on both mobile and web.
To run the vscode tasks: press cntrl/cmd + shift + p then type "run task" then select the task named in the step.
Our approach for establishing the full development ecosystem for your solution starts first with setting up a repository to store you code.
- Setup GitHub Account.
- Create a new repo using this repo as the template. At the top right of the repo in GitHub click the green 'Use this template' button and selec 'Create a new repository'.
- Clone Repo - Clone the repo you created
git clone <your repo url>
- Start IDE - Open in Visual Studio.
cd my-solution
code .
- Open In Container - Open the workspace in a development container.
NOTE: The devcontainer.json file is set to forward port 19001 to your container. This port is used by Expo to connect your dev build on a physical device to the metro server hosted in your container.
You can change this if you like. Just make sure to find all other references to 19001 in the solution files and update them as well.
Cntrl+Shift+P
"Reopen in Container"
- Install - Install the project depdendencies using npm.
npm install
- Claim Project - Run the claim-workspace.js script.
- Argument 1: Solution Name - This script updates all references from 'my' or 'My' to your solution name.
- Argument 2: Company Slug - This value will be cast to lower case and inserted into the app identifiers. Ex. com.stewartarmbrecht.myapp.com.
- Argument 3: IP Address - Sets your host maching IP address in the .env file in the root of the project. This enables the expo dev build to connect to your metro server hosted in the container.
node ./tools/scripts/claim-project Better BoundByBetter 10.24.1.57 19001
- Rebuild Dev Container - After you have 'claimed' the project rebuild the container.
Cntrl+Shift+P
"Rebuild Container"
-
Create Amazon account if you don't already have one: Sign Up for AWS
-
Initialize Amplify You need to initialize amplify to create some local files so that you can run the app. Note: if amplify is not recognized as a command I have found that rebuilding the container will fix this. Just press Cntrl+Shift+P and then type Rebuild Container and select the Dev Container command.
npx nx amplify-init <solutionName>-backend
- Environment Name: prod
- Default Editor: Visual Studio Code
- Authentication: AWS Profile
- New User: Yes
- Region: Your choice.
- Amplify CLI User: Click the link and follow the instructions to set a user that your Amplify CLI will use to connect to AWS. Set a name that will help you identify the cli running in your dev container. If you are connecting to a shared AWS account consider adding a name like: mySolutionBackend-
- accessKeyId: Copied from access key created in instructions provided.
- secretAccessKey: Copied from access key created in instructions provided.
- Profile Name: (default)
- Profile to Use: default
- Create amplify backend resources.
npx nx amplify-push <solutionName>-backend
- ✔ Are you sure you want to continue? (Y/n): Yes
- ? Do you want to update code for your updated GraphQL API (Y/n): No
- Run the app to verify the setup. To run the app you need to export the ip address of your machine and set the port for the javascript bundle to the value you set above then start the app. This command will start the app in web mode:
vscode task: metro
or
npx nx start my-app
w <- type 'w' to launch a browser and push metro through the first build.
To debug the web app, just open the browser devTools. Be sure to install the React Developer Tools and the Redux Developer Tools add ons to help debug the application.
- Run all unit tests and verify success.
vscode task: test
or
npx nx run-many -t test
- Create an Expo Account: Expo Sign Up
- Remove eas project id and updates URL. In the app.config.js, comment out 'updates' and the 'extra.eas' sections so it looks like this:
...
// updates: {
// url: 'https://u.expo.dev/0b1aa1f3-a7d9-4a39-8bfe-024107fcfbdb',
// },
...
extra: {
// This is the project ID from the previous step
// eas: {
// projectId: '0b1aa1f3-a7d9-4a39-8bfe-024107fcfbdb',
// },
},
...
- Create a build:
vscode task: build-dev
or
npx nx build-dev my-app
- Email or username: [from the EAS account you created]
- Password: [Your EAS password]
- Select Platform: [Select the one you want]
- Would you like to automatically create an EAS project for @stewartoutlook/my-app? Y
You will get an error because the project uses dynamic app configuration. Follow the instructions to update the app.config.js file with your expo.extra.eas.projectId property.
Warning: Your project uses dynamic app configuration, and the EAS project ID can't automatically be added to it.
https://docs.expo.dev/workflow/configuration/#dynamic-configuration-with-appconfigjs
To complete the setup process, set "extra.eas.projectId" in your app.config.js:
{
"expo": {
"extra": {
"eas": {
"projectId": "[your id]"
}
}
}
}
...
- Edit app.config.js using the directions above.
While you are updating this file from the directions above. You should also set the updates.url in the file.
Change the guid in the url to match the value you set for your projectId above.
updates: {
url: "https://u.expo.dev/fbd799b8-ac94-42ee-83ff-194ce23b9a59"
},
You should also update the owner to match your account:
owner: "stewartarmbrecht"
- Rerun the build:
vscode task: build-dev
or
npx nx build-dev my-app
- Install development build by scanning the QR Code
This creates an local instance of the development APK for using Detox to test.
vscode task: build-dev-detox
or
npx nx build-dev-detox my-app
- Setup Genymotion account: Create Account
- Log into Genymotion SaaS using a token: Create Token
gmsaas auth token
- Run detox tests:
vscode task: test-e2e-mobile
or
npx nx test-e2e-mobile my-app-e2e
After you have installed the development build. Run the app:
vscode task: run
or
npx nx start my-app
Then scan the QR Code with your phone. The app should be running on your phone. If you have a problem with the preview app being loaded from the dev server QR code, then just enter the URL manually in the dev instance of the app. The URL should be http://:
First you need to build a local instance of the android app:
vscode task: local-build-dev-android
or
npx nx local-build-dev-android my-app
Once you have built a local dev instance you can deploy it to your android emulator:
vscode task: run-android-geny
or
npx nx run-android-geny my-app
- Start App: Start the app use the instructions for Running the development build on a physical device above.
- Open Browswer: Open Edge or Chrome and enter
edge://inspect
orchrome://inspect
- Set Network Targets: Next to Discover network targets click configure and enter your host machines ip address and the port you started the development build on (ex. 19001)
- Inspect Hermes React Native: Click the 'inspect' link under Hermes React Native shown under remote targets.
- Find Code: To find the code hit Cntrl-P and type in the name of the code file.
//TODO: Load the code into the workspace. - Break Points: Breakpoints did not work for me. Instead I added
debugger;
into my code to break. //TODO: Fix code mapping to breakpoints line up to code. //TODO: Enable code debugging in VS Code.
- Start App Server: Start the app using
npx nx start my-app
. - Open App on Phone: Start the app on your phone.
- Open React Dev Tools: Hit Shift+M in the terminal where you started the app to open more tools options. Select
Open React devtools
and then hit enter. Enter yes to option to open the browser page. - Reload the App: Open the app on your phone. The browser should then connect to your app and allow you to inspect the UI elements and take performance snapshots.
The mobile preview build gives you an instance of the application that will run without the metro server running. This instance will also accept updates via the preview channel.
- Create a preview build:
vscode task: build-preview
or
npx nx build-preview my-app
- Install Preview. Scan the QR Code from running the last command and install the app on your phone.
The mobile preview update allows you to push changes to your preview users without having to re-install the app on the phone.
- Update Main.tsx. Update the Update number:
<Text>
v0.0.1 Update 002
</Text>
- Deploy update.
npx nx update-preview my-app
- Test update. Open and close the app on your phone 2 or more times and you should see the update.
You need to create an EAS Robot token so that Amplify can trigger a build and deployment of your app. For more information see this: Robot users and access tokens
Add Robot: Create a new robot on the https://expo.dev/accounts/**your account**/settings/access-tokens
page.
- Name: Your app name+ "-delpoyment".
- Role: "Developer". Create Token: Click the create token under the new robot you just created.
- Token name: Your app name+"-deployment-token". SAVE TOKEN: Make sure to save your token somewhere safe where you can access it later.
npx nx amplify-add-hosting backend
Select the plugin module to execute … ❯ Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
Choose a type > Continuous deployment (Git-based deployments)
Select Repo: The last selection should launch a browser and take you to your app console. Select Hosting Environment and then select your repo.
Select Branch: Select your main or master branch. Do NOT select the option that designated your repo as a monorepo.
App Build and Test Settings: Our setup uses an amplify.yaml file in the root of the report to handle the deployment.
- Repo: Select your repo.
- Branch: Select master.
- App Name: Select the backend we deployed earlier.
- Environment: Select 'prod'.
- Service Role: Select the one you created earlier. //TODO: Update with when this was created.
- Advanced Settings: Expand this section:
- Environment Variables: Click add under the Environment Variables section and add the following variables:
- EXPO_TOKEN: Use the EAS robot token you created earlier.
- Environment Variables: Click add under the Environment Variables section and add the following variables:
Save and run the deployment.
- In the amplify console, go to the 'Backend environments' tab.
- On the 'prod' environment click 'Actions' and the choose 'Clone'.
- Enter 'dev' and click 'Clone'.
- After the deployment of the new 'dev' environment is complete, go to the 'Hosting environments' tab.
- Click 'Connect a branch' button.
- Branch: dev
- App name: Select the app we have been working with.
- Environment: Select the branch we just created: 'dev'.
- To Develop using the dev environment run the following command:
npx nx amplify-pull-dev backend
? Select the authentication method you want to use: AWS profile
? Please choose the profile you want to use: default
? Which app are you working on? <your app id>
✔ Choose the type of app that you're building: javascript
? What javascript framework are you using: react-native
? Source Directory Path: src
? Distribution Directory Path: /
? Build Command: npm run-script build
? Start Command: npm run-script start
? Do you plan on modifying this backend? Yes
Then switch to using that environment for development:
npx nx amplify-checkout-dev backend
Then switch to the dev branch in the repo and merge master into dev:
git checkout dev
git merge master
Save and run the deployment.
TBD...
TBD...
In the code below, replace my-app with the name of your application. To run the vscode tasks: press cntrl/cmd + shift + p then type "run task" then select the task named in the step.
The steps below assume that you have a physical Android device for development.
Explanation of tags used in the Terminal commands:
- [project-file] = ./path/from/project/root/to/file.ext
- [solution-file] = ./path/from/solution/root/to/file.ext
- [project] = Project Name. Ex: my-app, features, ui, etc.
V | Step | VS Code Task | Terminal |
---|---|---|---|
Install Dependencies | Install dependencies | npm install | |
Connect Mobile | Connect mobile device | npx nx connect-mobile | |
Run Mobile | Build and run mobile | npx nx run-android my-app | |
Run Mobile Preview | Build and run mobile (preview) | npx nx run-android-preview my-app |
V | Step | VS Code Task | Terminal |
---|---|---|---|
Connect Mobile | Connect mobile device | npx nx connect-mobile | |
Start Server | Start mobile server (metro) | npx nx start [project] | |
Start Web Test Studio | Start web test studio (Cypress) | npx nx start-web-test-studio [project] | |
Start Mobile Test Studio | Start mobile test studio (Maestro) | npx nx start-mobile-test-studio [project] | |
Create E2E Tests | Create e2e tests for project | npx nx create-e2e-tests [project] | |
Create Unit Test | Create unit test | npx nx create-unit-test [project] | |
Run Unit Test | Test: Run test in current file | N/A | |
Run Web Test | Use Cypress Studio | N/A | |
Run Mobile Test | Run mobile tests in current file | npx nx run test-mobile [solution-file] | |
Deploy Preview Update | Deploy preview update | npx nx run deploy-preview-update | |
Run Mobile Test (preview) | Run mobile tests in current file (preview) | npx nx run test-mobile-preview [project-file] | |
Run Proj Unit Tests | Run unit tests for project | npx nx test [project] | |
Run Proj Unit Tests w Cover | Run unit tests with coverage for project | npx nx test-coverage [project] | |
Run Proj Web Tests | Run web tests for project | npx nx test-web [project] | |
Run Proj Mobile Tests | Run mobile tests for project | npx nx test-mobile [project] | |
Run All Unit Tests | Run all unit tests | npx nx run-many -t test | |
Run All Unit Tests w Cover | Run all unit tests with coverage | npx nx run-many -t test-coverage | |
Run All Web Tests | Run all web tests | npx nx run-many test-web | |
Run All Mobile Tests | Run all mobile tests | npx nx run-many test-mobile | |
Run All Mobile Tests Release | Run all mobile tests (preview) | npx nx run-many test-mobile-preview |
V | Step | VS Code Task | Terminal |
---|---|---|---|
View Amplify Project | View Amplify project | npx nx run view-amplify-project | |
View Expo.dev Project | View Expo.dev project | npx nx run view-expodev-project | |
View Github Project | View Github project | npx nx run view-github-project | |
View Discord | View Discord | npx nx run view-discord |
V | Step | VS Code Task | Terminal |
---|---|---|---|
Install Dependencies | Install dependencies | npm install | |
Install New Dependencies | Install new dependencies | npx nx install [project] dependency1,dep2 | |
Check Dependencies | Check dependencies | npx nx deps-check | |
Sort Dependencies | Sort dependencies | npx nx deps-sort | |
Migrate Nx | Migrate NX dependencies | npx nx migrate latest --run-migrations |
V | Step | VS Code Task | NX Project & Task |
---|---|---|---|
Build Dev App Android Cloud | build-dev-myapp-android-cloud | ||
Build Dev App Cloud | build-dev-myapp-android-cloud | ||
Build Prev App Android Local | build-preview-myapp-android-local | ||
Build Production App |
-
Start Expo: This starts an instance of the metro bundler that listens on your hosts ip and port 19001. This enables your physical device to connect using the debug build. It also serves up the web app.
-
Connect Android Device:: Connect to your Android device over wifi. I have found that the most efficient testing is performed on a baseline Android device. Either get a used Android phone or buy a cheap one off Amazon. I am using this one: UMIDIGI G3 Max. If you have not already built and deployed a dev version of your app see above.
-
Open Cypress: Use this interface to run your web E2E tests.
-
Open Maestro: Use this interface to write steps for E2E mobile testing.
-
Create E2E Tests: Creates both a test.spec.ts file for Cypress plus a test.yaml file for Maestro.
-
Write End-to-End (E2E) Web Test: Write a cypress test that performs the new feature you want to build. This test should be located in the 'my-app-e2e/cypress/e2e' folder.
-
Verify E2E Web Test Fails: Start the app and the Cypress test runner: Navigate to the test spec you created in the Cypress interface from the "Open Cypress E2E Tester" step and run the spec you created. Or if you do not want to use the Cypress interface you can run the following command in a new terminal:
vscode task: test-e2e-web-current-spec
(make sure to view the spec file you want to run in the editor before running the task.)
or
npx nx test-e2e-web my-app-e2e --spec /path/to/your/test.cy.ts
- Write E2E Mobile Test: Write a detox test that performs the new feature you want to build. This test should be located in the 'my-app-e2e/detox' folder. Use an AI to convert the test from cypress to detox.
- Verify E2E Mobile Test Fails: Run the new E2E test you wrote for mobile. In a new terminal run the following command. This assumes you have already built your detox android apk in the setup. It will launch an instance of android in the cloud, deploy your app to the device, then run your test.
vscode task: test-e2e-mobile-current-spec
(make sure to view the spec file you want to run in the editor before running the task.)
or
npx nx test-e2e-mobile my-app-e2e /path/to/your/test.spec.ts
- Write Unit Test: Write a unit test that requires the new code you need to write. Create a .test.ts or .test.tsx file that has the name of the function you need to write. Stub the actual code file so that your test compiles.
- Verify Unit Test Fails: Run your unit test and verify it fails:
Cntrl/Cmd+Shift+P
Test: Run Test at Cursor
- Write Code and Rerun: Write your code and rerun the unit tests until they pass.
Cntrl/Cmd+Shift+P
Test: Run Tests in Current File
- Verify in Web App: Manually verify your new feature in the web browser that you started in the first step.
- Verify in Mobile App: Manually verify your new feature in the dev app on your mobile device connected to the metro service you started in the "Start the App for Web and Mobile" step (first step).
- Verify Unit Test Passes: If you need to debug a test:
Cntrl/Cmd+Shift+P
Test: Debug Test at Cursor
-
Verify E2E Web Test Passes: Rerun your test that you created through the Cypress UI or via the CLI using the command listed in Verify E2E Web Test Fails step.
-
Verify E2E Mobile Test Passes: Rerun your test that you created via the CLI using the command listed in Verify E2E Mobile Test Fails step.
-
Debug Web App: Set breakpoints in the browser devtools and execute your feature in the app. Once the app is started. Open the dev tools. In the sources tab you can find files using Cmd/Cntrl+Shift+P and typing the file name. You can also set breakpoints. Install the redux tools as well as the React Native tools and you can inspect redux, the UI elements, and the UI performance.
-
Debug Mobile App: Set breakpoints in VSCode and execute your feature in the mobile app. //TODO: Add steps and commands.
-
Run All Unit Tests: Run all unit tests to verify all are still passing:
vscode task: test
or
npx nx run-many -t test
Alternatively, you can run all unit tests in a single project (ex. my-app) using:
vscode task: test-my-app
(Replace my-app with the name of the project: backend, features, shared, or state)
or
npx nx test my-app
- Verify 100% Unit Test Code Coverage: After you completed building your feature and have all tests passing, verify you have 100% code coverage.
vscode task: test-coverage
or
npx nx run-many -t test-coverage
Alternatively, you can check code coverage for a single project (ex. my-app) using:
vscode task: test-coverage-my-app
(Replace my-app with the name of the project: backend, features, shared, or state)
or
npx nx test-coverage my-app
- Run All E2E Web Tests: Run all the cypress tests to verify the web app is working.
vscode task: test-e2e-web
or
npx nx test-e2e-web my-app-e2e
- Run All e2e Mobile Tests: Run all the detox tests to verify the mobile app is working.
vscode task: test-e2e-mobile
or
npx nx test-e2e-mobile my-app-e2e
- Check If Package Versions Are Outdated: Check if your install dependencies are outdated.
vscode task: check-dependencies
or
npx npm-check-updates
- Upgrading Individual NPM Depencies: Execute npm install from the root of the solution.
npm install expo@latest
- Upgradeing All NPM Dependencies: Upgrade all dependencies to their latest version.
npx npm-check-updates -u
- Install Expo Modules: Use the following command to install expo modules in your app project:
npx nx install my-app package1,package2,package3
- Upgrade/Correct Expo Modules: Use the following command to install expo modules in your app project:
npx nx install my-app --fix
- Sort Package Dependencies: Use the following command to sort the dependencies in a package.json
cd to-directory-with-package-json
npx sort-package-json
- Build Android Mobile App Locally: You can build the android version of the app and run it in genymotion to check that the mobile app compiles and can run on a device.
npx nx build-local-dev-android my-app
- Run Android Mobile App in Genymotion: After you have built a new version of the app, you can launch an emulator in genymotion and deploy the build using the following commands:
- Build Android and IOS Using EAS: If you install modules that require updating the development build that is deployed to devices:
npx nx build-dev my-app
After you run the build, you will need to scan the QR code on all devices to update your development build. 8. Install EAS Build on Device:
If you are experiencing slow initial connections from the host or external device to your metro bundler just change the nameserver lines in /etc/resolv.conf to:
nameserver 8.8.8.8
nameserver 8.8.4.4
https://stackoverflow.com/questions/41923522/why-is-network-internet-in-my-docker-container-so-slow