Skip to content

Commit

Permalink
Gradle: Deprecate reactRoot in favor of root and reactNativeDir (
Browse files Browse the repository at this point in the history
…#33142)

Summary:
Pull Request resolved: #33142

The `reactRoot` property was confusing as we were using it for both the root of the project
and the react-native NPM Package root. I'm deprecating it and splitting it in two.

I've added several warning in the codebase to tell the people how to migrate away from it.
Moreover this is specifying default values that are more user-friendly. Users won't have to
configure anything unless they are in a monorepo.

Changelog:
[Android] [Changed] - Gradle: Deprecate `reactRoot` in favor of `root` and `reactNativeDir`

Reviewed By: ShikaSD

Differential Revision: D34277050

fbshipit-source-id: fc7f45017452b086726516a9586cacd9a661c287
  • Loading branch information
cortinico authored and Andrei Shikov committed Feb 24, 2022
1 parent bca4cf0 commit 57cc524
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 46 deletions.
2 changes: 1 addition & 1 deletion ReactAndroid/build.gradle
Expand Up @@ -406,7 +406,7 @@ react {
// This should be changed to a more generic name, e.g. `ReactCoreSpec`.
libraryName = "rncore"
jsRootDir = file("../Libraries")
reactRoot = file("$projectDir/..")
reactNativeDir = file("$projectDir/..")
useJavaGenerator = System.getenv("USE_CODEGEN_JAVAPOET")?.toBoolean() ?: false
// We search for the codegen in either one of the `node_modules` folder or in the
// root packages folder (that's for when we build from source without calling `yarn install`).
Expand Down
Expand Up @@ -29,13 +29,13 @@ abstract class ReactExtension @Inject constructor(project: Project) {
val applyAppPlugin: Property<Boolean> = objects.property(Boolean::class.java).convention(false)

/**
* The path to the react root folder. This is the path to the root folder where the `node_modules`
* folder is present. All the CLI commands will be invoked from this folder as working directory.
* 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: $projectDir/../../
* Default: ${rootProject.dir}/../
*/
val reactRoot: DirectoryProperty =
objects.directoryProperty().convention(project.layout.projectDirectory.dir("../../"))
val root: DirectoryProperty =
objects.directoryProperty().convention(project.rootProject.layout.projectDirectory.dir("../"))

/**
* The path to the JS entry file. If not specified, the plugin will try to resolve it using a list
Expand All @@ -45,7 +45,7 @@ abstract class ReactExtension @Inject constructor(project: Project) {

/**
* The path to the React Native CLI. If not specified, the plugin will try to resolve it looking
* for `react-native` CLI inside `node_modules` in [reactRoot].
* for `react-native` CLI inside `node_modules` in [root].
*/
val cliPath: Property<String> = objects.property(String::class.java)

Expand All @@ -56,9 +56,7 @@ abstract class ReactExtension @Inject constructor(project: Project) {
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 [reactRoot].
*/
/** 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")

/**
Expand Down Expand Up @@ -190,19 +188,27 @@ abstract class ReactExtension @Inject constructor(project: Project) {
/** Codegen Config */

/**
* The path to the react-native-codegen folder.
* The path to the react-native-codegen NPM package folder.
*
* Default: $projectDir/../../node_modules/react-native-codegen
* Default: ${rootProject.dir}/../node_modules/react-native-codegen
*/
val codegenDir: DirectoryProperty =
objects.directoryProperty().convention(reactRoot.dir("node_modules/react-native-codegen"))
objects.directoryProperty().convention(root.dir("node_modules/react-native-codegen"))

/**
* The path to the react-native NPM package folder.
*
* Default: ${rootProject.dir}/../node_modules/react-native-codegen
*/
val reactNativeDir: DirectoryProperty =
objects.directoryProperty().convention(root.dir("node_modules/react-native"))

/**
* The root directory for all JS files for the app.
*
* Default: $projectDir/../../
* Default: [root] (i.e. ${rootProject.dir}/../)
*/
val jsRootDir: DirectoryProperty = objects.directoryProperty().convention(reactRoot.get())
val jsRootDir: DirectoryProperty = objects.directoryProperty().convention(root.get())

/**
* The library name that will be used for the codegen artifacts.
Expand All @@ -222,4 +228,29 @@ abstract class ReactExtension @Inject constructor(project: Project) {

/** Whether the Java Generator (based on Javapoet) should be used or not. Default: false */
val useJavaGenerator: Property<Boolean> = objects.property(Boolean::class.java).convention(false)

/**
* The `reactRoot` property was confusing and should not be used.
*
* You should instead use either:
* - [root] to point to your root project (where the package.json lives)
* - [reactNativeDir] to point to the NPM package of react native.
*
* A valid configuration would look like:
*
* ```
* react {
* root = rootProject.file("..")
* reactNativeDir = rootProject.file("../node_modules/react-native")
* }
* ```
*
* Please also note that those are the default value and you most likely don't need those at all.
*/
@Deprecated(
"reactRoot was confusing and has been replace with root" +
"to point to your root project and reactNativeDir to point to " +
"the folder of the react-native NPM package",
replaceWith = ReplaceWith("reactNativeRoot"))
val reactRoot: DirectoryProperty = objects.directoryProperty()
}
Expand Up @@ -23,25 +23,26 @@ import org.gradle.internal.jvm.Jvm

class ReactPlugin : Plugin<Project> {
override fun apply(project: Project) {
checkJvmVersion()
checkJvmVersion(project)
val extension = project.extensions.create("react", ReactExtension::class.java, project)
applyAppPlugin(project, extension)
applyCodegenPlugin(project, extension)
}

private fun checkJvmVersion() {
private fun checkJvmVersion(project: Project) {
val jvmVersion = Jvm.current()?.javaVersion?.majorVersion
if ((jvmVersion?.toIntOrNull() ?: 0) <= 8) {
println("\n\n\n")
println(
"**************************************************************************************************************")
println("\n\n")
println("ERROR: requires JDK11 or higher.")
println("Incompatible major version detected: '" + jvmVersion + "'")
println("\n\n")
println(
"**************************************************************************************************************")
println("\n\n\n")
project.logger.error(
"""
********************************************************************************
ERROR: requires JDK11 or higher.
Incompatible major version detected: '$jvmVersion'
********************************************************************************
""".trimIndent())
exitProcess(1)
}
}
Expand Down Expand Up @@ -95,7 +96,8 @@ class ReactPlugin : Plugin<Project> {
project.tasks.register(
"generateCodegenArtifactsFromSchema", GenerateCodegenArtifactsTask::class.java) {
it.dependsOn(generateCodegenSchemaTask)
it.reactRoot.set(extension.reactRoot)
it.reactNativeDir.set(extension.reactNativeDir)
it.deprecatedReactRoot.set(extension.reactRoot)
it.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
it.codegenDir.set(extension.codegenDir)
it.useJavaGenerator.set(extension.useJavaGenerator)
Expand Down
Expand Up @@ -17,7 +17,6 @@ import com.facebook.react.utils.detectedCliPath
import com.facebook.react.utils.detectedEntryFile
import com.facebook.react.utils.detectedHermesCommand
import java.io.File
import java.util.*
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.Copy
Expand Down Expand Up @@ -56,11 +55,9 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactExte
it.group = REACT_GROUP
it.description = "create JS bundle and assets for $targetName."

it.reactRoot = config.reactRoot.get().asFile
it.reactRoot = config.root.get().asFile
it.sources =
fileTree(config.reactRoot) { fileTree ->
fileTree.setExcludes(config.inputExcludes.get())
}
fileTree(config.root) { fileTree -> fileTree.setExcludes(config.inputExcludes.get()) }
it.execCommand = execCommand
it.bundleCommand = config.bundleCommand.get()
it.devEnabled = !config.disableDevForVariant(variant)
Expand Down Expand Up @@ -98,7 +95,7 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactExte
it.group = REACT_GROUP
it.description = "bundle hermes resources for $targetName"

it.reactRoot = config.reactRoot.get().asFile
it.reactRoot = config.root.get().asFile
it.hermesCommand = detectedHermesCommand(config)
it.hermesFlags = config.hermesFlagsForVariant(variant)
it.jsBundleFile = jsBundleFile
Expand Down
Expand Up @@ -20,7 +20,7 @@ import org.gradle.api.tasks.*

abstract class GenerateCodegenArtifactsTask : Exec() {

@get:Internal abstract val reactRoot: DirectoryProperty
@get:Internal abstract val reactNativeDir: DirectoryProperty

@get:Internal abstract val codegenDir: DirectoryProperty

Expand All @@ -34,6 +34,9 @@ abstract class GenerateCodegenArtifactsTask : Exec() {

@get:Input abstract val libraryName: Property<String>

// We're keeping this just to fire a warning at the user should they use the `reactRoot` property.
@get:Internal abstract val deprecatedReactRoot: DirectoryProperty

@get:InputFile
val combineJsToSchemaCli: Provider<RegularFile> =
codegenDir.file("lib/cli/combine/combine-js-to-schema-cli.js")
Expand All @@ -46,6 +49,7 @@ abstract class GenerateCodegenArtifactsTask : Exec() {
@get:OutputDirectory val generatedJniFiles: Provider<Directory> = generatedSrcDir.dir("jni")

override fun exec() {
checkForDeprecatedProperty()
setupCommandLine()
super.exec()
if (useJavaGenerator.getOrElse(false)) {
Expand All @@ -63,11 +67,35 @@ abstract class GenerateCodegenArtifactsTask : Exec() {
}
}

private fun checkForDeprecatedProperty() {
if (deprecatedReactRoot.isPresent) {
project.logger.error(
"""
********************************************************************************
The `reactRoot` property is deprecated and will be removed in
future versions of React Native. The property is currently ignored.
You should instead use either:
- [root] to point to your root project (where the package.json lives)
- [reactNativeDir] to point to the NPM package of react native.
You should be fine by just removing the `reactRoot` line entirely from
your build.gradle file. Otherwise a valid configuration would look like:
react {
root = rootProject.file('..')
reactNativeDir = rootProject.file('../node_modules/react-native')
}
********************************************************************************
""".trimIndent())
}
}

internal fun setupCommandLine() {
commandLine(
windowsAwareYarn(
*nodeExecutableAndArgs.get().toTypedArray(),
reactRoot.file("scripts/generate-specs-cli.js").get().asFile.absolutePath,
reactNativeDir.file("scripts/generate-specs-cli.js").get().asFile.absolutePath,
"--platform",
"android",
"--schemaPath",
Expand Down
Expand Up @@ -11,7 +11,6 @@ package com.facebook.react.utils

import com.facebook.react.ReactExtension
import java.io.File
import java.util.*
import org.apache.tools.ant.taskdefs.condition.Os

/**
Expand All @@ -25,7 +24,7 @@ import org.apache.tools.ant.taskdefs.condition.Os
*/
internal fun detectedEntryFile(config: ReactExtension): File =
detectEntryFile(
entryFile = config.entryFile.orNull?.asFile, reactRoot = config.reactRoot.get().asFile)
entryFile = config.entryFile.orNull?.asFile, reactRoot = config.root.get().asFile)

/**
* Computes the CLI location for React Native. The Algo follows this order:
Expand All @@ -40,7 +39,7 @@ internal fun detectedCliPath(
): String =
detectCliPath(
projectDir = projectDir,
reactRoot = config.reactRoot.get().asFile,
reactRoot = config.root.get().asFile,
preconfiguredCliPath = config.cliPath.orNull)

/**
Expand Down
Expand Up @@ -79,13 +79,13 @@ class GenerateCodegenArtifactsTaskTest {
@Test
@WithOs(OS.UNIX)
fun setupCommandLine_withoutJavaGenerator_willSetupCorrectly() {
val reactRoot = tempFolder.newFolder("node_modules/react-native/")
val reactNativeDir = tempFolder.newFolder("node_modules/react-native/")
val codegenDir = tempFolder.newFolder("codegen")
val outputDir = tempFolder.newFolder("output")

val task =
createTestTask<GenerateCodegenArtifactsTask> {
it.reactRoot.set(reactRoot)
it.reactNativeDir.set(reactNativeDir)
it.codegenDir.set(codegenDir)
it.generatedSrcDir.set(outputDir)
it.nodeExecutableAndArgs.set(listOf("--verbose"))
Expand All @@ -99,7 +99,7 @@ class GenerateCodegenArtifactsTaskTest {
listOf(
"yarn",
"--verbose",
File(reactRoot, "scripts/generate-specs-cli.js").toString(),
File(reactNativeDir, "scripts/generate-specs-cli.js").toString(),
"--platform",
"android",
"--schemaPath",
Expand Down
Expand Up @@ -33,7 +33,7 @@ class PathUtilsTest {
@Test
fun detectedEntryFile_withAndroidEntryPoint() {
val extension = TestReactExtension(ProjectBuilder.builder().build())
extension.reactRoot.set(tempFolder.root)
extension.root.set(tempFolder.root)
tempFolder.newFile("index.android.js")

val actual = detectedEntryFile(extension)
Expand All @@ -44,7 +44,7 @@ class PathUtilsTest {
@Test
fun detectedEntryFile_withDefaultEntryPoint() {
val extension = TestReactExtension(ProjectBuilder.builder().build())
extension.reactRoot.set(tempFolder.root)
extension.root.set(tempFolder.root)

val actual = detectedEntryFile(extension)

Expand Down Expand Up @@ -80,7 +80,7 @@ class PathUtilsTest {
fun detectedCliPath_withCliFromNodeModules() {
val project = ProjectBuilder.builder().build()
val extension = TestReactExtension(project)
extension.reactRoot.set(tempFolder.root)
extension.root.set(tempFolder.root)
val expected =
File(tempFolder.root, "node_modules/react-native/cli.js").apply {
parentFile.mkdirs()
Expand Down
3 changes: 2 additions & 1 deletion packages/rn-tester/android/app/build.gradle
Expand Up @@ -80,14 +80,15 @@ react {
cliPath = "../../../../cli.js"
bundleAssetName = "RNTesterApp.android.bundle"
entryFile = file("../../js/RNTesterApp.android.js")
reactRoot = rootDir
root = rootDir
inputExcludes = ["android/**", "./**", ".gradle/**"]
composeSourceMapsPath = "$rootDir/scripts/compose-source-maps.js"
hermesCommand = "$rootDir/node_modules/hermes-engine/%OS-BIN%/hermesc"
enableHermesForVariant { def v -> v.name.contains("hermes") }

// Codegen Configs
jsRootDir = file("$rootDir/packages/rn-tester")
reactNativeDir = rootDir
libraryName = "rntester"
useJavaGenerator = System.getenv("USE_CODEGEN_JAVAPOET")?.toBoolean() ?: false
}
Expand Down

0 comments on commit 57cc524

Please sign in to comment.