feat(react-native): update @react-native-community/cli to 10.2.1 (#15738)

This commit is contained in:
Emily Xiong 2023-03-24 12:51:35 -04:00 committed by GitHub
parent 7a07b23de5
commit 04b6ddb596
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1568 additions and 301 deletions

View File

@ -5743,6 +5743,14 @@
"isExternal": false, "isExternal": false,
"disableCollapsible": false "disableCollapsible": false
}, },
{
"id": "build-ios",
"path": "/packages/react-native/executors/build-ios",
"name": "build-ios",
"children": [],
"isExternal": false,
"disableCollapsible": false
},
{ {
"id": "start", "id": "start",
"path": "/packages/react-native/executors/start", "path": "/packages/react-native/executors/start",
@ -5774,6 +5782,14 @@
"children": [], "children": [],
"isExternal": false, "isExternal": false,
"disableCollapsible": false "disableCollapsible": false
},
{
"id": "pod-install",
"path": "/packages/react-native/executors/pod-install",
"name": "pod-install",
"children": [],
"isExternal": false,
"disableCollapsible": false
} }
], ],
"isExternal": false, "isExternal": false,

View File

@ -2213,6 +2213,15 @@
"path": "/packages/react-native/executors/build-android", "path": "/packages/react-native/executors/build-android",
"type": "executor" "type": "executor"
}, },
"/packages/react-native/executors/build-ios": {
"description": "Build iOS app",
"file": "generated/packages/react-native/executors/build-ios.json",
"hidden": false,
"name": "build-ios",
"originalFilePath": "/packages/react-native/src/executors/build-ios/schema.json",
"path": "/packages/react-native/executors/build-ios",
"type": "executor"
},
"/packages/react-native/executors/start": { "/packages/react-native/executors/start": {
"description": "Starts the Javascript server that communicates with connected devices.", "description": "Starts the Javascript server that communicates with connected devices.",
"file": "generated/packages/react-native/executors/start.json", "file": "generated/packages/react-native/executors/start.json",
@ -2248,6 +2257,15 @@
"originalFilePath": "/packages/react-native/src/executors/storybook/schema.json", "originalFilePath": "/packages/react-native/src/executors/storybook/schema.json",
"path": "/packages/react-native/executors/storybook", "path": "/packages/react-native/executors/storybook",
"type": "executor" "type": "executor"
},
"/packages/react-native/executors/pod-install": {
"description": "Run `pod install` in the `ios` directory.",
"file": "generated/packages/react-native/executors/pod-install.json",
"hidden": false,
"name": "pod-install",
"originalFilePath": "/packages/react-native/src/executors/pod-install/schema.json",
"path": "/packages/react-native/executors/pod-install",
"type": "executor"
} }
}, },
"generators": { "generators": {

View File

@ -2186,6 +2186,15 @@
"path": "react-native/executors/build-android", "path": "react-native/executors/build-android",
"type": "executor" "type": "executor"
}, },
{
"description": "Build iOS app",
"file": "generated/packages/react-native/executors/build-ios.json",
"hidden": false,
"name": "build-ios",
"originalFilePath": "/packages/react-native/src/executors/build-ios/schema.json",
"path": "react-native/executors/build-ios",
"type": "executor"
},
{ {
"description": "Starts the Javascript server that communicates with connected devices.", "description": "Starts the Javascript server that communicates with connected devices.",
"file": "generated/packages/react-native/executors/start.json", "file": "generated/packages/react-native/executors/start.json",
@ -2221,6 +2230,15 @@
"originalFilePath": "/packages/react-native/src/executors/storybook/schema.json", "originalFilePath": "/packages/react-native/src/executors/storybook/schema.json",
"path": "react-native/executors/storybook", "path": "react-native/executors/storybook",
"type": "executor" "type": "executor"
},
{
"description": "Run `pod install` in the `ios` directory.",
"file": "generated/packages/react-native/executors/pod-install.json",
"hidden": false,
"name": "pod-install",
"originalFilePath": "/packages/react-native/src/executors/pod-install/schema.json",
"path": "react-native/executors/pod-install",
"type": "executor"
} }
], ],
"generators": [ "generators": [

View File

@ -52,7 +52,7 @@ yarn add --dev @nrwl/react-native
To create additional React Native apps run: To create additional React Native apps run:
```shell ```shell
nx g @nrwl/react-native:app your-app-name nx g @nrwl/react-native:app <your-app-name>
``` ```
### Generating Libraries ### Generating Libraries
@ -60,7 +60,7 @@ nx g @nrwl/react-native:app your-app-name
To generate a new library run: To generate a new library run:
```shell ```shell
npx nx g @nrwl/react-native:lib your-lib-name nx g @nrwl/react-native:lib your-lib-name
``` ```
### Generating Components ### Generating Components
@ -68,20 +68,78 @@ npx nx g @nrwl/react-native:lib your-lib-name
To generate a new component inside library run: To generate a new component inside library run:
```shell ```shell
npx nx g @nrwl/react-native:component your-component-name --project=your-lib-name --export nx g @nrwl/react-native:component your-component-name --project=your-lib-name --export
``` ```
Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json` Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json`
## Using React Native ### Upgrade React Native
- [run-ios](/packages/react-native/executors/run-ios) - Builds your app and starts it on iOS simulator or device The Nx CLI provides the [`migrate` command](/core-features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx.
- [run-android](/packages/react-native/executors/run-android) - Builds your app and starts it on a connected Android emulator or device
- [build-android](/packages/react-native/executors/build-android) - Release Build for Android #### Use upgrade-native Generator
- [start](/packages/react-native/executors/start) - Starts the server that communicates with connected devices
- [bundle](/packages/react-native/executors/bundle) - Builds the JavaScript bundle for offline use To upgrade native iOS and Android code to latest, you can use the [upgrade-native](/packages/react-native/generators/upgrade-native) generator:
- [sync-deps](/packages/react-native/executors/sync-deps) - Syncs dependencies to package.json (required for autolinking)
- [ensure-symlink](/packages/react-native/executors/ensure-symlink) - Ensure workspace node_modules is symlink under app's node_modules folder ```shell
nx generate @nrwl/react-native:upgrade-native <your-app-name>
```
This is a command that will replace the iOS and Android native code folder entirely.
#### Upgrade Manually
You can also upgrade React Native iOS and Android code using the [rn-diff-purge](https://react-native-community.github.io/upgrade-helper/) project.
### Start Metro Server
To start the server that communicates with connected devices:
```shell
nx start <your-app-name>
```
### Run iOS
To build your app and start it on iOS simulator or device:
```shell
nx run-ios <your-app-name>
```
### Run Android
To build your app and start it on a connected Android emulator or device:
```shell
nx run-android <your-app-name>
```
### Build iOS
To build an iOS app:
```shell
nx build-ios <your-app-name>
```
The build artifacts will be located under `<your app folder>/ios/build`.
You can specify the build folder by setting the `buildFolder` option:
```shell
nx build ios <your-app-name> --buildFolder="./build"
```
### Build Android
To build an Android app, run:
```shell
nx build-android <your app name>
```
The build artifacts will be located under `<your app folder>/android/app/build`.
## More Documentation ## More Documentation

View File

@ -10,23 +10,87 @@
"title": "Release Build for Android", "title": "Release Build for Android",
"description": "Build target options for Android.", "description": "Build target options for Android.",
"type": "object", "type": "object",
"presets": [
{
"name": "Build Android for current device architecture",
"keys": ["activeArchOnly"]
},
{ "name": "Build Android without metro cache", "keys": ["resetCache"] },
{ "name": "Build Android with specific tasks", "keys": ["tasks"] },
{ "name": "Build Android with a specific mode", "keys": ["mode"] }
],
"properties": { "properties": {
"apk": { "apk": {
"type": "boolean", "type": "boolean",
"description": "Generate apk file(s) rather than a bundle (`.aab`)." "description": "Generate apk file(s) rather than a bundle (`.aab`).",
"x-deprecated": "Use `tasks` option instead, e.g. `tasks=['bundleRelease']` to generate aab, `tasks=['assembleDebug']` to generate apk. Will be removed in Nx 17."
}, },
"debug": { "debug": {
"type": "boolean", "type": "boolean",
"description": "Generate a debug build instead of a release build." "description": "Generate a debug build instead of a release build.",
"x-deprecated": "Use `mode` option instead, e.g. `mode='debug'`. Deprecated from @react-native-community/cli. Will be removed in Nx 17."
}, },
"gradleTask": { "gradleTask": {
"type": "string", "type": "string",
"description": "Override default gradle task incase of multi build variants" "description": "Override default gradle task incase of multi build variants",
"x-deprecated": "Use `tasks` option instead, e.g. `tasks=['assembleDebug']`. Will be removed in Nx 17."
},
"mode": {
"type": "string",
"description": "Specify your app's build variant",
"default": "debug",
"examples": ["debug", "release"],
"x-priority": "important"
},
"packager": {
"type": "boolean",
"description": "Launch packager while building",
"default": true
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"tasks": {
"type": "array",
"items": { "type": "string" },
"description": "Run custom Gradle tasks. By default it's \"assembleDebug\". Will override passed mode and variant arguments.",
"examples": [
"assembleDebug",
"assembleRelease",
"bundleDebug",
"bundleRelease",
"installDebug",
"installRelease"
]
},
"activeArchOnly": {
"type": "boolean",
"description": "Build native libraries only for the current device architecture for debug builds.",
"default": false
},
"extraParams": {
"type": "string",
"description": "Custom params passed to gradle build command"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select build type and flavour to use before running a build"
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true
},
"resetCache": {
"type": "boolean",
"description": "Resets metro cache.",
"default": false
} }
}, },
"required": [], "required": [],
"examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:build-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Build with custom gradleTask\" %}\nThe `gradleTask` option accepts any custom gradle task, such as `assembleDebug`, `assembleRelease`, `bundleDebug`, `bundleRelease`:\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"gradleTask\": \"assembleDebug\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Create a build with apk format\" %}\n\nThe `apk` option allows you determine the format of android build. If set as true, it will create a build with `.apk` extension under apk folder; if set as false, it will create with `.aab` extension under bundle folder.\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"apk\": true\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build for debug/release\" %}\n\nIf set `debug` option as `true`, it will create a debug build; if set as `false`, it will create a release build.\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"debug\": true\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n", "examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:build-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Build with custom tasks\" %}\nThe `tasks` option accepts any custom gradle task, such as `assembleDebug`, `assembleRelease`, `bundleDebug`, `bundleRelease`, `installDebug`, `installRelease`.\nFor example, pass in `bundleRelease` or `bundleRelease` to tasks, it will create with `.aab` extension under bundle folder.\nPass in `assembleDebug` or `assembleRelease` to tasks, it will create a build with `.apk` extension under apk folder.\nPass in `installDebug` or `installRelease` to tasks, it will create a build with `.apk` extension and immediately install it on a running emulator or connected device.\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"tasks\": [\"bundleRelease\"]\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build for debug/release\" %}\n\nThe `mode` option allows you determine whether to build for debug/release apk.\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"mode\": \"debug\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build for current device architecture\" %}\n\nThe `activeArchOnly` option allows you to build native libraries only for the current device architecture for debug builds.\n\n```json\n \"build-android\": {\n \"executor\": \"@nrwl/react-native:build-android\",\n \"outputs\": [\n \"{projectRoot}/build/outputs/bundle\",\n \"{projectRoot}/build/outputs/apk\"\n ],\n \"options\": {\n \"activeArchOnly\": true\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n"
"presets": []
}, },
"description": "Release Build for Android.", "description": "Release Build for Android.",
"aliases": [], "aliases": [],

View File

@ -0,0 +1,106 @@
{
"name": "build-ios",
"implementation": "/packages/react-native/src/executors/build-ios/build-ios.impl.ts",
"schema": {
"$schema": "http://json-schema.org/schema",
"version": 2,
"cli": "nx",
"title": "React Native Build iOS executor",
"description": "Build iOS app.",
"type": "object",
"presets": [
{ "name": "Build iOS for a simulator", "keys": ["simulator"] },
{ "name": "Build iOS for a device", "keys": ["device"] },
{ "name": "Build iOS for a device with udid", "keys": ["udid"] },
{
"name": "Run `pod install` before building iOS app",
"keys": ["install"]
}
],
"properties": {
"simulator": {
"type": "string",
"description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: \"iPhone 6 (10.0)\"",
"examples": [
"iPhone 14",
"iPhone 13",
"iPhone 12",
"iPhone 11",
"iPhone X"
],
"x-priority": "important"
},
"mode": {
"type": "string",
"description": "Explicitly set the scheme configuration to use",
"default": "Debug",
"examples": ["Debug", "Release"],
"x-priority": "important"
},
"schema": {
"type": "string",
"description": "Explicitly set Xcode scheme to use"
},
"device": {
"type": "string",
"description": "Explicitly set device to use by name. The value is not required if you have a single device connected."
},
"udid": {
"type": "string",
"description": "Explicitly set device to use by udid"
},
"verbose": {
"type": "boolean",
"description": "Do not use xcbeautify or xcpretty even if installed"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"xcconfig": {
"type": "string",
"description": "Explicitly set xcconfig to use"
},
"buildFolder": {
"type": "string",
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory",
"default": "./build"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select which scheme and configuration to use before running a build"
},
"extraParams": {
"type": "string",
"description": "Custom params that will be passed to xcodebuild command."
},
"install": {
"type": "boolean",
"description": "Runs `pod install` for native modules before building iOS app."
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true
},
"resetCache": {
"type": "boolean",
"description": "Resets metro cache.",
"default": false
},
"packager": {
"type": "boolean",
"description": "Launch packager while building",
"default": true
}
},
"required": [],
"examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:build-ios\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Build the Debug/Release app\" %}\nThe `buildFolder` option allows to specify the location for ios build artifacts. It corresponds to Xcode's -derivedDataPath.\n\n```json\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {\n \"buildFolder\": \"dist/ios/build\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build the Debug/Release app\" %}\nThe `mode` option allows to specify the xcode configuartion, such as `Debug` or `Release`.\n\n```json\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {\n \"mode\": \"Release\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build for a simulator\" %}\nTo see all the available simulators, run command:\n\n```bash\nxcrun simctl list\n```\n\nThe `simulator` option allows you to launch your iOS app in a specific simulator:\n\n```json\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {\n \"simulator\": \"iPhone 14 Pro\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Build for a device\" %}\nThe `device` option allows you to launch your iOS app in a specific device.\n\nTo see all the available device, run command:\n\n```bash\nxcrun simctl list\n```\n\n```json\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {\n \"device\": \"deviceName\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Set Device by udid\" %}\nThe `udid` option allows you to explicitly set device to use by udid.\n\nTo see all the available simulators and devices with udid, run command:\n\n```bash\nxcrun simctl list\n```\n\n```json\n \"build-ios\": {\n \"executor\": \"@nrwl/react-native:build-ios\",\n \"options\": {\n \"udid\": \"device udid\"\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n"
},
"description": "Build iOS app",
"aliases": [],
"hidden": false,
"path": "/packages/react-native/src/executors/build-ios/schema.json",
"type": "executor"
}

View File

@ -10,6 +10,12 @@
"title": "Offline JS Bundle for React Native", "title": "Offline JS Bundle for React Native",
"description": "JS Bundle target options.", "description": "JS Bundle target options.",
"type": "object", "type": "object",
"presets": [
{ "name": "Bundle for a specific platform", "keys": ["platform"] },
{ "name": "Bundle a development build", "keys": ["dev"] },
{ "name": "Bundle to a specific output path", "keys": ["bundleOutput"] },
{ "name": "Bundle without global cache", "keys": ["resetCache"] }
],
"properties": { "properties": {
"entryFile": { "entryFile": {
"type": "string", "type": "string",
@ -68,13 +74,12 @@
}, },
"readGlobalCache": { "readGlobalCache": {
"type": "boolean", "type": "boolean",
"description": "Removes cached files.", "description": "Try to fetch transformed JS code from the global cache, if configured.",
"default": false "default": false
} }
}, },
"required": ["platform", "entryFile", "bundleOutput"], "required": ["platform", "entryFile", "bundleOutput"],
"examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"outputs\": [\"{projectRoot}/build\"],\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\"\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\"\n }\n }\n }\n}\n```\n\n```bash\nnx run mobile:bundle-ios\nnx run mobile:bundle-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Bundle with sourcemap\" %}\nThe `sourcemapOutput` option allows you to specify the path of the source map relative to app folder:\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"sourcemapOutput\": \"../../dist/apps/mobile/ios/main.map\",\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"sourcemapOutput\": \"../../dist/apps/mobile/android/main.map\",\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Create a dev/release bundle\" %}\n\nThe `dev` option determines whether to create a dev or release bundle. The default value is `true`, by setting it as `false`, warnings are disabled and the bundle is minified.\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"dev\": false\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"dev\": false\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Create a minified bundle\" %}\n\nThe `minify` option allows you to create a minified bundle:\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"minify\": true\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"minify\": true\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n", "examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"outputs\": [\"{projectRoot}/build\"],\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\"\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\"\n }\n }\n }\n}\n```\n\n```bash\nnx run mobile:bundle-ios\nnx run mobile:bundle-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Bundle with sourcemap\" %}\nThe `sourcemapOutput` option allows you to specify the path of the source map relative to app folder:\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"sourcemapOutput\": \"../../dist/apps/mobile/ios/main.map\",\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"sourcemapOutput\": \"../../dist/apps/mobile/android/main.map\",\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Create a dev/release bundle\" %}\n\nThe `dev` option determines whether to create a dev or release bundle. The default value is `true`, by setting it as `false`, warnings are disabled and the bundle is minified.\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"dev\": false\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"dev\": false\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Create a minified bundle\" %}\n\nThe `minify` option allows you to create a minified bundle:\n\n```json\n \"bundle-ios\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"ios\",\n \"bundleOutput\": \"dist/apps/mobile/ios/main.jsbundle\",\n \"minify\": true\n }\n },\n \"bundle-android\": {\n \"executor\": \"@nrwl/react-native:bundle\",\n \"options\": {\n \"entryFile\": \"src/main.tsx\",\n \"platform\": \"android\",\n \"bundleOutput\": \"dist/apps/mobile/android/main.jsbundle\",\n \"minify\": true\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n"
"presets": []
}, },
"description": "Builds the JavaScript bundle for offline use.", "description": "Builds the JavaScript bundle for offline use.",
"aliases": [], "aliases": [],

