- Application Philosophy
- API Details
- Contributing to Expensify
- Expensify Code of Conduct
- Contributor License Agreement
- React StrictMode
- Left Hand Navigation(LHN)
- HybridApp - additional info & troubleshooting
These instructions should get you set up ready to work on New Expensify 🙌
- Install
nvm
thennode
&npm
:brew install nvm && nvm install
- Install
watchman
:brew install watchman
- Install dependencies:
npm install
- Install
mkcert
:brew install mkcert
followed bynpm run setup-https
. If you are not using macOS, follow the instructions here. - Create a host entry in your local hosts file,
/etc/hosts
for dev.new.expensify.com pointing to localhost:
127.0.0.1 dev.new.expensify.com
You can use any IDE or code editing tool for developing on any platform. Use your favorite!
In order to have more consistent builds, we use a strict node
and npm
version as defined in the package.json
engines
field and .nvmrc
file. npm install
will fail if you do not use the version defined, so it is recommended to install node
via nvm
for easy node version management. Automatic node
version switching can be installed for zsh
or bash
using nvm
.
The webpack development server now uses https. If you're using a mac, you can simply run npm run setup-https
.
If you're using another operating system, you will need to ensure mkcert
is installed, and then follow the instructions in the repository to generate certificates valid for dev.new.expensify.com
and localhost
. The certificate should be named certificate.pem
and the key should be named key.pem
. They should be placed in config/webpack
.
- To run the development web app:
npm run web
- Changes applied to Javascript will be applied automatically via WebPack as configured in
webpack.dev.ts
For an M1 Mac, read this SO for installing cocoapods.
- If you haven't already, install Xcode tools and make sure to install the optional "iOS Platform" package as well. This installation may take awhile.
- After installation, check in System Settings that there's no update for Xcode. Otherwise, you may encounter issues later that don't explain that you solve them by updating Xcode.
- Install project gems, including cocoapods, using bundler to ensure everyone uses the same versions. In the project root, run:
bundle install
- If you get the error
Could not find 'bundler'
, install the bundler gem first:gem install bundler
and try again. - If you are using MacOS and get the error
Gem::FilePermissionError
when trying to install the bundler gem, you're likely using system Ruby, which requires administrator permission to modify. To get around this, install another version of Ruby with a version manager like rbenv.
- If you get the error
- Before installing iOS dependencies, you need to obtain a token from Mapbox to download their SDKs. Please run
npm run configure-mapbox
and follow the instructions.- For help with MapBox token, you can see this Slack thread
- To install the iOS dependencies, run:
npm install && npm run pod-install
- If you are an Expensify employee and want to point the emulator to your local VM, follow this
- To run a on a Development Simulator:
npm run ios
- Changes applied to Javascript will be applied automatically, any changes to native code will require a recompile
If you want to run the app on an actual physical iOS device, please follow the instructions here.
- Before installing Android dependencies, you need to obtain a token from Mapbox to download their SDKs. Please run
npm run configure-mapbox
and follow the instructions. If you already did this step for iOS, there is no need to repeat this step. - Go through the official React-Native instructions on this page to start running the app on android.
- If you are an Expensify employee and want to point the emulator to your local VM, follow this
- To run a on a Development Emulator:
npm run android
- Changes applied to Javascript will be applied automatically, any changes to native code will require a recompile
By default, react-native
is built from source when building the Android app. However, you can enable prebuilt artifacts to speed up the build process:
- Open
android/gradle.properties
(for Standalone NewDot) orMobile-Expensify/Android/gradle.properties
(for HybridApp) - Set
patchedArtifacts.forceBuildFromSource=false
To use prebuilt artifacts, you need to have GitHub CLI installed and configured:
-
Install GitHub CLI by following the instructions from cli.github.com
-
Create a GitHub Personal Access Token:
- Go to GitHub Settings > Developer Settings > Personal Access Tokens
- Click "Generate new token (classic)"
- Select the following scopes:
repo
read:org
gist
read:packages
- Copy the generated token
-
Login to GitHub CLI:
echo "YOUR_TOKEN" | gh auth login --with-token
-
Verify the login was successful:
gh auth status
You should see a message confirming you are authenticated with your GitHub account.
After completing these steps, you should be able to build Android apps with prebuilt react-native
artifacts.
- To run the Development app, run:
npm run desktop
, this will start a new Electron process running on your MacOS desktop in thedist/Mac
folder.
To receive mobile push notifications in the development build while hitting the Staging or Production API, you need to use the production airship config.
Add inProduction = true
to Mobile-Expensify/Android/assets/airshipconfig.properties
Copy the production config to the development config.
Set inProduction
to true
in Mobile-Expensify/iOS/AirshipConfig/Debug/AirshipConfig.plist
Replace the development key and secret with the production values.
- If you are having issues with Getting Started, please reference React Native's Documentation
- If you are running into CORS errors like (in the browser dev console)
You probably have a misconfigured
Access to fetch at 'https://www.expensify.com/api/BeginSignIn' from origin 'http://localhost:8080' has been blocked by CORS policy
.env
file - remove it (rm .env
) and try again
Note: Expensify engineers that will be testing with the API in your local dev environment please refer to these additional instructions.
Creating an .env
file is not necessary. We advise external contributors against it. It can lead to errors when
variables referenced here get updated since your local .env
file is ignored.
NEW_EXPENSIFY_URL
- The root URL used for the websiteSECURE_EXPENSIFY_URL
- The URL used to hit the Expensify secure APIEXPENSIFY_URL
- The URL used to hit the Expensify APIEXPENSIFY_PARTNER_NAME
- Constant used for the app when authenticating.EXPENSIFY_PARTNER_PASSWORD
- Another constant used for the app when authenticating. (This is OK to be public)PUSHER_APP_KEY
- Key used to authenticate with Pusher.comSECURE_NGROK_URL
- Secure URL used forngrok
when testingNGROK_URL
- URL used forngrok
when testingUSE_NGROK
- Flag to turnngrok
testing on or offUSE_WDYR
- Flag to turnWhy Did You Render
testing on or offUSE_WEB_PROXY
⚠️ - Used in web/desktop development, it starts a server along the local development server to proxy requests to the backend. External contributors should set this totrue
otherwise they'll have CORS errors. If you don't want to start the proxy server set this explicitly tofalse
CAPTURE_METRICS
(optional) - Set this totrue
to capture performance metrics and see them in Flipper see PERFORMANCE.md for more informationONYX_METRICS
(optional) - Set this totrue
to capture even more performance metrics and see them in Flipper see React-Native-Onyx#benchmarks for more informationE2E_TESTING
(optional) - This needs to be set totrue
when running the e2e tests for performance regression testing. This happens usually automatically, read this for more information
If your changes to .env aren't having an effect, try
rm -rf .rock
, then re-runnpm run ios
ornpm run android
The development server is reached through the HTTPS protocol, and any client that access the development server needs a certificate.
You create this certificate by following the instructions in Configuring HTTPS
of this readme. When accessing the website served from the development server on browsers in iOS simulator or Android emulator, these virtual devices need to have the same certificate installed. Follow the steps below to install them.
- Open any emulator using Android Studio
- Use
adb push "$(mkcert -CAROOT)/rootCA.pem" /storage/emulated/0/Download/
to push certificate to install in Download folder. - Install the certificate as CA certificate from the settings. On the Android emulator, this option can be found in Settings > Security > Encryption & Credentials > Install a certificate > CA certificate.
- Close the emulator.
Note: If you want to run app on https://127.0.0.1:8082
, then just install the certificate and use adb reverse tcp:8082 tcp:8082
on every startup.
- Run
npm run setupNewDotWebForEmulators android
- Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically)
- Let the script execute till the message
🎉 Done!
.
Note: If you want to run app on https://dev.new.expensify.com:8082
, then just do the Android flow and use npm run startAndroidEmulator
to start the Android Emulator every time (It will configure the emulator).
Possible Scenario:
The flow may fail to root with error adbd cannot run as root in production builds
. In this case, please refer to https://stackoverflow.com/a/45668555. Or use https://127.0.0.1:8082
for less hassle.
- Run
npm run setupNewDotWebForEmulators ios
- Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically)
- Let the script execute till the message
🎉 Done!
.
- Run
npm run setupNewDotWebForEmulators all
ornpm run setupNewDotWebForEmulators
- Check if the iOS flow runs first and then Android flow runs.
- Let the script execute till the message
🎉 Done!
.
Unit tests are valuable when you want to test one component. They should be short, fast, and ideally only test one thing. Often times in order to write a unit test, you may need to mock data, a component, or library. We use the library Jest to help run our Unit tests.
- To run the Jest unit tests:
npm run test
- UI tests guidelines can be found here
We use Reassure for monitoring performance regression. More detailed information can be found here:
- If running on the iOS simulator pressing
⌘D
will open the debugging menu. - This will allow you to attach a debugger in your IDE, React Developer Tools, or your browser.
- For more information on how to attach a debugger, see React Native Debugging Documentation
Alternatively, you can also set up debugger using Flipper. After installation, press ⌘D
and select "Open Debugger". This will open Flipper window. To view data stored by Onyx, go to Plugin Manager and install async-storage
plugin.
Our React Native Android app now uses the Hermes
JS engine which requires your browser for remote debugging. These instructions are specific to Chrome since that's what the Hermes documentation provided.
- Navigate to
chrome://inspect
- Use the
Configure...
button to add the Metro server address (typicallylocalhost:8081
, check yourMetro
output) - You should now see a "Hermes React Native" target with an "inspect" link which can be used to bring up a debugger. If you don't see the "inspect" link, make sure the Metro server is running
- You can now use the Chrome debug tools. See React Native Debugging Hermes
To make it easier to test things in web, we expose the Onyx object to the window, so you can easily do Onyx.set('bla', 1)
.
Often, performance issue debugging occurs in debug builds, which can introduce errors from elements such as JS Garbage Collection, Hermes debug markers, or LLDB pauses.
react-native-release-profiler
facilitates profiling within release builds for accurate local problem-solving and broad performance analysis in production to spot regressions or collect extensive device data. Therefore, we will utilize the production build version
To accurately profile your application, generating source maps for Android and iOS is crucial. Here's how to enable them:
-
Enable source maps on Android Ensure the following is set in your app's
android/app/build.gradle
file.project.ext.react = [ enableHermes: true, hermesFlagsRelease: ["-O", "-output-source-map"], // <-- here, plus whichever flag was required to set this away from default ]
-
Enable source maps on IOS Within Xcode head to the build phase -
Bundle React Native code and images
.export SOURCEMAP_FILE="$(pwd)/../main.jsbundle.map" // <-- here; export NODE_BINARY=node ../node_modules/react-native/scripts/react-native-xcode.sh
-
Install the necessary packages and CocoaPods dependencies:
npm i && npm run pod-install
-
Depending on the platform you are targeting, run your Android/iOS app in production mode.
-
Upon completion, the generated source map can be found at: Android:
android/app/build/generated/sourcemaps/react/productionRelease/index.android.bundle.map
IOS:main.jsbundle.map
web:dist/merged-source-map.js.map
- Ensure you have generated the source map as outlined above.
- Launch the app in production mode.
- Navigate to the feature you wish to profile.
- Initiate the profiling session by tapping with four fingers (on mobile) or
cmd+d
(on web) to open the menu and selectingUse Profiling
. - Close the menu and interact with the app.
- After completing your interactions, tap with four fingers or
cmd+d
again and select to stop profiling. - You will be presented with a
Share
option to export the trace, which includes a trace file (Profile<app version>.cpuprofile
) and build info (AppInfo<app version>.json
).
Build info:
{
appVersion: "1.0.0",
environment: "production",
platform: "IOS",
totalMemory: "3GB",
usedMemory: "300MB"
}
- You have two files:
AppInfo<app version>.json
andProfile<app version>.cpuprofile
- Place the
Profile<app version>.cpuprofile
file at the root of your project. - If you have already generated a source map from the steps above for this branch, you can skip to the next step. Otherwise, obtain the app version from
AppInfo<app version>.json
switch to that branch and generate the source map as described.
IMPORTANT:
You should generate the source map from the same branch as the trace was recorded.
- Use the following commands to symbolicate the trace for Android and iOS, respectively:
Android:
npm run symbolicate-release:android
IOS:npm run symbolicate-release:ios
web:npm run symbolicate-release:web
- A new file named
Profile_trace_for_<app version>-converted.json
will appear in your project's root folder. - Open this file in your tool of choice:
- SpeedScope (https://www.speedscope.app)
- Perfetto UI (https://ui.perfetto.dev/)
- Google Chrome's Tracing UI (chrome://tracing)