Skip to content

Commit

Permalink
feat(expo)!: use Expo CLI when building for development in Xcode (exp…
Browse files Browse the repository at this point in the history
…o#21397)

# Why

- Related expo#21396 
- Use `npx expo start --dev-client` instead of `npx react-native start`
when building a project from Xcode. This ensures we use the correct
version of Metro regardless of where the project is started.
- It's unclear if building from Android Studio is supposed to trigger
the bundler in development but I couldn't get it to do so, so this PR is
iOS-only.
<!--
Please describe the motivation for this PR, and link to relevant GitHub
issues, forums posts, or feature requests.
-->

# How

- Copy over a bunch of the default scripts from `react-native/scripts`
into the same locations in `expo/scripts` to make it easy to maintain
this change and simple to migrate.

I decided to omit the following as it appeared to be unused (sets
RCT_METRO_PORT):

```
source "$THIS_DIR/.packager.env"
```

I also dropped:
- Support for `$RCT_PACKAGER_LOGS_DIR`.
- The `Process terminated. Press <enter> to close the window` log that
is presented after closing the dev server.
- Support for a custom React Native CLI config (this is not supported in
Expo CLI).

<!--
How did you build this feature or fix this bug and why?
-->

# Test Plan

- TBD
- Building for development from Xcode causes a terminal window running
`npx expo start` will open instead of the community version.

<!--
Please describe how you tested this change and how a reviewer could
reproduce your test, especially if this PR does not include automated
tests! If possible, please also provide terminal output and/or
screenshots demonstrating your test/reproduction.
-->

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
This is required for changes to Expo modules.
-->

- [ ] Documentation is up to date to reflect these changes (eg:
https://docs.expo.dev and README.md).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
- [ ] This diff will work correctly for `expo prebuild` & EAS Build (eg:
updated a module plugin).

---------

Co-authored-by: Expo Bot <[email protected]>
Co-authored-by: Kudo Chien <[email protected]>
  • Loading branch information
3 people authored Mar 13, 2023
1 parent 0a6ddb2 commit b47ee28
Show file tree
Hide file tree
Showing 32 changed files with 468 additions and 488 deletions.
4 changes: 2 additions & 2 deletions apps/bare-expo/ios/BareExpo.xcodeproj/project.pbxproj

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions docs/pages/guides/customizing-metro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,5 @@ In the future, this will work universally across platforms with EAS Update hosti
> Experimental feature in SDK 49. Enable with the environment variable `EXPO_USE_PATH_ALIASES=1`.
Expo's Metro config has experimental support for the `compilerOptions.paths` and `compilerOptions.baseUrl` fields in the project's `tsconfig.json` (or `jsconfig.json`) file. This enables absolute imports and aliases in the project. Learn more in the [TypeScript guide](/guides/typescript).
These feature requires additional setup in bare projects. See the [versioned Metro setup guide](/versions/latest/config/metro#bare-workflow-setup) for more information.
2 changes: 2 additions & 0 deletions docs/pages/guides/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ The default alias is `@/`, but you can change this in your **tsconfig.json**:
- `jsconfig.json` can be used instead of `tsconfig.json` if you are not using TypeScript.
- Path aliases add additional resolution time when defined.
- Path aliases are Metro-only (including Metro web) and not supported by `@expo/webpack-config`.
- This feature requires additional setup in bare projects. See the [versioned Metro setup guide](/versions/latest/config/metro#bare-workflow-setup) for more information.

## Absolute Imports

Expand Down Expand Up @@ -134,6 +135,7 @@ The base directory can be modified in the **tsconfig.json** (or **jsconfig.json*
- Expo CLI must be restarted to update [`compilerOptions.baseUrl`][baseurl] when you change the **tsconfig.json**.
- `jsconfig.json` can be used instead of `tsconfig.json` if you are not using TypeScript.
- Absolute imports are Metro-only (including Metro web) and not supported by `@expo/webpack-config`.
- This feature requires additional setup in bare projects. See the [versioned Metro setup guide](/versions/latest/config/metro#bare-workflow-setup) for more information.

[baseurl]: https://www.typescriptlang.org/docs/handbook/module-resolution.html#base-url

Expand Down
37 changes: 35 additions & 2 deletions docs/pages/versions/unversioned/config/metro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,43 @@ react {

### `ios/<Project>.xcodeproj/project.pbxproj`

In your `ios/<Project>.xcodeproj/project.pbxproj` file, replace the "Bundle React Native code and images" script:
In your `ios/<Project>.xcodeproj/project.pbxproj` file, replace the following scripts:

#### "Start Packager"

```diff
+ shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\nexport RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > `$NODE_BINARY --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\"`\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open `$NODE_BINARY --print \"require('path').dirname(require.resolve('expo/package.json')) + '/scripts/launchPackager.command'\"` || echo \"Can't start packager automatically\"\n fi\nfi\n";
```

**Alternatively**, in the Xcode project, select the "Start Packager" build phase and add the following modifications:

```diff
+ if [[ -f "$PODS_ROOT/../.xcode.env" ]]; then
+ source "$PODS_ROOT/../.xcode.env"
+ fi
+ if [[ -f "$PODS_ROOT/../.xcode.env.local" ]]; then
+ source "$PODS_ROOT/../.xcode.env.local"
+ fi

export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > `$NODE_BINARY --print "require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'"`
if [ -z "${RCT_NO_LAUNCH_PACKAGER+xxx}" ] ; then
if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
exit 2
fi
else
- open `$NODE_BINARY --print "require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/launchPackager.command'"` || echo "Can't start packager automatically"
+ open `$NODE_BINARY --print "require('path').dirname(require.resolve('expo/package.json')) + '/scripts/launchPackager.command'"` || echo "Can't start packager automatically"
fi
fi
```

#### "Bundle React Native code and images"

```diff
+ shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios relative | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli')\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
+ shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios relative | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli')\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
```

**Alternatively**, in the Xcode project, select the "Bundle React Native code and images" build phase and add the following modifications:
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 @@ -23,6 +23,7 @@

### 💡 Others

- Update fixtures. ([#21397](https://github.com/expo/expo/pull/21397) by [@EvanBacon](https://github.com/EvanBacon))
- Upgrade e2e tests to SDK 47. ([#21335](https://github.com/expo/expo/pull/21335) by [@EvanBacon](https://github.com/EvanBacon))

## 0.6.1 — 2023-02-15
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ export default {
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\\"\${RCT_METRO_PORT:=8081}\\"\necho \\"export RCT_METRO_PORT=\${RCT_METRO_PORT}\\" > \\"\${SRCROOT}/../node_modules/react-native/scripts/.packager.env\\"\nif [ -z \\"\${RCT_NO_LAUNCH_PACKAGER+xxx}\\" ] ; then\n if nc -w 5 -z localhost \${RCT_METRO_PORT} ; then\n if ! curl -s \\"http://localhost:\${RCT_METRO_PORT}/status\\" | grep -q \\"packager-status:running\\" ; then\n echo \\"Port \${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\"\n exit 2\n fi\n else\n open \\"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\\" || echo \\"Can't start packager automatically\\"\n fi\nfi\n";
shellScript = "export RCT_METRO_PORT=\\"\${RCT_METRO_PORT:=8081}\\"\necho \\"export RCT_METRO_PORT=\${RCT_METRO_PORT}\\" > \\"\${SRCROOT}/../node_modules/react-native/scripts/.packager.env\\"\nif [ -z \\"\${RCT_NO_LAUNCH_PACKAGER+xxx}\\" ] ; then\n if nc -w 5 -z localhost \${RCT_METRO_PORT} ; then\n if ! curl -s \\"http://localhost:\${RCT_METRO_PORT}/status\\" | grep -q \\"packager-status:running\\" ; then\n echo \\"Port \${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\"\n exit 2\n fi\n else\n open \\"$SRCROOT/../node_modules/expo/scripts/launchPackager.command\\" || echo \\"Can't start packager automatically\\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ describe(ensureSwiftBridgingHeaderSetup, () => {
// Won't link a bridging header
expect(getDesignatedSwiftBridgingHeaderFileReference({ project })).toBe(null);

console.log('jj', Object.keys(vol.toJSON()));
expect(
vol.existsSync(path.join(projectRoot, 'ios/HelloWorld/HelloWorld-Bridging-Header.h'))
).toBe(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ exports[`BundleIdentifier module setBundleIdentifierForPbxproj sets the bundle i
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if [[ -f \\"$PODS_ROOT/../.xcode.env\\" ]]; then\\n source \\"$PODS_ROOT/../.xcode.env\\"\\nfi\\nif [[ -f \\"$PODS_ROOT/../.xcode.env.local\\" ]]; then\\n source \\"$PODS_ROOT/../.xcode.env.local\\"\\nfi\\n\\nexport RCT_METRO_PORT=\\"\${RCT_METRO_PORT:=8081}\\"\\necho \\"export RCT_METRO_PORT=\${RCT_METRO_PORT}\\" > \`$NODE_BINARY --print \\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\\"\`\\nif [ -z \\"\${RCT_NO_LAUNCH_PACKAGER+xxx}\\" ] ; then\\n if nc -w 5 -z localhost \${RCT_METRO_PORT} ; then\\n if ! curl -s \\"http://localhost:\${RCT_METRO_PORT}/status\\" | grep -q \\"packager-status:running\\" ; then\\n echo \\"Port \${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\"\\n exit 2\\n fi\\n else\\n open \`$NODE_BINARY --print \\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/launchPackager.command'\\"\` || echo \\"Can't start packager automatically\\"\\n fi\\nfi\\n";
shellScript = "if [[ -f \\"$PODS_ROOT/../.xcode.env\\" ]]; then\\n source \\"$PODS_ROOT/../.xcode.env\\"\\nfi\\nif [[ -f \\"$PODS_ROOT/../.xcode.env.local\\" ]]; then\\n source \\"$PODS_ROOT/../.xcode.env.local\\"\\nfi\\n\\nexport RCT_METRO_PORT=\\"\${RCT_METRO_PORT:=8081}\\"\\necho \\"export RCT_METRO_PORT=\${RCT_METRO_PORT}\\" > \`$NODE_BINARY --print \\"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/.packager.env'\\"\`\\nif [ -z \\"\${RCT_NO_LAUNCH_PACKAGER+xxx}\\" ] ; then\\n if nc -w 5 -z localhost \${RCT_METRO_PORT} ; then\\n if ! curl -s \\"http://localhost:\${RCT_METRO_PORT}/status\\" | grep -q \\"packager-status:running\\" ; then\\n echo \\"Port \${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\\"\\n exit 2\\n fi\\n else\\n open \`$NODE_BINARY --print \\"require('path').dirname(require.resolve('expo/package.json')) + '/scripts/launchPackager.command'\\"\` || echo \\"Can't start packager automatically\\"\\n fi\\nfi\\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
Expand Down
Loading

0 comments on commit b47ee28

Please sign in to comment.