View File

@ -0,0 +1,28 @@
{
"name": "pod-install",
"implementation": "/packages/react-native/src/executors/pod-install/pod-install.impl.ts",
"schema": {
"version": 2,
"outputCapture": "direct-nodejs",
"cli": "nx",
"$id": "NxReactNativePodInstall",
"$schema": "http://json-schema.org/schema",
"title": "Run Pod Install for React Native iOS Project",
"description": "Run `pod install` for React Native iOS Project.",
"type": "object",
"properties": {
"buildFolder": {
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory",
"type": "string",
"default": "./build"
}
},
"required": ["buildFolder"],
"presets": []
},
"description": "Run `pod install` in the `ios` directory.",
"aliases": [],
"hidden": false,
"path": "/packages/react-native/src/executors/pod-install/schema.json",
"type": "executor"
}

View File

@ -12,9 +12,14 @@
"type": "object", "type": "object",
"presets": [ "presets": [
{ {
"name": "Run Android without cache", "name": "Run Android for the current device architecture",
"keys": ["variant", "sync", "port", "packager", "resetCache"] "keys": ["activeArchOnly"]
} },
{
"name": "Lists all available Android devices and simulators",
"keys": ["listDevices"]
},
{ "name": "Run Android without metro cache", "keys": ["resetCache"] }
], ],
"properties": { "properties": {
"variant": { "variant": {
@ -22,7 +27,12 @@
"description": "Specify your app's build variant (e.g. `debug`, `release`).", "description": "Specify your app's build variant (e.g. `debug`, `release`).",
"default": "debug", "default": "debug",
"examples": ["debug", "release"], "examples": ["debug", "release"],
"x-priority": "important" "x-deprecated": "Deprecated from @react-native-community/cli, use mode instead, e.g. mode=debug. Will be remove in Nx 17."
},
"jetifier": {
"type": "boolean",
"description": "Run Jetifier the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don't support AndroidX yet.",
"x-deprecated": "Deprecated from @react-native-community/cli. Will be remove in Nx 17."
}, },
"appId": { "appId": {
"type": "string", "type": "string",
@ -41,18 +51,25 @@
"type": "string", "type": "string",
"description": "Builds your app and starts it on a specific device/simulator with the given device id (listed by running `adb devices` on the command line)." "description": "Builds your app and starts it on a specific device/simulator with the given device id (listed by running `adb devices` on the command line)."
}, },
"tasks": { "listDevices": {
"type": "boolean",
"description": "Lists all available Android devices and simulators and let you choose one to run the app",
"default": false
},
"binaryPath": {
"type": "string", "type": "string",
"description": "Run custom Gradle tasks. If this argument is provided, then `--variant` option is ignored. Example: `yarn react-native run-android --tasks clean,installDebug`." "description": "Path relative to project root where pre-built .apk binary lives."
}, },
"jetifier": { "mode": {
"type": "boolean", "type": "string",
"description": "Run Jetifier the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don't support AndroidX yet.", "description": "Specify your app's build variant",
"default": true "default": "debug",
"examples": ["debug", "release"],
"x-priority": "important"
}, },
"sync": { "packager": {
"type": "boolean", "type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).", "description": "Launch packager while building",
"default": true "default": true
}, },
"port": { "port": {
@ -60,32 +77,45 @@
"description": "The port where the packager server is listening on.", "description": "The port where the packager server is listening on.",
"default": 8081 "default": 8081
}, },
"terminal": { "tasks": {
"type": "string", "type": "array",
"description": "Launches the Metro Bundler in a new window using the specified terminal path." "items": { "type": "string" },
"description": "Run custom Gradle tasks. By default it's \"assembleDebug\". Will override passed mode and variant arguments.",
"examples": [
"assembleDebug",
"assembleRelease",
"bundleDebug",
"bundleRelease",
"installDebug",
"installRelease"
]
}, },
"packager": { "activeArchOnly": {
"type": "boolean", "type": "boolean",
"description": "Starts the packager server.", "description": "Build native libraries only for the current device architecture for debug builds.",
"examples": ["x86_64", "arm64-v8a"],
"default": false
},
"extraParams": {
"type": "string",
"description": "Custom params passed to gradle build command"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select build type and flavour to use before running a build"
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true "default": true
}, },
"resetCache": { "resetCache": {
"type": "boolean", "type": "boolean",
"description": "Resets metro cache.", "description": "Resets metro cache.",
"default": false "default": false
},
"interactive": {
"type": "boolean",
"description": "Run packager server in interactive mode.",
"default": true
},
"activeArchOnly": {
"type": "boolean",
"description": "Builds only for the active architecture (e.g. x86_64, arm64-v8a).",
"default": false
} }
}, },
"examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:run-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Run on a specific device/simulator\" %}\nTo see all the avaiable emulators, run command:\n\n```bash\nemulator -list-avds\n```\n\nThe `deviceId` option allows you to launch your android app in a specific device/simulator:\n\n```json\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {\n \"deviceId\": \"Pixel_5_API_30\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run the debug/release app\" %}\nThe `variant` option allows to specify the build variant, such as `debug` or `release`.\n\n```json\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {\n \"variant\": \"release\"\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n" "examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:run-android\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Run on a specific device/simulator\" %}\nTo see all the avaiable emulators, run command:\n\n```bash\nemulator -list-avds\n```\n\nThe `deviceId` option allows you to launch your android app in a specific device/simulator:\n\n```json\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {\n \"deviceId\": \"Pixel_5_API_30\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run the debug/release app\" %}\nThe `mode` option allows to specify the build variant, such as `debug` or `release`.\n\n```json\n \"run-android\": {\n \"executor\": \"@nrwl/react-native:run-android\",\n \"options\": {\n \"mode\": \"release\"\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n"
}, },
"description": "Runs Android application.", "description": "Runs Android application.",
"aliases": [], "aliases": [],

