Skip to content

Commit

Permalink
feat(cli): auto enable --dev-client in npx expo start (#22926)
Browse files Browse the repository at this point in the history
# Why

- related #22924
#22925
#22890
- Use a basic heuristic to auto enable `--dev-client` when
`expo-dev-client` is in the project `package.json`. Users can swap to
Expo Go with `s` or pass `--go` to ensure Expo Go is the default target.

# Test Plan

- Added basic option tests.
- Updated the docs.

---------

Co-authored-by: Expo Bot <34669131+expo-bot@users.noreply.github.com>
  • Loading branch information
EvanBacon and expo-bot committed Jun 21, 2023
1 parent e32ccf9 commit 8df9096
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 5 deletions.
11 changes: 9 additions & 2 deletions docs/pages/more/expo-cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,26 @@ The UI that shows up in the process is referred to as the **Terminal UI**. It co

| Keyboard shortcut | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <kbd>A</kbd> | Open the project in Expo Go on Android. |
| <kbd>A</kbd> | Open the project on a connected Android device. |
| <kbd>Shift</kbd> + <kbd>A</kbd> | Select an Android device or emulator to open. |
| <kbd>I</kbd> | Open the project in Expo Go on iOS. |
| <kbd>I</kbd> | Open the project in an iOS simulator. |
| <kbd>Shift</kbd> + <kbd>I</kbd> | Select an iOS Simulator to open. |
| <kbd>W</kbd> | Open the project in a web browser. This may require webpack to be installed in your project. |
| <kbd>R</kbd> | Reload the app on any connected device. |
| <kbd>S</kbd> | Switch the launch target between Expo Go and development builds. |
| <kbd>M</kbd> | Open the dev menu on any connected native device (web not supported). |
| <kbd>Shift</kbd> + <kbd>M</kbd> | Choose more commands to trigger on connected devices.<br/>This includes toggling the performance monitor, opening the element inspector, reloading the device, and opening the dev menu. |
| <kbd>J</kbd> | Open Chrome Dev Tools for any connected device that is using Hermes as the JavaScript engine. [Learn more](/guides/using-hermes#javascript-inspector-for-hermes). |
| <kbd>O</kbd> | Open project code in your editor. This can be configured with the `EXPO_EDITOR` and `EDITOR` [environment variables](#environment-variables). |
| <kbd>E</kbd> | Show the development server URL as a QR code in the terminal. |
| <kbd>?</kbd> | Show all Terminal UI commands. |

### Launch target

The `npx expo start` command will automatically launch the app in Expo Go unless `expo-dev-client` in installed in the project, in which case it will open in the custom app. You can force the launch target by passing the `--dev-client` and `--go` flags. For example, running `npx expo start --go` will always launch the app in Expo Go, and `npx expo start --dev-client` will always attempt to launch the app in a development build.

You can switch the launch target during runtime by pressing <kbd>S</kbd> in the **Terminal UI**. The run commands will also default to using `--dev-client` after compiling the development build.

### Server URL

By default, the project is served over a LAN connection. You can change this behavior to localhost-only by using the flag `npx expo start --localhost`.
Expand Down
1 change: 1 addition & 0 deletions packages/@expo/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Add `-d` as an alias to `--dev-client`. ([#22925](https://github.com/expo/expo/pull/22925) by [@EvanBacon](https://github.com/EvanBacon))
- Allow client-side device ids to reuse debugger sessions when restarting app. ([#22742](https://github.com/expo/expo/pull/22742) by [@byCedric](https://github.com/byCedric))
- Enable inspector proxy with network support by default. ([#22936](https://github.com/expo/expo/pull/22936) by [@byCedric](https://github.com/byCedric))
- Auto enable `--dev-client` in `expo start` if `--go` is not passed and `expo-dev-client` is in the `package.json`. ([#22926](https://github.com/expo/expo/pull/22926) by [@EvanBacon](https://github.com/EvanBacon))
- Add `EXPO_OFFLINE` environment variable to disable network requests across the entire CLI. ([#22961](https://github.com/expo/expo/pull/22961) by [@EvanBacon](https://github.com/EvanBacon))

### 🐛 Bug fixes
Expand Down
14 changes: 14 additions & 0 deletions packages/@expo/cli/src/start/__tests__/resolveOptions-test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { asMock } from '../../__tests__/asMock';
import { hasDirectDevClientDependency } from '../../utils/analytics/getDevClientProperties';
import { resolvePortAsync } from '../../utils/port';
import { resolveHostType, resolveOptionsAsync, resolvePortsAsync } from '../resolveOptions';

Expand All @@ -12,6 +13,11 @@ jest.mock('../../utils/scheme', () => {
getOptionalDevClientSchemeAsync: jest.fn(async () => []),
};
});
jest.mock('../../utils/analytics/getDevClientProperties', () => {
return {
hasDirectDevClientDependency: jest.fn(() => false),
};
});

describe(resolveOptionsAsync, () => {
it(`prevents using --dev-client and --go together`, async () => {
Expand Down Expand Up @@ -39,6 +45,14 @@ describe(resolveOptionsAsync, () => {
it(`sets devClient to true`, async () => {
expect((await resolveOptionsAsync('/noop', { '--dev-client': true })).devClient).toBe(true);
});
it(`infers that devClient should be true`, async () => {
jest.mocked(hasDirectDevClientDependency).mockReturnValueOnce(true);
expect((await resolveOptionsAsync('/noop', {})).devClient).toBe(true);
});
it(`--go forces devClient to false`, async () => {
jest.mocked(hasDirectDevClientDependency).mockReturnValueOnce(true);
expect((await resolveOptionsAsync('/noop', { '--go': true })).devClient).toBe(false);
});
});

describe(resolveHostType, () => {
Expand Down
16 changes: 14 additions & 2 deletions packages/@expo/cli/src/start/resolveOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assert from 'assert';

import { hasDirectDevClientDependency } from '../utils/analytics/getDevClientProperties';
import { AbortCommandError, CommandError } from '../utils/errors';
import { resolvePortAsync } from '../utils/port';

Expand Down Expand Up @@ -38,8 +39,19 @@ export async function resolveOptionsAsync(projectRoot: string, args: any): Promi
tunnel: args['--tunnel'],
});

// TODO: Add a third option which is auto detecting if the user is using `expo-dev-client` or `expo-dev-launcher`.
const isDevClient = !!args['--dev-client'] || (args['--go'] == null ? false : !args['--go']);
// User can force the default target by passing either `--dev-client` or `--go`. They can also
// swap between them during development by pressing `s`.
const isUserDefinedDevClient =
!!args['--dev-client'] || (args['--go'] == null ? false : !args['--go']);

// If the user didn't specify `--dev-client` or `--go` we check if they have the dev client package
// in their package.json.
const isAutoDevClient =
args['--dev-client'] == null &&
args['--go'] == null &&
hasDirectDevClientDependency(projectRoot);

const isDevClient = isAutoDevClient || isUserDefinedDevClient;

const scheme = await resolveSchemeAsync(projectRoot, {
scheme: args['--scheme'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ExpoConfig, getAccountUsername, getDefaultTarget } from '@expo/config';
import { ExpoConfig, getAccountUsername, getDefaultTarget, getPackageJson } from '@expo/config';
import JsonFile, { JSONValue } from '@expo/json-file';
import resolveFrom from 'resolve-from';

Expand All @@ -8,6 +8,12 @@ const getAccountName = memoize((exp: Pick<ExpoConfig, 'owner'>) => {
return getAccountUsername(exp);
});

/** @returns true if the expo-dev-client package is found in the project `package.json` file. */
export function hasDirectDevClientDependency(projectRoot: string): boolean {
const pkg = getPackageJson(projectRoot);
return !!pkg.dependencies?.['expo-dev-client'] || !!pkg.devDependencies?.['expo-dev-client'];
}

const getDevClientVersion = memoize((projectRoot: string): JSONValue | undefined => {
try {
const devClientPackage = resolveFrom.silent(projectRoot, 'expo-dev-client/package.json');
Expand Down

0 comments on commit 8df9096

Please sign in to comment.