Package Exports
- @expo/cli
- @expo/cli/build/bin/cli
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@expo/cli) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@expo/cli
The @expo/cli package is a CLI binary that should be used via expo like npx expo start.
npx expoDesign
This CLI has the following purposes:
- Be a minimal interface for starting a local development server that emulates a production EAS Updates server. The development server is the proxy between a native runtime (Expo Go, Dev Client) and a JS Bundler (Metro, Webpack).- To accomplish secure manifest signing (think https/TSL/SSL for web (required for sandboxing AsyncStorage, Permissions, etc.)) we need an authenticated Expo user account. This is the only reason we include the authentication commands login,logout,whoami,register. Standard web CLIs don't have authentication commands because they either don't setup https or they use emulation via packages likedevcert.
 
- To accomplish secure manifest signing (think https/TSL/SSL for web (required for sandboxing AsyncStorage, Permissions, etc.)) we need an authenticated Expo user account. This is the only reason we include the authentication commands 
- Orchestrating various native tools like Xcode, Simulator.app, Android Studio, ADB, etc. to make native builds as painless as possible. run:ios,run:androidcommands.
- Implementing a versioned prebuildcommand that can reliably work with a project for long periods of time. Prebuild is like a bundler for native code, it generates theios,androidfolders based on the project Expo config (app.json).- npx expo configis auxiliary to- npx expo prebuildand used for debugging/introspection.
 
- Installing versioned libraries with npx expo installthis is a minimal utility born out of pure necessity since versioning in React Native is hard to get right.
Contributing
To develop the CLI run (defaults to watch mode):
yarn buildWe highly recommend setting up an alias for the Expo CLI so you can try it in projects all around your computer. Open your .zshrc or other config file and add:
alias nexpo="/path/to/expo/packages/@expo/cli/build/bin/cli"Then use it with nexpo like nexpo config. You can also setup a debug version:
alias expo-inspect="node --inspect /path/to/expo/packages/@expo/cli/build/bin/cli"Then you can run it, and visit chrome://inspect/#devices in Chrome, and press "Open dedicated DevTools for Node" to get a debugger attached to your process. When debugging the CLI, you'll want to disable workers whenever possible, this will make all code run on the same thread, this is mostly applicable to the start command, i.e. expo-inspect start --max-workers 0.
Format
- Be sure to update the CHANGELOG.mdwith changes for every PR. You only need to add the message, our GitHub bot will automatically suggest adding your name and PR number to the diff.
- End asyncfunctions withAsynclikerunAsync. This is just how we format functions at Expo.
- When throwing errors, always opt for CommandErrorinstead ofError-- this helps with debugging and making the experience feel more coherent.
- Utilize the unified Logmodule instead ofconsole.log.
- When logging with variables, utilize the following format Something happened (foo: bar, baz: foz).- Avoid other formats like Something happened: bar, fozorSomething happened: foo=bar, baz=foz.
 
- Avoid other formats like 
- Main UI components like command names (expo start), arguments (--port), and--helpmessages should be modified internally, by the Expo team to ensure the developer experience is unified across Expo tooling. External contributions modifying these core aspects may be rejected.
- Use the profileutility method with theEXPO_PROFILE=1environment variable to measure execution time.
- Avoid globals and singletons as these make testing harder and less predictable. The only global we have (at the time of writing this) is the isOfflineboolean.
Environment
- Always be cautious of the transitive size of dependencies. packagephobia is a great resource for determining if a package is lean. Try to minimize adding dependencies to the CLI.
- We build the CLI using taskr+swc, this is partially inspired by Next.js' local CLI.
- The build pipeline will inline the CLI version as an environment variable that is accessible anywhere in the CLI codebase. You can access it via process.env.__EXPO_VERSIONinstead of reading the localpackage.jsonat runtime.
- Unlike the legacy global Expo CLI, this CLI is shipped with expomeaning the SDK Version is always present.- Reduce SDK specific tasks since only one SDK should be accounted for in a single version of @expo/cli.
- The @expo/configmethodgetConfigdoes not need theskipSDKVersionRequirementin any case sinceexposhould always be installed. Ex:getConfig('...', { skipSDKVersionRequirement: true });shouldn't be used.
 
- Reduce SDK specific tasks since only one SDK should be accounted for in a single version of 
- Also unlike the global Expo CLI we can assume that node modules are always installed since this CLI should be used via a project's local node_modulesfolder.- This means we can't perform operations that upgrade the expopackage as these may kill the running process. Features that need this pattern (likeexpo upgrade) should live in standalone global tools.
 
- This means we can't perform operations that upgrade the 
Testing
There are two testing scripts:
- yarn test: Controlled unit and integration tests.
- yarn test:e2e: End to end testing for CLI commands. This requires the files be built with- yarn build
- You can target a specific set of tests with the --watchflag. Example:yarn test --watch config.
- We use back ticks for itblocks. Exampleit(.works)
- If a pull request is fully self contained to the packages/@expo/cli/folder (i.e. noyarn.lockmodifications, etc.) then most native CI tests will be skipped, making CI pass faster in PRs.
Unit Testing Guidelines
- Use nockfor network requests.
- No top level describeblocks that wrap all the tests in a file.
- When testing a function, pass the function to the describe instead of a stringified function name:- describe(foobar, () => {})instead of- describe('foobar', () => {})
 
- Use virtual fsviamemfswhenever possible.
- We have a lot of global module mocks already in place, consider them when writing tests.
- GitHub Copilot can make writing tests a little less tedious.
E2E Testing Guidelines
- E2E tests should be resilient and reliable, be sure to give them plenty of time for network requests.
- When testing locally you should attempt to reuse node modules for faster results. In the npx expo prebuildandnpx expo startcommands for instance, we utilize a helper method that will default to reusing a project + node_modules when run locally. This can be toggled off to bootstrap a fresh project every time.
- When bootstrapping test projects, utilize the temporary folder os.tmpdir()as this folder is automatically cleaned up when the computer restarts.
Coming from Expo CLI
TL;DR:
expo-cliwas 'make it work', whereas@expo/cliis 'make it right, make it fast'.
The legacy global expo-cli package was deprecated in favor of this versioned @expo/cli package for the following reasons:
- expo-cliwas too big and took way too long to install. This made CI frustrating to setup since you needed to also target global node modules for caching.
- expo-cliworked for almost all versions of the- expopackage, meaning it was getting more complex with every release.
- expo-clicombined service commands (like the legacy- build,- submit,- publish) with project-level commands like- expo start. We've since divided services into- eas-cliand project commands into- npx expo(- @expo/cli). This structure is more optimal/faster for developers since they can install/update commands when they need them.
- This CLI utilizes more Node.js standard features like $EDITORinstead of the custom$EXPO_EDITORenvironment variable. Also transitioning away from$EXPO_DEBUGand more towards$DEBUG=expo:*. These types of changes make Expo CLI play nicer with existing tooling.
- The DevTools UI has been deprecated to reduce the net install size, minimize complexity, and make room for future debugging UIs (Hermes/v8 Chrome debugger).
- The expo start:webandexpo webcommands have been rolled intonpx expo startas we now lazily load platforms until the device requests them.
- Other missing or beta features from expo-climay still be getting migrated over to this new CLI. For a more comprehensive breakdown see the start command PR.