View File

@ -11,16 +11,12 @@
"description": "Run iOS target options.", "description": "Run iOS target options.",
"type": "object", "type": "object",
"presets": [ "presets": [
{ "name": "Run iOS on a simulator", "keys": ["simulator"] },
{ "name": "Run iOS on a device", "keys": ["device"] },
{ "name": "Run iOS on a device with udid", "keys": ["udid"] },
{ {
"name": "Run iOS without cache", "name": "Run `pod install` before building iOS app",
"keys": [ "keys": ["install"]
"xcodeConfiguration",
"install",
"sync",
"port",
"packager",
"resetCache"
]
} }
], ],
"properties": { "properties": {
@ -29,16 +25,11 @@
"description": "Explicitly set the Xcode configuration to use.", "description": "Explicitly set the Xcode configuration to use.",
"default": "Debug", "default": "Debug",
"examples": ["Debug", "Release"], "examples": ["Debug", "Release"],
"x-priority": "important" "x-deprecated": "Use `mode` instead. Deprecated from @react-native-community/cli. Will be removed in Nx 17."
},
"scheme": {
"type": "string",
"description": "Explicitly set the Xcode scheme to use."
}, },
"simulator": { "simulator": {
"type": "string", "type": "string",
"description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: `iPhone X (12.1)`.", "description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: \"iPhone 6 (10.0)\"",
"default": "iPhone 14",
"examples": [ "examples": [
"iPhone 14", "iPhone 14",
"iPhone 13", "iPhone 13",
@ -48,10 +39,50 @@
], ],
"x-priority": "important" "x-priority": "important"
}, },
"mode": {
"type": "string",
"description": "Explicitly set the scheme configuration to use",
"default": "Debug",
"examples": ["Debug", "Release"],
"x-priority": "important"
},
"schema": {
"type": "string",
"description": "Explicitly set Xcode scheme to use"
},
"device": { "device": {
"type": "string", "type": "string",
"description": "Explicitly set device to use by name. The value is not required if you have a single device connected.", "description": "Explicitly set device to use by name. The value is not required if you have a single device connected."
"x-priority": "important" },
"udid": {
"type": "string",
"description": "Explicitly set device to use by udid"
},
"verbose": {
"type": "boolean",
"description": "Do not use xcbeautify or xcpretty even if installed"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"xcconfig": {
"type": "string",
"description": "Explicitly set xcconfig to use"
},
"buildFolder": {
"type": "string",
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory.",
"buildFolder": "./build"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select which scheme and configuration to use before running a build"
},
"extraParams": {
"type": "string",
"description": "Custom params that will be passed to xcodebuild command."
}, },
"install": { "install": {
"type": "boolean", "type": "boolean",
@ -60,22 +91,7 @@
}, },
"sync": { "sync": {
"type": "boolean", "type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink). Always true when `--install` is used.", "description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true,
"x-priority": "internal"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"terminal": {
"type": "string",
"description": "Launches the Metro Bundler in a new window using the specified terminal path."
},
"packager": {
"type": "boolean",
"description": "Starts the packager server.",
"default": true "default": true
}, },
"resetCache": { "resetCache": {
@ -83,13 +99,17 @@
"description": "Resets metro cache.", "description": "Resets metro cache.",
"default": false "default": false
}, },
"interactive": { "packager": {
"type": "boolean", "type": "boolean",
"description": "Run packager server in interactive mode.", "description": "Launch packager while building",
"default": true "default": true
},
"binaryPath": {
"type": "string",
"description": "Path relative to project root where pre-built .app binary lives."
} }
}, },
"examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:run-ios\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Run on a simulator\" %}\nTo see all the available simulators, run command:\n\n```bash\nxcrun simctl list\n```\n\nThe `simulator` option allows you to launch your iOS app in a specific simulator:\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"simulator\": \"iPhone 14 Pro\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run on a device\" %}\nThe `device` option allows you to launch your iOS app in a specific device.\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"device\": \"deviceName\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run the Debug/Release app\" %}\nThe `xcodeConfiguration` option allows to specify the xcode configuartion, such as `Debug` or `Release`.\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"xcodeConfiguration\": \"Release\"\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n" "examplesFile": "`project.json`:\n\n```json\n{\n \"name\": \"mobile\",\n //...\n \"targets\": {\n //...\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {}\n }\n }\n}\n```\n\n```bash\nnx run mobile:run-ios\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Build the Debug/Release app\" %}\nThe `mode` option allows to specify the xcode configuartion schema, such as `Debug` or `Release`.\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"mode\": \"Release\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run on a simulator\" %}\nTo see all the available simulators, run command:\n\n```bash\nxcrun simctl list\n```\n\nThe `simulator` option allows you to launch your iOS app in a specific simulator:\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"simulator\": \"iPhone 14 Pro\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Run on a device\" %}\nThe `device` option allows you to launch your iOS app in a specific device.\n\nTo see all the available devices, run command:\n\n```bash\nxcrun simctl list\n```\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"device\": \"deviceName\"\n }\n }\n```\n\n{% /tab %}\n{% tab label=\"Set Device by udid\" %}\nThe `udid` option allows you to explicitly set device to use by udid.\n\nTo see all the available simulators and devices with udid, run command:\n\n```bash\nxcrun simctl list\n```\n\n```json\n \"run-ios\": {\n \"executor\": \"@nrwl/react-native:run-ios\",\n \"options\": {\n \"udid\": \"device udid\"\n }\n }\n```\n\n{% /tab %}\n{% /tabs %}\n\n---\n"
}, },
"description": "Runs iOS application.", "description": "Runs iOS application.",
"aliases": [], "aliases": [],

View File

