@react-native/core-cli-utils 0.87.0-nightly-20260519-58cd1bf58 → 0.87.0-nightly-20260528-eaf770433
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +6 -0
- package/README.md +11 -48
- package/package.json +8 -23
- package/src/index.js +21 -0
- package/src/private/android.js +129 -0
- package/src/private/app.js +247 -0
- package/src/private/apple.js +239 -0
- package/src/private/clean.js +227 -0
- package/{dist/private/types.js.flow → src/private/types.js} +2 -0
- package/src/private/utils.js +81 -0
- package/{dist/public/version.js.flow → src/public/version.js} +20 -15
- package/dist/index.d.ts +0 -26
- package/dist/index.js +0 -48
- package/dist/index.js.flow +0 -25
- package/dist/private/android.d.ts +0 -29
- package/dist/private/android.js +0 -74
- package/dist/private/android.js.flow +0 -41
- package/dist/private/app.d.ts +0 -37
- package/dist/private/app.js +0 -172
- package/dist/private/app.js.flow +0 -71
- package/dist/private/apple.d.ts +0 -56
- package/dist/private/apple.js +0 -179
- package/dist/private/apple.js.flow +0 -75
- package/dist/private/clean.d.ts +0 -59
- package/dist/private/clean.js +0 -140
- package/dist/private/clean.js.flow +0 -76
- package/dist/private/types.d.ts +0 -15
- package/dist/private/types.js +0 -1
- package/dist/private/utils.d.ts +0 -30
- package/dist/private/utils.js +0 -51
- package/dist/private/utils.js.flow +0 -37
- package/dist/public/version.d.ts +0 -33
- package/dist/public/version.js +0 -27
package/.eslintrc.json
ADDED
package/README.md
CHANGED
|
@@ -1,55 +1,18 @@
|
|
|
1
1
|
# @react-native/core-cli-utils
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A reference implementation of React Native CLI tooling. This package provides composable, ordered `Task` objects for common CLI operations including Android Gradle builds, iOS Xcode/CocoaPods workflows, Metro bundling with Hermes support, and cache cleaning.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This is not published to npm. Framework authors can use this code as a starting point for their own CLI tooling, but should not depend on it as a versioned API.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Modules
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
- **`android`** — Gradle-based Android build tasks (assemble, build, install)
|
|
10
|
+
- **`apple`** — Xcode/CocoaPods-based iOS tasks (bootstrap, build, install)
|
|
11
|
+
- **`app`** — Metro bundler tasks (watch mode, bundle mode, Hermes bytecode compilation)
|
|
12
|
+
- **`clean`** — Cache-cleaning tasks (Android/Gradle, Metro, npm, Watchman, Yarn, CocoaPods)
|
|
13
|
+
- **`version`** — Semver version requirements for platform toolchains (Android NDK/SDK, Xcode, Node, etc.)
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
## Consumers
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const log = debug('fancy-framework:android');
|
|
19
|
-
|
|
20
|
-
android
|
|
21
|
-
.command('clean')
|
|
22
|
-
.description(cli.clean.android)
|
|
23
|
-
.action(async () => {
|
|
24
|
-
const log = debug('fancy-framework:android:clean');
|
|
25
|
-
log(`🧹 let me clean your Android caches`);
|
|
26
|
-
// Add other caches your framework needs besides the normal React Native caches
|
|
27
|
-
// here.
|
|
28
|
-
for (const task of tasks) {
|
|
29
|
-
try {
|
|
30
|
-
log(`\t ${task.label}`);
|
|
31
|
-
// See: https://github.com/sindresorhus/execa#lines
|
|
32
|
-
const {stdout} = await task.action({ lines: true })
|
|
33
|
-
log(stdout.join('\n\tGradle: '));
|
|
34
|
-
} catch (e) {
|
|
35
|
-
log(`\t ⚠️ whoops: ${e.message}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
And you'd be using it like this:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
$ ./fancy-framework android clean
|
|
45
|
-
🧹 let me clean your Android caches
|
|
46
|
-
Gradle: // a bunch of gradle output
|
|
47
|
-
Gradle: ....
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Features
|
|
51
|
-
- `"@react-native/core-cli-utils/version.js"` contains the platform and tooling version requirements for react-native.
|
|
52
|
-
|
|
53
|
-
## Contributing
|
|
54
|
-
|
|
55
|
-
Changes to this package can be made locally and linked against your app. Please see the [Contributing guide](https://reactnative.dev/contributing/overview#contributing-code).
|
|
17
|
+
- [`private/helloworld/`](../helloworld/) — the primary consumer, using Android, iOS, and Metro modules
|
|
18
|
+
- [`packages/rn-tester/`](../../packages/rn-tester/) — uses iOS bootstrap for CocoaPods setup
|
package/package.json
CHANGED
|
@@ -1,34 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native/core-cli-utils",
|
|
3
|
-
"version": "0.87.0-nightly-
|
|
4
|
-
"description": "React Native CLI
|
|
3
|
+
"version": "0.87.0-nightly-20260528-eaf770433",
|
|
4
|
+
"description": "Reference implementation of React Native CLI tooling",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
"cli-utils",
|
|
8
|
-
"react-native"
|
|
9
|
-
],
|
|
10
|
-
"homepage": "https://github.com/facebook/react-native/tree/HEAD/packages/core-cli-utils#readme",
|
|
11
|
-
"bugs": "https://github.com/facebook/react-native/issues",
|
|
12
|
-
"repository": {
|
|
13
|
-
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/facebook/react-native.git",
|
|
15
|
-
"directory": "packages/core-cli-utils"
|
|
16
|
-
},
|
|
17
|
-
"main": "./dist/index.js",
|
|
6
|
+
"main": "./src/index.js",
|
|
18
7
|
"exports": {
|
|
19
|
-
".": "./
|
|
8
|
+
".": "./src/index.js",
|
|
20
9
|
"./package.json": "./package.json",
|
|
21
|
-
"./version.js": "./
|
|
10
|
+
"./version.js": "./src/public/version.js"
|
|
22
11
|
},
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
],
|
|
26
|
-
"scripts": {
|
|
27
|
-
"prepack": "node ../../scripts/build/prepack.js"
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"metro-babel-register": "^0.84.3"
|
|
28
14
|
},
|
|
29
|
-
"dependencies": {},
|
|
30
15
|
"devDependencies": {},
|
|
31
16
|
"engines": {
|
|
32
|
-
"node": "^
|
|
17
|
+
"node": "^22.13.0 || ^24.3.0 || >= 26.0.0"
|
|
33
18
|
}
|
|
34
19
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*::
|
|
12
|
+
export type {Task} from './private/types';
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const {tasks: android} = require('./private/android.js');
|
|
16
|
+
const {tasks: app} = require('./private/app.js');
|
|
17
|
+
const {tasks: apple} = require('./private/apple.js');
|
|
18
|
+
const {tasks: clean} = require('./private/clean.js');
|
|
19
|
+
const version = require('./public/version.js');
|
|
20
|
+
|
|
21
|
+
module.exports = {android, app, apple, clean, version};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*::
|
|
12
|
+
import type {Task} from './types';
|
|
13
|
+
import type {ExecaPromise} from 'execa';
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const {isWindows, task} = require('./utils');
|
|
17
|
+
const execa = require('execa');
|
|
18
|
+
|
|
19
|
+
/*::
|
|
20
|
+
type AndroidBuildMode = 'Debug' | 'Release';
|
|
21
|
+
|
|
22
|
+
type Path = string;
|
|
23
|
+
type Args = ReadonlyArray<string>;
|
|
24
|
+
|
|
25
|
+
type Config = {
|
|
26
|
+
cwd: Path,
|
|
27
|
+
hermes?: boolean,
|
|
28
|
+
mode: AndroidBuildMode,
|
|
29
|
+
name: string,
|
|
30
|
+
newArchitecture?: boolean,
|
|
31
|
+
sdk?: Path,
|
|
32
|
+
};
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
function gradle(
|
|
36
|
+
taskName /*: string */,
|
|
37
|
+
args /*: Args */,
|
|
38
|
+
options /*: {cwd: string, env?: {[k: string]: string | void}} */,
|
|
39
|
+
) /*: ExecaPromise */ {
|
|
40
|
+
const gradlew = isWindows ? 'gradlew.bat' : './gradlew';
|
|
41
|
+
return execa(gradlew, [taskName, ...args], {
|
|
42
|
+
cwd: options.cwd,
|
|
43
|
+
env: options.env,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function androidSdkPath(sdk /*: ?string */) /*: string */ {
|
|
48
|
+
return sdk ?? process.env.ANDROID_HOME ?? process.env.ANDROID_SDK ?? '';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function boolToStr(value /*: boolean */) /*: string */ {
|
|
52
|
+
return value ? 'true' : 'false';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const FIRST = 1;
|
|
56
|
+
|
|
57
|
+
//
|
|
58
|
+
// Android Tasks
|
|
59
|
+
//
|
|
60
|
+
/*::
|
|
61
|
+
type AndroidTasks = {
|
|
62
|
+
assemble: (...gradleArgs: Args) => {
|
|
63
|
+
run: Task<ExecaPromise>,
|
|
64
|
+
},
|
|
65
|
+
build: (...gradleArgs: Args) => {
|
|
66
|
+
run: Task<ExecaPromise>,
|
|
67
|
+
},
|
|
68
|
+
install: (...gradleArgs: Args) => {
|
|
69
|
+
run: Task<ExecaPromise>,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
const tasks = (config /*: Config */) /*: AndroidTasks */ => ({
|
|
75
|
+
assemble: (...gradleArgs /*: Args */) => ({
|
|
76
|
+
run: task(FIRST, 'Assemble Android App', () => {
|
|
77
|
+
const args = [];
|
|
78
|
+
if (config.hermes != null) {
|
|
79
|
+
args.push(`-PhermesEnabled=${boolToStr(config.hermes)}`);
|
|
80
|
+
}
|
|
81
|
+
if (config.newArchitecture != null) {
|
|
82
|
+
args.push(`-PnewArchEnabled=${boolToStr(config.newArchitecture)}`);
|
|
83
|
+
}
|
|
84
|
+
args.push(...gradleArgs);
|
|
85
|
+
return gradle(`${config.name}:assemble${config.mode}`, gradleArgs, {
|
|
86
|
+
cwd: config.cwd,
|
|
87
|
+
env: {ANDROID_HOME: androidSdkPath(config.sdk)},
|
|
88
|
+
});
|
|
89
|
+
}),
|
|
90
|
+
}),
|
|
91
|
+
build: (...gradleArgs /*: Args */) => ({
|
|
92
|
+
run: task(FIRST, 'Assembles and tests Android App', () => {
|
|
93
|
+
const args = [];
|
|
94
|
+
if (config.hermes != null) {
|
|
95
|
+
args.push(`-PhermesEnabled=${boolToStr(config.hermes)}`);
|
|
96
|
+
}
|
|
97
|
+
if (config.newArchitecture != null) {
|
|
98
|
+
args.push(`-PnewArchEnabled=${boolToStr(config.newArchitecture)}`);
|
|
99
|
+
}
|
|
100
|
+
args.push(...gradleArgs);
|
|
101
|
+
return gradle(`${config.name}:bundle${config.mode}`, args, {
|
|
102
|
+
cwd: config.cwd,
|
|
103
|
+
env: {ANDROID_HOME: androidSdkPath(config.sdk)},
|
|
104
|
+
});
|
|
105
|
+
}),
|
|
106
|
+
}),
|
|
107
|
+
/**
|
|
108
|
+
* Useful extra gradle arguments:
|
|
109
|
+
*
|
|
110
|
+
*
|
|
111
|
+
* -PreactNativeDevServerPort=8081 sets the port for the installed app to point towards a Metro
|
|
112
|
+
* server on (for example) 8081.
|
|
113
|
+
*/
|
|
114
|
+
install: (...gradleArgs /*: Args */) => ({
|
|
115
|
+
run: task(FIRST, 'Installs the assembled Android App', () =>
|
|
116
|
+
gradle(`${config.name}:install${config.mode}`, gradleArgs, {
|
|
117
|
+
cwd: config.cwd,
|
|
118
|
+
env: {ANDROID_HOME: androidSdkPath(config.sdk)},
|
|
119
|
+
}),
|
|
120
|
+
),
|
|
121
|
+
}),
|
|
122
|
+
|
|
123
|
+
// We are not supporting launching the app and setting up the tunnel for metro <-> app, this is
|
|
124
|
+
// a framework concern. For an example of how one could do this, please look at the community
|
|
125
|
+
// CLI's code:
|
|
126
|
+
// https://github.com/react-native-community/cli/blob/54d48a4e08a1aef334ae6168788e0157a666b4f5/packages/cli-platform-android/src/commands/runAndroid/index.ts#L272C1-L290C2
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
module.exports = {tasks};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/*::
|
|
12
|
+
import type {Task} from './types';
|
|
13
|
+
import type {ExecaPromise} from 'execa';
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const {task} = require('./utils');
|
|
17
|
+
const debug = require('debug');
|
|
18
|
+
const execa = require('execa');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
const log = debug('core-cli-utils');
|
|
23
|
+
|
|
24
|
+
/*::
|
|
25
|
+
type BundlerOptions = {
|
|
26
|
+
// Metro's config: https://metrobundler.dev/docs/configuration/
|
|
27
|
+
config?: string,
|
|
28
|
+
// Typically index.{ios,android}.js
|
|
29
|
+
entryFile: string,
|
|
30
|
+
+platform: 'ios' | 'android' | string,
|
|
31
|
+
dev: boolean,
|
|
32
|
+
// Metro built main bundle
|
|
33
|
+
outputJsBundle: string,
|
|
34
|
+
minify: boolean,
|
|
35
|
+
optimize: boolean,
|
|
36
|
+
// Generate a source map file
|
|
37
|
+
outputSourceMap: string,
|
|
38
|
+
// Where to pass the final bundle. Typically this is the App's resource
|
|
39
|
+
// folder, however this is app specific. React Native will need to know where
|
|
40
|
+
// this is to bootstrap your application. See:
|
|
41
|
+
// - Android: https://reactnative.dev/docs/integration-with-existing-apps?language=kotlin#creating-a-release-build-in-android-studio
|
|
42
|
+
// - iOS: https://reactnative.dev/docs/integration-with-existing-apps?language=swift#2-event-handler
|
|
43
|
+
outputBundle: string,
|
|
44
|
+
cwd: string,
|
|
45
|
+
|
|
46
|
+
jsvm: 'hermes' | 'jsc',
|
|
47
|
+
hermes?: HermesConfig,
|
|
48
|
+
|
|
49
|
+
...Bundler,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type HermesConfig = {
|
|
53
|
+
// Path where hermes is is installed
|
|
54
|
+
// iOS: Pods/hermes-engine
|
|
55
|
+
path: string,
|
|
56
|
+
// iOS: <hermes.path>/destroot/bin/hermesc
|
|
57
|
+
hermesc: string,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type BundlerWatch = {
|
|
61
|
+
+mode: 'watch',
|
|
62
|
+
callback?: (metro: ExecaPromise) => void,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type BundlerBuild = {
|
|
66
|
+
+mode: 'bundle',
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
type Bundler = BundlerWatch | BundlerBuild;
|
|
70
|
+
|
|
71
|
+
type Bundle = {
|
|
72
|
+
validate?: Task<void>,
|
|
73
|
+
javascript: Task<ExecaPromise>,
|
|
74
|
+
sourcemap?: Task<void>,
|
|
75
|
+
validateHermesc?: Task<ExecaPromise>,
|
|
76
|
+
convert?: Task<ExecaPromise>,
|
|
77
|
+
compose?: Task<ExecaPromise>,
|
|
78
|
+
};
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
const FIRST = 1,
|
|
82
|
+
SECOND = 2,
|
|
83
|
+
THIRD = 3,
|
|
84
|
+
FOURTH = 4;
|
|
85
|
+
|
|
86
|
+
function getNodePackagePath(packageName /*: string */) /*: string */ {
|
|
87
|
+
// $FlowFixMe[prop-missing] type definition is incomplete
|
|
88
|
+
return require.resolve(packageName, {cwd: [process.cwd(), ...module.paths]});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function metro(...args /*: ReadonlyArray<string> */) /*: ExecaPromise */ {
|
|
92
|
+
log(`🚇 metro ${args.join(' ')} `);
|
|
93
|
+
return execa('npx', ['--offline', 'metro', ...args]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const tasks = {
|
|
97
|
+
bundle: (
|
|
98
|
+
options /*: BundlerOptions */,
|
|
99
|
+
...args /*: ReadonlyArray<string> */
|
|
100
|
+
) /*: Bundle */ => {
|
|
101
|
+
const steps /*: Bundle */ = {
|
|
102
|
+
/* eslint-disable sort-keys */
|
|
103
|
+
validate: task(FIRST, 'Check if Metro is available', () => {
|
|
104
|
+
try {
|
|
105
|
+
require('metro');
|
|
106
|
+
} catch {
|
|
107
|
+
throw new Error('Metro is not available');
|
|
108
|
+
}
|
|
109
|
+
}),
|
|
110
|
+
javascript: task(SECOND, 'Metro watching for changes', () =>
|
|
111
|
+
metro('serve', ...args),
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return options.mode === 'bundle'
|
|
116
|
+
? // $FlowFixMe[unsafe-object-assign]
|
|
117
|
+
Object.assign(steps, bundleApp(options, ...args))
|
|
118
|
+
: steps;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const bundleApp = (
|
|
123
|
+
options /*: BundlerOptions */,
|
|
124
|
+
...metroArgs /*: ReadonlyArray<string> */
|
|
125
|
+
) => {
|
|
126
|
+
if (options.outputJsBundle === options.outputBundle) {
|
|
127
|
+
throw new Error('outputJsBundle and outputBundle cannot be the same.');
|
|
128
|
+
}
|
|
129
|
+
let output =
|
|
130
|
+
options.jsvm === 'hermes' ? options.outputJsBundle : options.outputBundle;
|
|
131
|
+
|
|
132
|
+
if (output === options.outputJsBundle && !output.endsWith('.js')) {
|
|
133
|
+
log(
|
|
134
|
+
`Appending .js to outputBundle (because metro cli does it if it's missing): ${output}`,
|
|
135
|
+
);
|
|
136
|
+
output += '.js';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const isSourceMaps = options.outputSourceMap != null;
|
|
140
|
+
const bundle /*: Bundle */ = {
|
|
141
|
+
javascript: task(SECOND, 'Metro generating an .jsbundle', () => {
|
|
142
|
+
const args = [
|
|
143
|
+
'--platform',
|
|
144
|
+
options.platform,
|
|
145
|
+
'--dev',
|
|
146
|
+
options.dev ? 'true' : 'false',
|
|
147
|
+
'--reset-cache',
|
|
148
|
+
'--out',
|
|
149
|
+
output,
|
|
150
|
+
];
|
|
151
|
+
if (options.jsvm === 'hermes' && !options.dev) {
|
|
152
|
+
args.push('--minify', 'false');
|
|
153
|
+
} else {
|
|
154
|
+
args.push('--minify', options.minify ? 'true' : 'false');
|
|
155
|
+
}
|
|
156
|
+
if (isSourceMaps) {
|
|
157
|
+
args.push('--source-map');
|
|
158
|
+
}
|
|
159
|
+
return metro('build', options.entryFile, ...args, ...metroArgs);
|
|
160
|
+
}),
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
if (options.jsvm === 'jsc') {
|
|
164
|
+
return bundle;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (options.hermes?.path == null || options.hermes?.hermesc == null) {
|
|
168
|
+
throw new Error('If jsvm == "hermes", hermes config must be provided.');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const hermes /*: HermesConfig */ = options.hermes;
|
|
172
|
+
|
|
173
|
+
const isHermesInstalled /*: boolean */ = fs.existsSync(hermes.path);
|
|
174
|
+
if (!isHermesInstalled) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
'Hermes Pod must be installed before bundling.\n' +
|
|
177
|
+
'Did you forget to bootstrap?',
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const hermesc /*: string */ = path.join(hermes.path, hermes.hermesc);
|
|
182
|
+
|
|
183
|
+
let composeSourceMaps;
|
|
184
|
+
if (isSourceMaps) {
|
|
185
|
+
bundle.sourcemap = task(
|
|
186
|
+
FIRST,
|
|
187
|
+
'Check if SourceMap script available',
|
|
188
|
+
() => {
|
|
189
|
+
composeSourceMaps = getNodePackagePath(
|
|
190
|
+
'react-native/scripts/compose-source-maps.js',
|
|
191
|
+
);
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
bundle.validateHermesc = task(FIRST, 'Check if Hermesc is available', () =>
|
|
197
|
+
execa(hermesc, ['--version']),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
bundle.convert = task(
|
|
201
|
+
THIRD,
|
|
202
|
+
'Hermesc converting .jsbundle → bytecode',
|
|
203
|
+
() => {
|
|
204
|
+
const args = [
|
|
205
|
+
'-emit-binary',
|
|
206
|
+
'-max-diagnostic-width=80',
|
|
207
|
+
options.dev === true ? '-Og' : '-O',
|
|
208
|
+
];
|
|
209
|
+
if (isSourceMaps) {
|
|
210
|
+
args.push('-output-source-map');
|
|
211
|
+
}
|
|
212
|
+
args.push(`-out=${options.outputBundle}`, output);
|
|
213
|
+
return execa(hermesc, args, {cwd: options.cwd});
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
bundle.compose = task(FOURTH, 'Compose Hermes and Metro source maps', () => {
|
|
218
|
+
if (composeSourceMaps == null) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
'Unable to find the compose-source-map.js script in react-native',
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
const metroSourceMap = output.replace(/(\.js)?$/, '.map');
|
|
224
|
+
const hermesSourceMap = options.outputBundle + '.map';
|
|
225
|
+
const compose = execa(
|
|
226
|
+
'node',
|
|
227
|
+
[
|
|
228
|
+
composeSourceMaps,
|
|
229
|
+
metroSourceMap,
|
|
230
|
+
hermesSourceMap,
|
|
231
|
+
`-o ${options.outputSourceMap}`,
|
|
232
|
+
],
|
|
233
|
+
{
|
|
234
|
+
cwd: options.cwd,
|
|
235
|
+
},
|
|
236
|
+
);
|
|
237
|
+
compose.finally(() => {
|
|
238
|
+
fs.rmSync(metroSourceMap, {force: true});
|
|
239
|
+
fs.rmSync(hermesSourceMap, {force: true});
|
|
240
|
+
});
|
|
241
|
+
return compose;
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return bundle;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
module.exports = {tasks};
|