-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
choose proper numberOfLines prop name based on native
- Loading branch information
1 parent
5a90e0d
commit 1d9ae2c
Showing
56 changed files
with
5,320 additions
and
2 deletions.
There are no files selected for viewing
151 changes: 151 additions & 0 deletions
151
packages/react-native-gradle-plugin/bin/main/com/facebook/react/ReactExtension.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react | ||
|
||
import com.facebook.react.utils.projectPathToLibraryName | ||
import javax.inject.Inject | ||
import org.gradle.api.Project | ||
import org.gradle.api.file.DirectoryProperty | ||
import org.gradle.api.file.RegularFileProperty | ||
import org.gradle.api.provider.ListProperty | ||
import org.gradle.api.provider.Property | ||
|
||
abstract class ReactExtension @Inject constructor(project: Project) { | ||
|
||
private val objects = project.objects | ||
|
||
/** | ||
* The path to the root of your project. This is the path to where the `package.json` lives. All | ||
* the CLI commands will be invoked from this folder as working directory. | ||
* | ||
* Default: ${rootProject.dir}/../ | ||
*/ | ||
val root: DirectoryProperty = | ||
objects.directoryProperty().convention(project.rootProject.layout.projectDirectory.dir("../")) | ||
|
||
/** | ||
* The path to the react-native NPM package folder. | ||
* | ||
* Default: ${rootProject.dir}/../node_modules/react-native | ||
*/ | ||
val reactNativeDir: DirectoryProperty = | ||
objects.directoryProperty().convention(root.dir("node_modules/react-native")) | ||
|
||
/** | ||
* The path to the JS entry file. If not specified, the plugin will try to resolve it using a list | ||
* of known locations (e.g. `index.android.js`, `index.js`, etc.). | ||
*/ | ||
val entryFile: RegularFileProperty = objects.fileProperty() | ||
|
||
/** | ||
* The reference to the React Native CLI. If not specified, the plugin will try to resolve it | ||
* looking for `react-native` CLI inside `node_modules` in [root]. | ||
*/ | ||
val cliFile: RegularFileProperty = | ||
objects.fileProperty().convention(reactNativeDir.file("cli.js")) | ||
|
||
/** | ||
* The path to the Node executable and extra args. By default it assumes that you have `node` | ||
* installed and configured in your $PATH. Default: ["node"] | ||
*/ | ||
val nodeExecutableAndArgs: ListProperty<String> = | ||
objects.listProperty(String::class.java).convention(listOf("node")) | ||
|
||
/** The command to use to invoke bundle. Default is `bundle` and will be invoked on [root]. */ | ||
val bundleCommand: Property<String> = objects.property(String::class.java).convention("bundle") | ||
|
||
/** | ||
* Custom configuration file for the [bundleCommand]. If provided, it will be passed over with a | ||
* `--config` flag to the bundle command. | ||
*/ | ||
val bundleConfig: RegularFileProperty = objects.fileProperty() | ||
|
||
/** | ||
* The Bundle Asset name. This name will be used also for deriving other bundle outputs such as | ||
* the packager source map, the compiler source map and the output source map file. | ||
* | ||
* Default: index.android.bundle | ||
*/ | ||
val bundleAssetName: Property<String> = | ||
objects.property(String::class.java).convention("index.android.bundle") | ||
|
||
/** | ||
* Toggles the .so Cleanup step. If enabled, we will clean up all the unnecessary files before the | ||
* bundle task. If disabled, the developers will have to manually cleanup the files. Default: true | ||
*/ | ||
val enableSoCleanup: Property<Boolean> = objects.property(Boolean::class.java).convention(true) | ||
|
||
/** Extra args that will be passed to the [bundleCommand] Default: [] */ | ||
val extraPackagerArgs: ListProperty<String> = | ||
objects.listProperty(String::class.java).convention(emptyList()) | ||
|
||
/** | ||
* Allows to specify the debuggable variants (by default just 'debug'). Variants in this list | ||
* will: | ||
* - Not be bundled (the bundle file will not be created and won't be copied over). | ||
* - Have the Hermes Debug flags set. That's useful if you have another variant (say `canary`) | ||
* where you want dev mode to be enabled. Default: ['debug'] | ||
*/ | ||
val debuggableVariants: ListProperty<String> = | ||
objects.listProperty(String::class.java).convention(listOf("debug")) | ||
|
||
/** Hermes Config */ | ||
|
||
/** | ||
* The command to use to invoke hermesc (the hermes compiler). Default is "", the plugin will | ||
* autodetect it. | ||
*/ | ||
val hermesCommand: Property<String> = objects.property(String::class.java).convention("") | ||
|
||
/** | ||
* Whether to enable Hermes only on certain variants. If specified as a non-empty list, hermesc | ||
* and the .so cleanup for Hermes will be executed only for variants in this list. An empty list | ||
* assumes you're either using Hermes for all variants or not (see [enableHermes]). | ||
* | ||
* Default: [] | ||
*/ | ||
val enableHermesOnlyInVariants: ListProperty<String> = | ||
objects.listProperty(String::class.java).convention(emptyList()) | ||
|
||
/** Flags to pass to Hermesc. Default: ["-O", "-output-source-map"] */ | ||
val hermesFlags: ListProperty<String> = | ||
objects.listProperty(String::class.java).convention(listOf("-O", "-output-source-map")) | ||
|
||
/** Codegen Config */ | ||
|
||
/** | ||
* The path to the react-native-codegen NPM package folder. | ||
* | ||
* Default: ${rootProject.dir}/../node_modules/@react-native/codegen | ||
*/ | ||
val codegenDir: DirectoryProperty = | ||
objects.directoryProperty().convention(root.dir("node_modules/@react-native/codegen")) | ||
|
||
/** | ||
* The root directory for all JS files for the app. | ||
* | ||
* Default: the parent folder of the `/android` folder. | ||
*/ | ||
val jsRootDir: DirectoryProperty = objects.directoryProperty() | ||
|
||
/** | ||
* The library name that will be used for the codegen artifacts. | ||
* | ||
* Default: <UpperCamelVersionOfProjectPath>Spec (e.g. for :example:project it will be | ||
* ExampleProjectSpec). | ||
*/ | ||
val libraryName: Property<String> = | ||
objects.property(String::class.java).convention(projectPathToLibraryName(project.path)) | ||
|
||
/** | ||
* Java package name to use for any codegen artifacts produced during build time. Default: | ||
* com.facebook.fbreact.specs | ||
*/ | ||
val codegenJavaPackageName: Property<String> = | ||
objects.property(String::class.java).convention("com.facebook.fbreact.specs") | ||
} |
197 changes: 197 additions & 0 deletions
197
packages/react-native-gradle-plugin/bin/main/com/facebook/react/ReactPlugin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/* | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
package com.facebook.react | ||
|
||
import com.android.build.api.variant.AndroidComponentsExtension | ||
import com.android.build.gradle.internal.tasks.factory.dependsOn | ||
import com.facebook.react.internal.PrivateReactExtension | ||
import com.facebook.react.tasks.BuildCodegenCLITask | ||
import com.facebook.react.tasks.GenerateCodegenArtifactsTask | ||
import com.facebook.react.tasks.GenerateCodegenSchemaTask | ||
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFields | ||
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts | ||
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap | ||
import com.facebook.react.utils.DependencyUtils.configureDependencies | ||
import com.facebook.react.utils.DependencyUtils.configureRepositories | ||
import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings | ||
import com.facebook.react.utils.JdkConfiguratorUtils.configureJavaToolChains | ||
import com.facebook.react.utils.JsonUtils | ||
import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativeNdk | ||
import com.facebook.react.utils.ProjectUtils.needsCodegenFromPackageJson | ||
import com.facebook.react.utils.findPackageJsonFile | ||
import java.io.File | ||
import kotlin.system.exitProcess | ||
import org.gradle.api.Plugin | ||
import org.gradle.api.Project | ||
import org.gradle.api.Task | ||
import org.gradle.internal.jvm.Jvm | ||
|
||
class ReactPlugin : Plugin<Project> { | ||
override fun apply(project: Project) { | ||
checkJvmVersion(project) | ||
val extension = project.extensions.create("react", ReactExtension::class.java, project) | ||
|
||
// We register a private extension on the rootProject so that project wide configs | ||
// like codegen config can be propagated from app project to libraries. | ||
val rootExtension = | ||
project.rootProject.extensions.findByType(PrivateReactExtension::class.java) | ||
?: project.rootProject.extensions.create( | ||
"privateReact", PrivateReactExtension::class.java, project) | ||
|
||
// App Only Configuration | ||
project.pluginManager.withPlugin("com.android.application") { | ||
// We wire the root extension with the values coming from the app (either user populated or | ||
// defaults). | ||
rootExtension.root.set(extension.root) | ||
rootExtension.reactNativeDir.set(extension.reactNativeDir) | ||
rootExtension.codegenDir.set(extension.codegenDir) | ||
rootExtension.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs) | ||
|
||
project.afterEvaluate { | ||
val reactNativeDir = extension.reactNativeDir.get().asFile | ||
val propertiesFile = File(reactNativeDir, "ReactAndroid/gradle.properties") | ||
val versionAndGroupStrings = readVersionAndGroupStrings(propertiesFile) | ||
val versionString = versionAndGroupStrings.first | ||
val groupString = versionAndGroupStrings.second | ||
configureDependencies(project, versionString, groupString) | ||
configureRepositories(project, reactNativeDir) | ||
} | ||
|
||
configureReactNativeNdk(project, extension) | ||
configureBuildConfigFields(project) | ||
configureDevPorts(project) | ||
configureBackwardCompatibilityReactMap(project) | ||
|
||
project.extensions.getByType(AndroidComponentsExtension::class.java).apply { | ||
onVariants(selector().all()) { variant -> | ||
project.configureReactTasks(variant = variant, config = extension) | ||
} | ||
} | ||
configureCodegen(project, extension, rootExtension, isLibrary = false) | ||
} | ||
|
||
// Library Only Configuration | ||
project.pluginManager.withPlugin("com.android.library") { | ||
configureCodegen(project, extension, rootExtension, isLibrary = true) | ||
} | ||
|
||
// Library and App Configurations | ||
configureJavaToolChains(project) | ||
} | ||
|
||
private fun checkJvmVersion(project: Project) { | ||
val jvmVersion = Jvm.current()?.javaVersion?.majorVersion | ||
if ((jvmVersion?.toIntOrNull() ?: 0) <= 8) { | ||
project.logger.error( | ||
""" | ||
******************************************************************************** | ||
ERROR: requires JDK11 or higher. | ||
Incompatible major version detected: '$jvmVersion' | ||
******************************************************************************** | ||
""" | ||
.trimIndent()) | ||
exitProcess(1) | ||
} | ||
} | ||
|
||
/** This function sets up `react-native-codegen` in our Gradle plugin. */ | ||
@Suppress("UnstableApiUsage") | ||
private fun configureCodegen( | ||
project: Project, | ||
localExtension: ReactExtension, | ||
rootExtension: PrivateReactExtension, | ||
isLibrary: Boolean | ||
) { | ||
// First, we set up the output dir for the codegen. | ||
val generatedSrcDir = File(project.buildDir, "generated/source/codegen") | ||
|
||
// We specify the default value (convention) for jsRootDir. | ||
// It's the root folder for apps (so ../../ from the Gradle project) | ||
// and the package folder for library (so ../ from the Gradle project) | ||
if (isLibrary) { | ||
localExtension.jsRootDir.convention(project.layout.projectDirectory.dir("../")) | ||
} else { | ||
localExtension.jsRootDir.convention(localExtension.root) | ||
} | ||
|
||
val buildCodegenTask = | ||
project.tasks.register("buildCodegenCLI", BuildCodegenCLITask::class.java) { | ||
it.codegenDir.set(rootExtension.codegenDir) | ||
val bashWindowsHome = project.findProperty("REACT_WINDOWS_BASH") as String? | ||
it.bashWindowsHome.set(bashWindowsHome) | ||
|
||
// Please note that appNeedsCodegen is triggering a read of the package.json at | ||
// configuration time as we need to feed the onlyIf condition of this task. | ||
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda. | ||
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root) | ||
it.onlyIf { isLibrary || needsCodegenFromPackageJson } | ||
} | ||
|
||
// We create the task to produce schema from JS files. | ||
val generateCodegenSchemaTask = | ||
project.tasks.register( | ||
"generateCodegenSchemaFromJavaScript", GenerateCodegenSchemaTask::class.java) { it -> | ||
it.dependsOn(buildCodegenTask) | ||
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs) | ||
it.codegenDir.set(rootExtension.codegenDir) | ||
it.generatedSrcDir.set(generatedSrcDir) | ||
|
||
// We're reading the package.json at configuration time to properly feed | ||
// the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the | ||
// parsePackageJson should be invoked inside this lambda. | ||
val packageJson = findPackageJsonFile(project, rootExtension.root) | ||
val parsedPackageJson = packageJson?.let { JsonUtils.fromCodegenJson(it) } | ||
|
||
val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir | ||
if (jsSrcsDirInPackageJson != null) { | ||
it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson)) | ||
} else { | ||
it.jsRootDir.set(localExtension.jsRootDir) | ||
} | ||
val needsCodegenFromPackageJson = | ||
project.needsCodegenFromPackageJson(rootExtension.root) | ||
it.onlyIf { isLibrary || needsCodegenFromPackageJson } | ||
} | ||
|
||
// We create the task to generate Java code from schema. | ||
val generateCodegenArtifactsTask = | ||
project.tasks.register( | ||
"generateCodegenArtifactsFromSchema", GenerateCodegenArtifactsTask::class.java) { | ||
it.dependsOn(generateCodegenSchemaTask) | ||
it.reactNativeDir.set(rootExtension.reactNativeDir) | ||
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs) | ||
it.generatedSrcDir.set(generatedSrcDir) | ||
it.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root)) | ||
it.codegenJavaPackageName.set(localExtension.codegenJavaPackageName) | ||
it.libraryName.set(localExtension.libraryName) | ||
|
||
// Please note that appNeedsCodegen is triggering a read of the package.json at | ||
// configuration time as we need to feed the onlyIf condition of this task. | ||
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda. | ||
val needsCodegenFromPackageJson = | ||
project.needsCodegenFromPackageJson(rootExtension.root) | ||
it.onlyIf { isLibrary || needsCodegenFromPackageJson } | ||
} | ||
|
||
// We update the android configuration to include the generated sources. | ||
// This equivalent to this DSL: | ||
// | ||
// android { sourceSets { main { java { srcDirs += "$generatedSrcDir/java" } } } } | ||
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext -> | ||
ext.sourceSets.getByName("main").java.srcDir(File(generatedSrcDir, "java")) | ||
} | ||
|
||
// `preBuild` is one of the base tasks automatically registered by AGP. | ||
// This will invoke the codegen before compiling the entire project. | ||
project.tasks.named("preBuild", Task::class.java).dependsOn(generateCodegenArtifactsTask) | ||
} | ||
} |
Oops, something went wrong.