@ -52,7 +52,7 @@ yarn add --dev @nrwl/react-native
To create additional React Native apps run: To create additional React Native apps run:
```shell ```shell
nx g @nrwl/react-native:app your-app-name nx g @nrwl/react-native:app <your-app-name>
``` ```
### Generating Libraries ### Generating Libraries
@ -60,7 +60,7 @@ nx g @nrwl/react-native:app your-app-name
To generate a new library run: To generate a new library run:
```shell ```shell
npx nx g @nrwl/react-native:lib your-lib-name nx g @nrwl/react-native:lib your-lib-name
``` ```
### Generating Components ### Generating Components
@ -68,20 +68,78 @@ npx nx g @nrwl/react-native:lib your-lib-name
To generate a new component inside library run: To generate a new component inside library run:
```shell ```shell
npx nx g @nrwl/react-native:component your-component-name --project=your-lib-name --export nx g @nrwl/react-native:component your-component-name --project=your-lib-name --export
``` ```
Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json` Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json`
## Using React Native ### Upgrade React Native
- [run-ios](/packages/react-native/executors/run-ios) - Builds your app and starts it on iOS simulator or device The Nx CLI provides the [`migrate` command](/core-features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx.
- [run-android](/packages/react-native/executors/run-android) - Builds your app and starts it on a connected Android emulator or device
- [build-android](/packages/react-native/executors/build-android) - Release Build for Android #### Use upgrade-native Generator
- [start](/packages/react-native/executors/start) - Starts the server that communicates with connected devices
- [bundle](/packages/react-native/executors/bundle) - Builds the JavaScript bundle for offline use To upgrade native iOS and Android code to latest, you can use the [upgrade-native](/packages/react-native/generators/upgrade-native) generator:
- [sync-deps](/packages/react-native/executors/sync-deps) - Syncs dependencies to package.json (required for autolinking)
- [ensure-symlink](/packages/react-native/executors/ensure-symlink) - Ensure workspace node_modules is symlink under app's node_modules folder ```shell
nx generate @nrwl/react-native:upgrade-native <your-app-name>
```
This is a command that will replace the iOS and Android native code folder entirely.
#### Upgrade Manually
You can also upgrade React Native iOS and Android code using the [rn-diff-purge](https://react-native-community.github.io/upgrade-helper/) project.
### Start Metro Server
To start the server that communicates with connected devices:
```shell
nx start <your-app-name>
```
### Run iOS
To build your app and start it on iOS simulator or device:
```shell
nx run-ios <your-app-name>
```
### Run Android
To build your app and start it on a connected Android emulator or device:
```shell
nx run-android <your-app-name>
```
### Build iOS
To build an iOS app:
```shell
nx build-ios <your-app-name>
```
The build artifacts will be located under `<your app folder>/ios/build`.
You can specify the build folder by setting the `buildFolder` option:
```shell
nx build ios <your-app-name> --buildFolder="./build"
```
### Build Android
To build an Android app, run:
```shell
nx build-android <your app name>
```
The build artifacts will be located under `<your app folder>/android/app/build`.
## More Documentation ## More Documentation

View File

@ -2,13 +2,18 @@ import {
checkFilesExist, checkFilesExist,
cleanupProject, cleanupProject,
expectTestsPass, expectTestsPass,
isOSX,
killPorts,
newProject, newProject,
promisifiedTreeKill,
readJson, readJson,
runCLI, runCLI,
runCLIAsync, runCLIAsync,
runCommandUntil,
uniq, uniq,
updateFile, updateFile,
} from '@nrwl/e2e/utils'; } from '@nrwl/e2e/utils';
import { ChildProcess } from 'child_process';
import { join } from 'path'; import { join } from 'path';
describe('react native', () => { describe('react native', () => {
@ -27,7 +32,7 @@ describe('react native', () => {
}); });
afterAll(() => cleanupProject()); afterAll(() => cleanupProject());
it('should test, create ios and android JS bundles', async () => { it('should test and lint', async () => {
const componentName = uniq('component'); const componentName = uniq('component');
runCLI( runCLI(
`generate @nrwl/react-native:component ${componentName} --project=${libName} --export --no-interactive` `generate @nrwl/react-native:component ${componentName} --project=${libName} --export --no-interactive`
@ -46,7 +51,9 @@ describe('react native', () => {
const libLintResults = await runCLIAsync(`lint ${libName}`); const libLintResults = await runCLIAsync(`lint ${libName}`);
expect(libLintResults.combinedOutput).toContain('All files pass linting.'); expect(libLintResults.combinedOutput).toContain('All files pass linting.');
});
it('should bundle-ios', async () => {
const iosBundleResult = await runCLIAsync( const iosBundleResult = await runCLIAsync(
`bundle-ios ${appName} --sourcemapOutput=../../dist/apps/${appName}/ios/main.map` `bundle-ios ${appName} --sourcemapOutput=../../dist/apps/${appName}/ios/main.map`
); );
@ -57,7 +64,9 @@ describe('react native', () => {
checkFilesExist(`dist/apps/${appName}/ios/main.jsbundle`); checkFilesExist(`dist/apps/${appName}/ios/main.jsbundle`);
checkFilesExist(`dist/apps/${appName}/ios/main.map`); checkFilesExist(`dist/apps/${appName}/ios/main.map`);
}).not.toThrow(); }).not.toThrow();
});
it('should bundle-android', async () => {
const androidBundleResult = await runCLIAsync( const androidBundleResult = await runCLIAsync(
`bundle-android ${appName} --sourcemapOutput=../../dist/apps/${appName}/android/main.map` `bundle-android ${appName} --sourcemapOutput=../../dist/apps/${appName}/android/main.map`
); );
@ -68,7 +77,45 @@ describe('react native', () => {
checkFilesExist(`dist/apps/${appName}/android/main.jsbundle`); checkFilesExist(`dist/apps/${appName}/android/main.jsbundle`);
checkFilesExist(`dist/apps/${appName}/android/main.map`); checkFilesExist(`dist/apps/${appName}/android/main.map`);
}).not.toThrow(); }).not.toThrow();
}, 1000000); });
it('should start', async () => {
let process: ChildProcess;
const port = 8081;
try {
process = await runCommandUntil(
`start ${appName} --interactive=false --port=${port}`,
(output) => {
return (
output.includes(`Packager is ready at http://localhost::${port}`) ||
output.includes('Starting JS server...')
);
}
);
} catch (err) {
console.error(err);
}
// port and process cleanup
try {
if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL');
await killPorts(port);
}
} catch (err) {
expect(err).toBeFalsy();
}
});
if (isOSX()) {
it('should pod install', async () => {
expect(async () => {
await runCLIAsync(`pod-install ${appName}`);
checkFilesExist(`apps/${appName}/ios/Podfile.lock`);
}).not.toThrow();
});
}
it('should create storybook with application', async () => { it('should create storybook with application', async () => {
runCLI( runCLI(

View File

@ -3,13 +3,13 @@ import * as chalk from 'chalk';
import { GeneratorCallback, logger } from '@nrwl/devkit'; import { GeneratorCallback, logger } from '@nrwl/devkit';
export function runSymlink( export function runSymlink(
worksapceRoot: string, workspaceRoot: string,
projectRoot: string projectRoot: string
): GeneratorCallback { ): GeneratorCallback {
return () => { return () => {
logger.info(`creating symlinks for ${chalk.bold(projectRoot)}`); logger.info(`creating symlinks for ${chalk.bold(projectRoot)}`);
try { try {
ensureNodeModulesSymlink(worksapceRoot, projectRoot); ensureNodeModulesSymlink(workspaceRoot, projectRoot);
} catch { } catch {
throw new Error( throw new Error(
`Failed to create symlinks for ${chalk.bold(projectRoot)}` `Failed to create symlinks for ${chalk.bold(projectRoot)}`

View File

@ -25,8 +25,11 @@ nx run mobile:build-android
## Examples ## Examples
{% tabs %} {% tabs %}
{% tab label="Build with custom gradleTask" %} {% tab label="Build with custom tasks" %}
The `gradleTask` option accepts any custom gradle task, such as `assembleDebug`, `assembleRelease`, `bundleDebug`, `bundleRelease`: The `tasks` option accepts any custom gradle task, such as `assembleDebug`, `assembleRelease`, `bundleDebug`, `bundleRelease`, `installDebug`, `installRelease`.
For example, pass in `bundleRelease` or `bundleRelease` to tasks, it will create with `.aab` extension under bundle folder.
Pass in `assembleDebug` or `assembleRelease` to tasks, it will create a build with `.apk` extension under apk folder.
Pass in `installDebug` or `installRelease` to tasks, it will create a build with `.apk` extension and immediately install it on a running emulator or connected device.
```json ```json
"build-android": { "build-android": {
@ -36,25 +39,7 @@ The `gradleTask` option accepts any custom gradle task, such as `assembleDebug`,
"{projectRoot}/build/outputs/apk" "{projectRoot}/build/outputs/apk"
], ],
"options": { "options": {
"gradleTask": "assembleDebug" "tasks": ["bundleRelease"]
}
}
```
{% /tab %}
{% tab label="Create a build with apk format" %}
The `apk` option allows you determine the format of android build. If set as true, it will create a build with `.apk` extension under apk folder; if set as false, it will create with `.aab` extension under bundle folder.
```json
"build-android": {
"executor": "@nrwl/react-native:build-android",
"outputs": [
"{projectRoot}/build/outputs/bundle",
"{projectRoot}/build/outputs/apk"
],
"options": {
"apk": true
} }
} }
``` ```
@ -62,7 +47,7 @@ The `apk` option allows you determine the format of android build. If set as tru
{% /tab %} {% /tab %}
{% tab label="Build for debug/release" %} {% tab label="Build for debug/release" %}
If set `debug` option as `true`, it will create a debug build; if set as `false`, it will create a release build. The `mode` option allows you determine whether to build for debug/release apk.
```json ```json
"build-android": { "build-android": {
@ -72,7 +57,25 @@ If set `debug` option as `true`, it will create a debug build; if set as `false`
"{projectRoot}/build/outputs/apk" "{projectRoot}/build/outputs/apk"
], ],
"options": { "options": {
"debug": true "mode": "debug"
}
}
```
{% /tab %}
{% tab label="Build for current device architecture" %}
The `activeArchOnly` option allows you to build native libraries only for the current device architecture for debug builds.
```json
"build-android": {
"executor": "@nrwl/react-native:build-android",
"outputs": [
"{projectRoot}/build/outputs/bundle",
"{projectRoot}/build/outputs/apk"
],
"options": {
"activeArchOnly": true
} }
} }
``` ```

View File

@ -0,0 +1,109 @@
`project.json`:
```json
{
"name": "mobile",
//...
"targets": {
//...
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {}
}
}
}
```
```bash
nx run mobile:build-ios
```
## Examples
{% tabs %}
{% tab label="Build the Debug/Release app" %}
The `buildFolder` option allows to specify the location for ios build artifacts. It corresponds to Xcode's -derivedDataPath.
```json
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {
"buildFolder": "dist/ios/build"
}
}
```
{% /tab %}
{% tab label="Build the Debug/Release app" %}
The `mode` option allows to specify the xcode configuartion, such as `Debug` or `Release`.
```json
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {
"mode": "Release"
}
}
```
{% /tab %}
{% tab label="Build for a simulator" %}
To see all the available simulators, run command:
```bash
xcrun simctl list
```
The `simulator` option allows you to launch your iOS app in a specific simulator:
```json
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {
"simulator": "iPhone 14 Pro"
}
}
```
{% /tab %}
{% tab label="Build for a device" %}
The `device` option allows you to launch your iOS app in a specific device.
To see all the available device, run command:
```bash
xcrun simctl list
```
```json
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {
"device": "deviceName"
}
}
```
{% /tab %}
{% tab label="Set Device by udid" %}
The `udid` option allows you to explicitly set device to use by udid.
To see all the available simulators and devices with udid, run command:
```bash
xcrun simctl list
```
```json
"build-ios": {
"executor": "@nrwl/react-native:build-ios",
"options": {
"udid": "device udid"
}
}
```
{% /tab %}
{% /tabs %}
---

View File

@ -41,13 +41,13 @@ The `deviceId` option allows you to launch your android app in a specific device
{% /tab %} {% /tab %}
{% tab label="Run the debug/release app" %} {% tab label="Run the debug/release app" %}
The `variant` option allows to specify the build variant, such as `debug` or `release`. The `mode` option allows to specify the build variant, such as `debug` or `release`.
```json ```json
"run-android": { "run-android": {
"executor": "@nrwl/react-native:run-android", "executor": "@nrwl/react-native:run-android",
"options": { "options": {
"variant": "release" "mode": "release"
} }
} }
``` ```

View File

@ -21,6 +21,19 @@ nx run mobile:run-ios
## Examples ## Examples
{% tabs %} {% tabs %}
{% tab label="Build the Debug/Release app" %}
The `mode` option allows to specify the xcode configuartion schema, such as `Debug` or `Release`.
```json
"run-ios": {
"executor": "@nrwl/react-native:run-ios",
"options": {
"mode": "Release"
}
}
```
{% /tab %}
{% tab label="Run on a simulator" %} {% tab label="Run on a simulator" %}
To see all the available simulators, run command: To see all the available simulators, run command:
@ -43,6 +56,12 @@ The `simulator` option allows you to launch your iOS app in a specific simulator
{% tab label="Run on a device" %} {% tab label="Run on a device" %}
The `device` option allows you to launch your iOS app in a specific device. The `device` option allows you to launch your iOS app in a specific device.
To see all the available devices, run command:
```bash
xcrun simctl list
```
```json ```json
"run-ios": { "run-ios": {
"executor": "@nrwl/react-native:run-ios", "executor": "@nrwl/react-native:run-ios",
@ -53,14 +72,20 @@ The `device` option allows you to launch your iOS app in a specific device.
``` ```
{% /tab %} {% /tab %}
{% tab label="Run the Debug/Release app" %} {% tab label="Set Device by udid" %}
The `xcodeConfiguration` option allows to specify the xcode configuartion, such as `Debug` or `Release`. The `udid` option allows you to explicitly set device to use by udid.
To see all the available simulators and devices with udid, run command:
```bash
xcrun simctl list
```
```json ```json
"run-ios": { "run-ios": {
"executor": "@nrwl/react-native:run-ios", "executor": "@nrwl/react-native:run-ios",
"options": { "options": {
"xcodeConfiguration": "Release" "udid": "device udid"
} }
} }
``` ```

View File

@ -20,6 +20,11 @@
"schema": "./src/executors/build-android/schema.json", "schema": "./src/executors/build-android/schema.json",
"description": "Release Build for Android." "description": "Release Build for Android."
}, },
"build-ios": {
"implementation": "./src/executors/build-ios/build-ios.impl",
"schema": "./src/executors/build-ios/schema.json",
"description": "Build iOS app"
},
"start": { "start": {
"implementation": "./src/executors/start/start.impl", "implementation": "./src/executors/start/start.impl",
"schema": "./src/executors/start/schema.json", "schema": "./src/executors/start/schema.json",
@ -39,6 +44,11 @@
"implementation": "./src/executors/storybook/storybook.impl", "implementation": "./src/executors/storybook/storybook.impl",
"schema": "./src/executors/storybook/schema.json", "schema": "./src/executors/storybook/schema.json",
"description": "Serve React Native Storybook." "description": "Serve React Native Storybook."
},
"pod-install": {
"implementation": "./src/executors/pod-install/pod-install.impl",
"schema": "./src/executors/pod-install/schema.json",
"description": "Run `pod install` in the `ios` directory."
} }
}, },
"builders": { "builders": {
@ -62,6 +72,11 @@
"schema": "./src/executors/build-android/schema.json", "schema": "./src/executors/build-android/schema.json",
"description": "Release Build for Android." "description": "Release Build for Android."
}, },
"build-ios": {
"implementation": "./src/executors/build-ios/compat",
"schema": "./src/executors/build-ios/schema.json",
"description": "Build iOS app"
},
"start": { "start": {
"implementation": "./src/executors/start/compat", "implementation": "./src/executors/start/compat",
"schema": "./src/executors/start/schema.json", "schema": "./src/executors/start/schema.json",
@ -81,6 +96,11 @@
"implementation": "./src/executors/storybook/compat", "implementation": "./src/executors/storybook/compat",
"schema": "./src/executors/storybook/schema.json", "schema": "./src/executors/storybook/schema.json",
"description": "Serve React Native Storybook." "description": "Serve React Native Storybook."
},
"pod-install": {
"implementation": "./src/executors/pod-install/compat",
"schema": "./src/executors/pod-install/schema.json",
"description": "Run `pod install` in the `ios` directory."
} }
} }
} }

View File

@ -71,6 +71,12 @@
"version": "15.0.0-beta.0", "version": "15.0.0-beta.0",
"description": "Adds babel.config.json to the hash of all tasks", "description": "Adds babel.config.json to the hash of all tasks",
"factory": "./src/migrations/update-15-0-0/add-babel-inputs" "factory": "./src/migrations/update-15-0-0/add-babel-inputs"
},
"add-build-ios-target": {
"cli": "nx",
"version": "15.9.1-beta.0",
"description": "Add target build-ios and pod-install for react native apps",
"factory": "./src/migrations/update-15-9-1/add-build-ios-target"
} }
}, },
"packageJsonUpdates": { "packageJsonUpdates": {
@ -1261,6 +1267,19 @@
"alwaysAddToPackageJson": false "alwaysAddToPackageJson": false
} }
} }
},
"15.9.1": {
"version": "15.9.1-beta.0",
"packages": {
"@react-native-community/cli": {
"version": "10.2.1",
"alwaysAddToPackageJson": false
},
"@react-native-community/cli-platform-ios": {
"version": "10.2.1",
"alwaysAddToPackageJson": false
}
}
} }
} }
} }

