/eas-monorepo-example

An example monorepo for EAS or just Expo usage

Primary LanguageJavaMIT LicenseMIT

EAS monorepo example

Enterprise-ready Expo Application Service monorepo with code sharing

managed preview latest standalone build license

Structure   —   Workflows   —   How to use it   —   Caveats   —   Common Errors


📁 Structure

  • apps - Expo apps that only use packages and aren't aware of other apps.
  • packages - Node packages that may use external and/or local packages.

Apps

  • apps/ejected - Expo bare app using babel, eslint, and ui packages.
  • apps/managed - Expo managed app using babel, eslint, and ui packages.
  • apps/with-sentry - Expo managed app with expo-sentry integrated.

Packages

  • packages/babel - Preconfigured Babel configuration for Expo.
  • packages/eslint - Preconfigured ESLint coniguration for Expo.
  • packages/ui - Shared React Native UI components for the apps, using the eslint package.

👷 Workflows

  • preview - Publishes managed apps to a PR-specific release channel and adds a QR code to that PR.
  • standalone - Starts the EAS builds for user-provided OS and build profiles.
  • test - Ensures that the apps and packages are passing lint and build checks.

🚀 How to use it

To set this repository up, you need an Expo account with access to EAS. After that, you need to run these commands.

  • $ yarn - This installs all required Node libraries using Yarn Workspaces
  • $ yarn build - To precompile the packages to publish them to NPM and/or use them in your apps.
  • Change the expo.owner and expo.android.package / expo.ios.bundleIdentifier properties in app.json for all apps.

Starting apps

After the initial setup, you can start the apps from their app directories.

  • $ cd apps/ejected - From here, you can run your bare project with yarn start and yarn android|ios.
  • $ cd apps/managed - From here, you can start Expo with yarn start.

You can also run these commands with yarn workspaces from the monorepo root with yarn ejected|managed <script>. But sometimes, the context is incorrectly reverted to the root of the monorepo instead of the app directory.

⚠️ Caveats

Precompile packages

EAS only sends the files which are committed to the repository. That means the packages/*/build folders need to be generated before building our apps. To tell EAS how to compile our packages, we can use the postinstall hook.

Running EAS from apps directories

As of writing, the eas build command needs to be executed from the package folder itself. EAS will still create a tarball with all files from your monorepo, but runs the build commands from this local folder. You can see this happening in the standalone workflow.

Using local credentials in CI

If you want to maintain the keystore or certificates yourself, you have to configure EAS with local credentials. When your CI provider doesn't allow you to add "secret files", you can encode these files to base64 strings and decode whenever you need it.

It's highly recommended to keep keystores and certificates out of your repository to avoid security issues.

❌ Common Errors

Scripts not found

In React Native, your Node modules often contain native code or scripts used during native compilation. Sometimes the default native configuration isn't aware of the monorepo structure and tries to look for packages in the app's node_modules directory.

# Android example
> Could not read script '.../packages/app/node_modules/expo-constants/scripts/get-app-config-android.gradle' as it does not exist.

# iOS example
> fatal error: module map file '.../Release-iphoneos/YogaKit/YogaKit.modulemap' not found

Luckily, we can solve that in different ways:

  • Bare workflow - You can update the native code to point to the root of the monorepo. You can do that by adding ../../ to the package-specific scripts.
  • Managed workflow - You need to symlink these packages into the app's node_modules directory. expo-yarn-workspaces can help with that.

with :heart:  byCedric