View File

@ -1,9 +1,16 @@
import { ExecutorContext } from '@nrwl/devkit'; import { ExecutorContext, names } from '@nrwl/devkit';
import { join } from 'path'; import { join } from 'path';
import { ensureNodeModulesSymlink } from '../../utils/ensure-node-modules-symlink'; import { ensureNodeModulesSymlink } from '../../utils/ensure-node-modules-symlink';
import { ChildProcess, spawn } from 'child_process'; import { ChildProcess, fork } from 'child_process';
import { ReactNativeBuildOptions } from './schema'; import { ReactNativeBuildAndroidOptions } from './schema';
import { chmodAndroidGradlewFiles } from '../../utils/chmod-android-gradle-files'; import { chmodAndroidGradlewFiles } from '../../utils/chmod-android-gradle-files';
import { runCliStart } from '../start/start.impl';
import {
displayNewlyAddedDepsMessage,
syncDeps,
} from '../sync-deps/sync-deps.impl';
import { getCliOptions } from '../../utils/get-cli-options';
export interface ReactNativeBuildOutput { export interface ReactNativeBuildOutput {
success: boolean; success: boolean;
} }
@ -11,16 +18,39 @@ export interface ReactNativeBuildOutput {
let childProcess: ChildProcess; let childProcess: ChildProcess;
export default async function* buildAndroidExecutor( export default async function* buildAndroidExecutor(
options: ReactNativeBuildOptions, options: ReactNativeBuildAndroidOptions,
context: ExecutorContext context: ExecutorContext
): AsyncGenerator<ReactNativeBuildOutput> { ): AsyncGenerator<ReactNativeBuildOutput> {
const projectRoot = const projectRoot =
context.projectsConfigurations.projects[context.projectName].root; context.projectsConfigurations.projects[context.projectName].root;
ensureNodeModulesSymlink(context.root, projectRoot); ensureNodeModulesSymlink(context.root, projectRoot);
if (options.sync) {
displayNewlyAddedDepsMessage(
context.projectName,
await syncDeps(
context.projectName,
projectRoot,
context.root,
context.projectGraph
)
);
}
chmodAndroidGradlewFiles(join(projectRoot, 'android')); chmodAndroidGradlewFiles(join(projectRoot, 'android'));
try { try {
await runCliBuild(context.root, projectRoot, options); const tasks = [runCliBuild(context.root, projectRoot, options)];
if (options.packager && options.mode !== 'release') {
tasks.push(
runCliStart(context.root, projectRoot, {
port: options.port,
resetCache: options.resetCache,
interactive: options.interactive,
})
);
}
await Promise.all(tasks);
yield { success: true }; yield { success: true };
} finally { } finally {
if (childProcess) { if (childProcess) {
@ -32,17 +62,19 @@ export default async function* buildAndroidExecutor(
function runCliBuild( function runCliBuild(
workspaceRoot: string, workspaceRoot: string,
projectRoot: string, projectRoot: string,
options: ReactNativeBuildOptions options: ReactNativeBuildAndroidOptions
) { ) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const gradleCommand = getGradleCommand(options); /**
* Call the react native cli with option `--no-packager`
childProcess = spawn( * Not passing '--packager' due to cli will launch start command from the project root
process.platform === 'win32' ? 'gradlew.bat' : './gradlew', */
[gradleCommand], childProcess = fork(
join(workspaceRoot, './node_modules/react-native/cli.js'),
['run-android', ...createBuildAndroidOptions(options), '--no-packager'],
{ {
cwd: join(workspaceRoot, projectRoot, 'android'), cwd: join(workspaceRoot, projectRoot),
stdio: [0, 1, 2], env: { ...process.env, RCT_METRO_PORT: options.port.toString() },
} }
); );
@ -63,19 +95,14 @@ function runCliBuild(
}); });
} }
function getGradleCommand(options: ReactNativeBuildOptions) { const nxOptions = ['sync', 'packager'];
if (options?.gradleTask) { const startOptions = ['port', 'resetCache'];
return options.gradleTask; const deprecatedOptions = ['apk', 'debug', 'gradleTask'];
}
if (options.apk) { function createBuildAndroidOptions(options: ReactNativeBuildAndroidOptions) {
if (options.debug) { return getCliOptions<ReactNativeBuildAndroidOptions>(options, [
return 'assembleDebug'; ...nxOptions,
} ...startOptions,
return 'assembleRelease'; ...deprecatedOptions,
} else { ]);
if (options.debug) {
return 'bundleDebug';
}
return 'bundleRelease';
}
} }

View File

@ -1,5 +1,31 @@
export interface ReactNativeBuildOptions { // options taken from https://github.com/react-native-community/cli/blob/main/packages/cli-platform-android/src/commands/buildAndroid/index.ts
import { ReactNativeStartOptions } from '../start/schema';
export interface ReactNativeBuildAndroidOptions
extends ReactNativeStartOptions {
/**
* @deprecated, use tasks instead. e.g. tasks=['bundleRelease'] for aab, and tasks=['assembleRelease'] for apk. Will be removed in nx 17.
*/
apk?: boolean; apk?: boolean;
/**
* @deprecated, use mode='debug' instead. Will be removed in nx 17.
*/
debug?: boolean; debug?: boolean;
/**
* @deprecated, use tasks instead instead. Will be removed in nx 17.
*/
gradleTask?: string; gradleTask?: string;
// react native options
mode: string; // default is debug
activeArchOnly: boolean; // default is false
port: number; // default is 8081
tasks?: Array<string>;
extraParams?: Array<string>;
interactive?: boolean;
// nx options
packager: boolean; // default is true
sync: boolean;
} }

View File

@ -7,18 +7,94 @@
"title": "Release Build for Android", "title": "Release Build for Android",
"description": "Build target options for Android.", "description": "Build target options for Android.",
"type": "object", "type": "object",
"presets": [
{
"name": "Build Android for current device architecture",
"keys": ["activeArchOnly"]
},
{
"name": "Build Android without metro cache",
"keys": ["resetCache"]
},
{
"name": "Build Android with specific tasks",
"keys": ["tasks"]
},
{
"name": "Build Android with a specific mode",
"keys": ["mode"]
}
],
"properties": { "properties": {
"apk": { "apk": {
"type": "boolean", "type": "boolean",
"description": "Generate apk file(s) rather than a bundle (`.aab`)." "description": "Generate apk file(s) rather than a bundle (`.aab`).",
"x-deprecated": "Use `tasks` option instead, e.g. `tasks=['bundleRelease']` to generate aab, `tasks=['assembleDebug']` to generate apk. Will be removed in Nx 17."
}, },
"debug": { "debug": {
"type": "boolean", "type": "boolean",
"description": "Generate a debug build instead of a release build." "description": "Generate a debug build instead of a release build.",
"x-deprecated": "Use `mode` option instead, e.g. `mode='debug'`. Deprecated from @react-native-community/cli. Will be removed in Nx 17."
}, },
"gradleTask": { "gradleTask": {
"type": "string", "type": "string",
"description": "Override default gradle task incase of multi build variants" "description": "Override default gradle task incase of multi build variants",
"x-deprecated": "Use `tasks` option instead, e.g. `tasks=['assembleDebug']`. Will be removed in Nx 17."
},
"mode": {
"type": "string",
"description": "Specify your app's build variant",
"default": "debug",
"examples": ["debug", "release"],
"x-priority": "important"
},
"packager": {
"type": "boolean",
"description": "Launch packager while building",
"default": true
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"tasks": {
"type": "array",
"items": {
"type": "string"
},
"description": "Run custom Gradle tasks. By default it's \"assembleDebug\". Will override passed mode and variant arguments.",
"examples": [
"assembleDebug",
"assembleRelease",
"bundleDebug",
"bundleRelease",
"installDebug",
"installRelease"
]
},
"activeArchOnly": {
"type": "boolean",
"description": "Build native libraries only for the current device architecture for debug builds.",
"default": false
},
"extraParams": {
"type": "string",
"description": "Custom params passed to gradle build command"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select build type and flavour to use before running a build"
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true
},
"resetCache": {
"type": "boolean",
"description": "Resets metro cache.",
"default": false
} }
}, },
"required": [], "required": [],

View File

@ -0,0 +1,118 @@
import { ExecutorContext } from '@nrwl/devkit';
import { join } from 'path';
import { ChildProcess, fork } from 'child_process';
import { platform } from 'os';
import { ensureNodeModulesSymlink } from '../../utils/ensure-node-modules-symlink';
import {
displayNewlyAddedDepsMessage,
syncDeps,
} from '../sync-deps/sync-deps.impl';
import { podInstall } from '../../utils/pod-install-task';
import { ReactNativeBuildIosOptions } from './schema';
import { runCliStart } from '../start/start.impl';
import { getCliOptions } from '../../utils/get-cli-options';
export interface ReactNativeBuildIosOutput {
success: boolean;
}
let childProcess: ChildProcess;
export default async function* runIosExecutor(
options: ReactNativeBuildIosOptions,
context: ExecutorContext
): AsyncGenerator<ReactNativeBuildIosOutput> {
if (platform() !== 'darwin') {
throw new Error(`The run-ios build requires Mac to run`);
}
const projectRoot =
context.projectsConfigurations.projects[context.projectName].root;
ensureNodeModulesSymlink(context.root, projectRoot);
if (options.sync) {
displayNewlyAddedDepsMessage(
context.projectName,
await syncDeps(
context.projectName,
projectRoot,
context.root,
context.projectGraph
)
);
}
if (options.install) {
await podInstall(
join(context.root, projectRoot, 'ios'),
options.buildFolder
);
}
try {
const tasks = [runCliBuildIOS(context.root, projectRoot, options)];
if (options.packager && options.mode !== 'Release') {
tasks.push(
runCliStart(context.root, projectRoot, {
port: options.port,
resetCache: options.resetCache,
interactive: options.interactive,
})
);
}
await Promise.all(tasks);
yield { success: true };
} finally {
if (childProcess) {
childProcess.kill();
}
}
}
function runCliBuildIOS(
workspaceRoot: string,
projectRoot: string,
options: ReactNativeBuildIosOptions
) {
return new Promise((resolve, reject) => {
/**
* Call the react native cli with option `--no-packager`
* Not passing '--packager' due to cli will launch start command from the project root
*/
childProcess = fork(
join(workspaceRoot, './node_modules/react-native/cli.js'),
['run-ios', ...createBuildIOSOptions(options), '--no-packager'],
{
cwd: join(workspaceRoot, projectRoot),
env: { ...process.env, RCT_METRO_PORT: options.port.toString() },
}
);
// Ensure the child process is killed when the parent exits
process.on('exit', () => childProcess.kill());
process.on('SIGTERM', () => childProcess.kill());
childProcess.on('error', (err) => {
reject(err);
});
childProcess.on('exit', (code) => {
if (code === 0) {
resolve(code);
} else {
reject(code);
}
});
});
}
const nxOptions = ['sync', 'install', 'packager'];
const startOptions = ['port', 'resetCache'];
function createBuildIOSOptions(options: ReactNativeBuildIosOptions) {
return getCliOptions<ReactNativeBuildIosOptions>(
options,
[...nxOptions, ...startOptions],
['buildFolder']
);
}

View File

@ -0,0 +1,5 @@
import { convertNxExecutor } from '@nrwl/devkit';
import buildIosExecutor from './build-ios.impl';
export default convertNxExecutor(buildIosExecutor);

View File

@ -0,0 +1,22 @@
// options from https://github.com/react-native-community/cli/blob/main/packages/cli-platform-ios/src/commands/buildIOS/index.ts
import { ReactNativeStartOptions } from '../start/schema';
export interface ReactNativeBuildIosOptions extends ReactNativeStartOptions {
// react native options
simulator?: string;
mode: string; // default if 'Debug'
scheme?: string;
device?: string;
udid?: string;
verbose?: boolean;
port: number; // default is 8081
xcconfig?: string;
buildFolder?: string;
extraParams?: string;
// nx options
packager: boolean; // default is true
install: boolean; // default is true
sync: boolean; // default is true
}

View File

@ -0,0 +1,106 @@
{
"$schema": "http://json-schema.org/schema",
"version": 2,
"cli": "nx",
"title": "React Native Build iOS executor",
"description": "Build iOS app.",
"type": "object",
"presets": [
{
"name": "Build iOS for a simulator",
"keys": ["simulator"]
},
{
"name": "Build iOS for a device",
"keys": ["device"]
},
{
"name": "Build iOS for a device with udid",
"keys": ["udid"]
},
{
"name": "Run `pod install` before building iOS app",
"keys": ["install"]
}
],
"properties": {
"simulator": {
"type": "string",
"description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: \"iPhone 6 (10.0)\"",
"examples": [
"iPhone 14",
"iPhone 13",
"iPhone 12",
"iPhone 11",
"iPhone X"
],
"x-priority": "important"
},
"mode": {
"type": "string",
"description": "Explicitly set the scheme configuration to use",
"default": "Debug",
"examples": ["Debug", "Release"],
"x-priority": "important"
},
"schema": {
"type": "string",
"description": "Explicitly set Xcode scheme to use"
},
"device": {
"type": "string",
"description": "Explicitly set device to use by name. The value is not required if you have a single device connected."
},
"udid": {
"type": "string",
"description": "Explicitly set device to use by udid"
},
"verbose": {
"type": "boolean",
"description": "Do not use xcbeautify or xcpretty even if installed"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"xcconfig": {
"type": "string",
"description": "Explicitly set xcconfig to use"
},
"buildFolder": {
"type": "string",
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory",
"default": "./build"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select which scheme and configuration to use before running a build"
},
"extraParams": {
"type": "string",
"description": "Custom params that will be passed to xcodebuild command."
},
"install": {
"type": "boolean",
"description": "Runs `pod install` for native modules before building iOS app."
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true
},
"resetCache": {
"type": "boolean",
"description": "Resets metro cache.",
"default": false
},
"packager": {
"type": "boolean",
"description": "Launch packager while building",
"default": true
}
},
"required": [],
"examplesFile": "../../../docs/build-ios-examples.md"
}

View File

@ -7,6 +7,24 @@
"title": "Offline JS Bundle for React Native", "title": "Offline JS Bundle for React Native",
"description": "JS Bundle target options.", "description": "JS Bundle target options.",
"type": "object", "type": "object",
"presets": [
{
"name": "Bundle for a specific platform",
"keys": ["platform"]
},
{
"name": "Bundle a development build",
"keys": ["dev"]
},
{
"name": "Bundle to a specific output path",
"keys": ["bundleOutput"]
},
{
"name": "Bundle without global cache",
"keys": ["resetCache"]
}
],
"properties": { "properties": {
"entryFile": { "entryFile": {
"type": "string", "type": "string",
@ -65,7 +83,7 @@
}, },
"readGlobalCache": { "readGlobalCache": {
"type": "boolean", "type": "boolean",
"description": "Removes cached files.", "description": "Try to fetch transformed JS code from the global cache, if configured.",
"default": false "default": false
} }
}, },

View File

@ -0,0 +1,5 @@
import { convertNxExecutor } from '@nrwl/devkit';
import podInstall from './pod-install.impl';
export default convertNxExecutor(podInstall);

View File

@ -0,0 +1,21 @@
import { join } from 'path';
import { ExecutorContext } from '@nrwl/devkit';
import { runPodInstall } from '../../utils/pod-install-task';
import { ReactNativePodInstallOptions } from './schema';
export interface ReactNativePodInstallOutput {
success: boolean;
}
export default async function* podInstall(
options: ReactNativePodInstallOptions,
context: ExecutorContext
): AsyncGenerator<ReactNativePodInstallOutput> {
const projectRoot =
context.projectsConfigurations.projects[context.projectName].root;
const iosDirectory = join(context.root, projectRoot, 'ios');
await runPodInstall(iosDirectory, true, options.buildFolder)();
yield { success: true };
}

View File

@ -0,0 +1,3 @@
export interface ReactNativePodInstallOptions {
buildFolder: string;
}

View File

@ -0,0 +1,18 @@
{
"version": 2,
"outputCapture": "direct-nodejs",
"cli": "nx",
"$id": "NxReactNativePodInstall",
"$schema": "http://json-schema.org/schema",
"title": "Run Pod Install for React Native iOS Project",
"description": "Run `pod install` for React Native iOS Project.",
"type": "object",
"properties": {
"buildFolder": {
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory",
"type": "string",
"default": "./build"
}
},
"required": ["buildFolder"]
}

View File

@ -7,10 +7,10 @@ import {
displayNewlyAddedDepsMessage, displayNewlyAddedDepsMessage,
syncDeps, syncDeps,
} from '../sync-deps/sync-deps.impl'; } from '../sync-deps/sync-deps.impl';
import { chmodSync } from 'fs';
import { ReactNativeRunAndroidOptions } from './schema'; import { ReactNativeRunAndroidOptions } from './schema';
import { runCliStart } from '../start/start.impl'; import { runCliStart } from '../start/start.impl';
import { chmodAndroidGradlewFiles } from '../../utils/chmod-android-gradle-files'; import { chmodAndroidGradlewFiles } from '../../utils/chmod-android-gradle-files';
import { getCliOptions } from '../../utils/get-cli-options';
export interface ReactNativeRunAndroidOutput { export interface ReactNativeRunAndroidOutput {
success: boolean; success: boolean;
@ -97,31 +97,14 @@ function runCliRunAndroid(
}); });
} }
const nxOrStartOptions = [ const nxOptions = ['sync', 'packager'];
'sync', const startOptions = ['port', 'resetCache'];
'install', const deprecatedOptions = ['variant', 'jetifier'];
'packager',
'port',
'resetCache',
'interactive',
];
function createRunAndroidOptions(options) { function createRunAndroidOptions(options: ReactNativeRunAndroidOptions) {
return Object.keys(options).reduce((acc, k) => { return getCliOptions<ReactNativeRunAndroidOptions>(
const v = options[k]; options,
if (k === 'mainActivity') { [...nxOptions, ...startOptions, ...deprecatedOptions],
acc.push(`--main-activity`, v); ['appId', 'appIdSuffix']
} else if (k === 'jetifier') { );
if (!v) {
acc.push(`--no-jetifier`);
}
} else if (k === 'activeArchOnly') {
if (v) {
acc.push(`--active-arch-only`);
}
} else if (v && !nxOrStartOptions.includes(k)) {
acc.push(`--${k}`, v);
}
return acc;
}, []);
} }

View File

@ -1,17 +1,24 @@
// part of options from https://github.com/react-native-community/cli/blob/master/packages/platform-android/src/commands/runAndroid/index.ts#L314 import { ReactNativeBuildAndroidOptions } from '../build-android/schema';
export interface ReactNativeRunAndroidOptions { import { ReactNativeStartOptions } from '../start/schema';
// part of options from https://github.com/react-native-community/cli/blob/main/packages/cli-platform-android/src/commands/runAndroid/index.ts
export interface ReactNativeRunAndroidOptions
extends ReactNativeBuildAndroidOptions {
/**
* @deprecated use mode instead
*/
variant: string; variant: string;
/**
* @deprecated no longer supported in react native cli
* https://github.com/react-native-community/cli/commit/7c003f2b1d9d80ec5c167614ba533a004272c685
*/
jetifier: boolean;
// react native options
appId: string; appId: string;
appIdSuffix: string; appIdSuffix: string;
mainActiviy: string; mainActiviy: string;
deviceId: string; deviceId: string;
tasks?: string; listDevices?: boolean;
jetifier: boolean; binaryPath?: string;
sync: boolean;
port: number;
terminal?: string;
packager: boolean; // default is true
resetCache: boolean; // default is false
interactive: boolean; // default is true
activeArchOnly?: boolean;
} }

View File

@ -9,8 +9,16 @@
"type": "object", "type": "object",
"presets": [ "presets": [
{ {
"name": "Run Android without cache", "name": "Run Android for the current device architecture",
"keys": ["variant", "sync", "port", "packager", "resetCache"] "keys": ["activeArchOnly"]
},
{
"name": "Lists all available Android devices and simulators",
"keys": ["listDevices"]
},
{
"name": "Run Android without metro cache",
"keys": ["resetCache"]
} }
], ],
"properties": { "properties": {
@ -19,7 +27,12 @@
"description": "Specify your app's build variant (e.g. `debug`, `release`).", "description": "Specify your app's build variant (e.g. `debug`, `release`).",
"default": "debug", "default": "debug",
"examples": ["debug", "release"], "examples": ["debug", "release"],
"x-priority": "important" "x-deprecated": "Deprecated from @react-native-community/cli, use mode instead, e.g. mode=debug. Will be remove in Nx 17."
},
"jetifier": {
"type": "boolean",
"description": "Run Jetifier the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don't support AndroidX yet.",
"x-deprecated": "Deprecated from @react-native-community/cli. Will be remove in Nx 17."
}, },
"appId": { "appId": {
"type": "string", "type": "string",
@ -38,18 +51,25 @@
"type": "string", "type": "string",
"description": "Builds your app and starts it on a specific device/simulator with the given device id (listed by running `adb devices` on the command line)." "description": "Builds your app and starts it on a specific device/simulator with the given device id (listed by running `adb devices` on the command line)."
}, },
"tasks": { "listDevices": {
"type": "boolean",
"description": "Lists all available Android devices and simulators and let you choose one to run the app",
"default": false
},
"binaryPath": {
"type": "string", "type": "string",
"description": "Run custom Gradle tasks. If this argument is provided, then `--variant` option is ignored. Example: `yarn react-native run-android --tasks clean,installDebug`." "description": "Path relative to project root where pre-built .apk binary lives."
}, },
"jetifier": { "mode": {
"type": "boolean", "type": "string",
"description": "Run Jetifier the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don't support AndroidX yet.", "description": "Specify your app's build variant",
"default": true "default": "debug",
"examples": ["debug", "release"],
"x-priority": "important"
}, },
"sync": { "packager": {
"type": "boolean", "type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).", "description": "Launch packager while building",
"default": true "default": true
}, },
"port": { "port": {
@ -57,29 +77,44 @@
"description": "The port where the packager server is listening on.", "description": "The port where the packager server is listening on.",
"default": 8081 "default": 8081
}, },
"terminal": { "tasks": {
"type": "string", "type": "array",
"description": "Launches the Metro Bundler in a new window using the specified terminal path." "items": {
"type": "string"
},
"description": "Run custom Gradle tasks. By default it's \"assembleDebug\". Will override passed mode and variant arguments.",
"examples": [
"assembleDebug",
"assembleRelease",
"bundleDebug",
"bundleRelease",
"installDebug",
"installRelease"
]
}, },
"packager": { "activeArchOnly": {
"type": "boolean", "type": "boolean",
"description": "Starts the packager server.", "description": "Build native libraries only for the current device architecture for debug builds.",
"examples": ["x86_64", "arm64-v8a"],
"default": false
},
"extraParams": {
"type": "string",
"description": "Custom params passed to gradle build command"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select build type and flavour to use before running a build"
},
"sync": {
"type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true "default": true
}, },
"resetCache": { "resetCache": {
"type": "boolean", "type": "boolean",
"description": "Resets metro cache.", "description": "Resets metro cache.",
"default": false "default": false
},
"interactive": {
"type": "boolean",
"description": "Run packager server in interactive mode.",
"default": true
},
"activeArchOnly": {
"type": "boolean",
"description": "Builds only for the active architecture (e.g. x86_64, arm64-v8a).",
"default": false
} }
}, },
"examplesFile": "../../../docs/run-android-examples.md" "examplesFile": "../../../docs/run-android-examples.md"

View File

@ -1,4 +1,4 @@
import { ExecutorContext } from '@nrwl/devkit'; import { ExecutorContext, logger, names } from '@nrwl/devkit';
import { join } from 'path'; import { join } from 'path';
import { ChildProcess, fork } from 'child_process'; import { ChildProcess, fork } from 'child_process';
import { platform } from 'os'; import { platform } from 'os';
@ -11,6 +11,8 @@ import {
import { podInstall } from '../../utils/pod-install-task'; import { podInstall } from '../../utils/pod-install-task';
import { ReactNativeRunIosOptions } from './schema'; import { ReactNativeRunIosOptions } from './schema';
import { runCliStart } from '../start/start.impl'; import { runCliStart } from '../start/start.impl';
import { getCliOptions } from '../../utils/get-cli-options';
import { rmdirSync } from 'fs-extra';
export interface ReactNativeRunIosOutput { export interface ReactNativeRunIosOutput {
success: boolean; success: boolean;
@ -39,13 +41,17 @@ export default async function* runIosExecutor(
) )
); );
} }
if (options.install) { if (options.install) {
await podInstall(join(context.root, projectRoot, 'ios')); await podInstall(
join(context.root, projectRoot, 'ios'),
options.buildFolder
);
} }
try { try {
const tasks = [runCliRunIOS(context.root, projectRoot, options)]; const tasks = [runCliRunIOS(context.root, projectRoot, options)];
if (options.packager && options.xcodeConfiguration !== 'Release') { if (options.packager && options.mode !== 'Release') {
tasks.push( tasks.push(
runCliStart(context.root, projectRoot, { runCliStart(context.root, projectRoot, {
port: options.port, port: options.port,
@ -101,23 +107,14 @@ function runCliRunIOS(
}); });
} }
const nxOrStartOptions = [ const nxOptions = ['sync', 'install', 'packager'];
'sync', const startOptions = ['port', 'resetCache'];
'install', const deprecatedOptions = ['xcodeConfiguration'];
'packager',
'port',
'resetCache',
'interactive',
];
function createRunIOSOptions(options) { function createRunIOSOptions(options: ReactNativeRunIosOptions) {
return Object.keys(options).reduce((acc, k) => { return getCliOptions<ReactNativeRunIosOptions>(
const v = options[k]; options,
if (k === 'xcodeConfiguration') { [...nxOptions, ...startOptions, ...deprecatedOptions],
acc.push('--configuration', v); ['buildFolder']
} else if (v && !nxOrStartOptions.includes(k)) { );
acc.push(`--${k}`, options[k]);
}
return acc;
}, []);
} }

View File

@ -1,14 +1,12 @@
// part of options form https://github.com/react-native-community/cli/blob/master/packages/platform-ios/src/commands/runIOS/index.ts#L541 import { ReactNativeBuildIosOptions } from '../build-ios/schema';
export interface ReactNativeRunIosOptions { import { ReactNativeStartOptions } from '../start/schema';
xcodeConfiguration: string;
port: number; // part of options form https://github.com/react-native-community/cli/blob/main/packages/cli-platform-ios/src/commands/runIOS/index.ts
scheme: string; export interface ReactNativeRunIosOptions extends ReactNativeBuildIosOptions {
simulator: string; /**
device: string; * @deprecated use mode instead, will be removed in nx 17.
packager: boolean; // default is true */
install?: boolean; xcodeConfiguration?: string;
sync?: boolean;
terminal?: string; binaryPath?: string;
resetCache: boolean; // default is false
interactive: boolean; // default is true
} }

View File

@ -9,15 +9,20 @@
"type": "object", "type": "object",
"presets": [ "presets": [
{ {
"name": "Run iOS without cache", "name": "Run iOS on a simulator",
"keys": [ "keys": ["simulator"]
"xcodeConfiguration", },
"install", {
"sync", "name": "Run iOS on a device",
"port", "keys": ["device"]
"packager", },
"resetCache" {
] "name": "Run iOS on a device with udid",
"keys": ["udid"]
},
{
"name": "Run `pod install` before building iOS app",
"keys": ["install"]
} }
], ],
"properties": { "properties": {
@ -26,16 +31,11 @@
"description": "Explicitly set the Xcode configuration to use.", "description": "Explicitly set the Xcode configuration to use.",
"default": "Debug", "default": "Debug",
"examples": ["Debug", "Release"], "examples": ["Debug", "Release"],
"x-priority": "important" "x-deprecated": "Use `mode` instead. Deprecated from @react-native-community/cli. Will be removed in Nx 17."
},
"scheme": {
"type": "string",
"description": "Explicitly set the Xcode scheme to use."
}, },
"simulator": { "simulator": {
"type": "string", "type": "string",
"description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: `iPhone X (12.1)`.", "description": "Explicitly set simulator to use. Optionally include iOS version between parenthesis at the end to match an exact version: \"iPhone 6 (10.0)\"",
"default": "iPhone 14",
"examples": [ "examples": [
"iPhone 14", "iPhone 14",
"iPhone 13", "iPhone 13",
@ -45,10 +45,50 @@
], ],
"x-priority": "important" "x-priority": "important"
}, },
"mode": {
"type": "string",
"description": "Explicitly set the scheme configuration to use",
"default": "Debug",
"examples": ["Debug", "Release"],
"x-priority": "important"
},
"schema": {
"type": "string",
"description": "Explicitly set Xcode scheme to use"
},
"device": { "device": {
"type": "string", "type": "string",
"description": "Explicitly set device to use by name. The value is not required if you have a single device connected.", "description": "Explicitly set device to use by name. The value is not required if you have a single device connected."
"x-priority": "important" },
"udid": {
"type": "string",
"description": "Explicitly set device to use by udid"
},
"verbose": {
"type": "boolean",
"description": "Do not use xcbeautify or xcpretty even if installed"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"xcconfig": {
"type": "string",
"description": "Explicitly set xcconfig to use"
},
"buildFolder": {
"type": "string",
"description": "Location for iOS build artifacts. Corresponds to Xcode's \"-derivedDataPath\". Relative to ios directory.",
"buildFolder": "./build"
},
"interactive": {
"type": "boolean",
"description": "Explicitly select which scheme and configuration to use before running a build"
},
"extraParams": {
"type": "string",
"description": "Custom params that will be passed to xcodebuild command."
}, },
"install": { "install": {
"type": "boolean", "type": "boolean",
@ -57,22 +97,7 @@
}, },
"sync": { "sync": {
"type": "boolean", "type": "boolean",
"description": "Syncs npm dependencies to `package.json` (for React Native autolink). Always true when `--install` is used.", "description": "Syncs npm dependencies to `package.json` (for React Native autolink).",
"default": true,
"x-priority": "internal"
},
"port": {
"type": "number",
"description": "The port where the packager server is listening on.",
"default": 8081
},
"terminal": {
"type": "string",
"description": "Launches the Metro Bundler in a new window using the specified terminal path."
},
"packager": {
"type": "boolean",
"description": "Starts the packager server.",
"default": true "default": true
}, },
"resetCache": { "resetCache": {
@ -80,10 +105,14 @@
"description": "Resets metro cache.", "description": "Resets metro cache.",
"default": false "default": false
}, },
"interactive": { "packager": {
"type": "boolean", "type": "boolean",
"description": "Run packager server in interactive mode.", "description": "Launch packager while building",
"default": true "default": true
},
"binaryPath": {
"type": "string",
"description": "Path relative to project root where pre-built .app binary lives."
} }
}, },
"examplesFile": "../../../docs/run-ios-examples.md" "examplesFile": "../../../docs/run-ios-examples.md"

View File

@ -1,3 +1,5 @@
// options from https://github.com/react-native-community/cli/blob/main/packages/cli-plugin-metro/src/commands/start/index.ts
export interface ReactNativeStartOptions { export interface ReactNativeStartOptions {
port: number; port: number;
resetCache: boolean; // default is false resetCache: boolean; // default is false

View File

@ -44,6 +44,7 @@ function getTargets(options: NormalizedSchema) {
architect['bundle-ios'] = { architect['bundle-ios'] = {
executor: '@nrwl/react-native:bundle', executor: '@nrwl/react-native:bundle',
outputs: ['{options.bundleOutput}'],
options: { options: {
entryFile: options.entryFile, entryFile: options.entryFile,
platform: 'ios', platform: 'ios',
@ -65,8 +66,20 @@ function getTargets(options: NormalizedSchema) {
options: {}, options: {},
}; };
architect['build-ios'] = {
executor: '@nrwl/react-native:build-ios',
outputs: ['{projectRoot}/ios/build/Build'],
options: {},
};
architect['pod-install'] = {
executor: '@nrwl/react-native:pod-install',
options: {},
};
architect['bundle-android'] = { architect['bundle-android'] = {
executor: '@nrwl/react-native:bundle', executor: '@nrwl/react-native:bundle',
outputs: ['{options.bundleOutput}'],
options: { options: {
entryFile: options.entryFile, entryFile: options.entryFile,
platform: 'android', platform: 'android',

View File

@ -0,0 +1,36 @@
import { addProjectConfiguration, getProjects, Tree } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import update from './add-build-ios-target';
describe('add-build-ios-target', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'product', {
root: 'apps/product',
sourceRoot: 'apps/product/src',
targets: {
start: {
executor: '@nrwl/react-native:start',
},
},
});
});
it(`should update project.json with target build-ios and pod-install`, async () => {
await update(tree);
getProjects(tree).forEach((project) => {
expect(project.targets['build-ios']).toEqual({
executor: '@nrwl/react-native:build-ios',
outputs: ['{projectRoot}/ios/build/Build'],
options: {},
});
expect(project.targets['pod-install']).toEqual({
executor: '@nrwl/react-native:pod-install',
options: {},
});
});
});
});

View File

@ -0,0 +1,35 @@
import {
Tree,
formatFiles,
getProjects,
updateProjectConfiguration,
} from '@nrwl/devkit';
/**
* Add build-ios target for react-native
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const [name, config] of projects.entries()) {
if (config.targets?.['start']?.executor === '@nrwl/react-native:start') {
if (!config.targets['build-ios']) {
config.targets['build-ios'] = {
executor: '@nrwl/react-native:build-ios',
outputs: ['{projectRoot}/ios/build/Build'],
options: {},
};
}
if (!config.targets['pod-install']) {
config.targets['pod-install'] = {
executor: '@nrwl/react-native:pod-install',
options: {},
};
}
}
updateProjectConfiguration(tree, name, config);
}
await formatFiles(tree);
}

View File

@ -0,0 +1,30 @@
import { names } from '@nrwl/devkit';
/**
* This function normalizes the options passed in to the Nx and returns an array of strings that can be passed to the React Native CLI.
* @param options Nx options
* @param optionKeysToIgnore Keys to ignore
* @param optionKeysInCamelName Keys that are in camel case. Most react native cli options are in kebab case, but some are in camel case.
* @returns options that can be passed to the React Native CLI
*/
export function getCliOptions<T>(
options: T,
optionKeysToIgnore: string[] = [],
optionKeysInCamelName: string[] = []
): string[] {
return Object.keys(options).reduce((acc, optionKey) => {
const optionValue = options[optionKey];
if (!optionKeysToIgnore.includes(optionKey)) {
const cliKey = optionKeysInCamelName.includes(optionKey)
? names(optionKey).propertyName
: names(optionKey).fileName; // cli uses kebab case as default
if (typeof optionValue === 'boolean' && optionValue) {
// no need to pass in the value when it is true, just the flag name
acc.push(`--${cliKey}`);
} else {
acc.push(`--${cliKey}`, optionValue);
}
}
return acc;
}, []);
}

View File

@ -2,6 +2,8 @@ import { execSync } from 'child_process';
import { platform } from 'os'; import { platform } from 'os';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import { GeneratorCallback, logger } from '@nrwl/devkit'; import { GeneratorCallback, logger } from '@nrwl/devkit';
import { rmdirSync, existsSync } from 'fs-extra';
import { join } from 'path';
const podInstallErrorMessage = ` const podInstallErrorMessage = `
Running ${chalk.bold('pod install')} failed, see above. Running ${chalk.bold('pod install')} failed, see above.
@ -21,7 +23,8 @@ ${chalk.bold('sudo xcode-select --switch /Applications/Xcode.app')}
*/ */
export function runPodInstall( export function runPodInstall(
iosDirectory: string, iosDirectory: string,
install: boolean = true install: boolean = true,
buildFolder?: string
): GeneratorCallback { ): GeneratorCallback {
return () => { return () => {
if (platform() !== 'darwin') { if (platform() !== 'darwin') {
@ -36,17 +39,27 @@ export function runPodInstall(
logger.info(`Running \`pod install\` from "${iosDirectory}"`); logger.info(`Running \`pod install\` from "${iosDirectory}"`);
return podInstall(iosDirectory); return podInstall(iosDirectory, buildFolder);
}; };
} }
export function podInstall(iosDirectory: string): Promise<void> { export function podInstall(
iosDirectory: string,
buildFolder?: string
): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const result = execSync('pod install', { const result = execSync('pod install', {
cwd: iosDirectory, cwd: iosDirectory,
}); });
logger.info(result.toString()); logger.info(result.toString());
if (result.toString().includes('Pod installation complete')) { if (result.toString().includes('Pod installation complete')) {
// Remove build folder after pod install
if (buildFolder) {
buildFolder = join(iosDirectory, buildFolder);
if (existsSync(buildFolder)) {
rmdirSync(buildFolder, { recursive: true });
}
}
resolve(); resolve();
} else { } else {
reject(new Error(podInstallErrorMessage)); reject(new Error(podInstallErrorMessage));

View File

@ -3,13 +3,13 @@ import * as chalk from 'chalk';
import { GeneratorCallback, logger } from '@nrwl/devkit'; import { GeneratorCallback, logger } from '@nrwl/devkit';
export function runSymlink( export function runSymlink(
worksapceRoot: string, workspaceRoot: string,
projectRoot: string projectRoot: string
): GeneratorCallback { ): GeneratorCallback {
return () => { return () => {
logger.info(`creating symlinks for ${chalk.bold(projectRoot)}`); logger.info(`creating symlinks for ${chalk.bold(projectRoot)}`);
try { try {
ensureNodeModulesSymlink(worksapceRoot, projectRoot); ensureNodeModulesSymlink(workspaceRoot, projectRoot);
} catch { } catch {
throw new Error( throw new Error(
`Failed to create symlinks for ${chalk.bold(projectRoot)}` `Failed to create symlinks for ${chalk.bold(projectRoot)}`

View File

@ -7,8 +7,8 @@ export const typesNodeVersion = '18.14.4';
export const metroVersion = '0.74.1'; export const metroVersion = '0.74.1';
export const reactNativeCommunityCli = '10.2.0'; export const reactNativeCommunityCli = '10.2.1';
export const reactNativeCommunityCliIos = '10.2.0'; export const reactNativeCommunityCliIos = '10.2.1';
export const reactNativeCommunityCliAndroid = '10.2.0'; export const reactNativeCommunityCliAndroid = '10.2.0';
export const reactVersion = '18.2.0'; export const reactVersion = '18.2.0';