@ohos-ports/react-native-gradle-plugin 0.71.19-beta.0
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/README.md +16 -0
- package/build/libs/react-native-gradle-plugin.jar +0 -0
- package/build.gradle.kts +59 -0
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/gradlew +234 -0
- package/gradlew.bat +89 -0
- package/index.js +73 -0
- package/package.json +30 -0
- package/settings.gradle.kts +16 -0
- package/src/main/kotlin/com/facebook/react/ReactExtension.kt +151 -0
- package/src/main/kotlin/com/facebook/react/ReactPlugin.kt +212 -0
- package/src/main/kotlin/com/facebook/react/TaskConfiguration.kt +81 -0
- package/src/main/kotlin/com/facebook/react/internal/PrivateReactExtension.kt +56 -0
- package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfig.kt +15 -0
- package/src/main/kotlin/com/facebook/react/model/ModelCodegenConfigAndroid.kt +10 -0
- package/src/main/kotlin/com/facebook/react/model/ModelPackageJson.kt +10 -0
- package/src/main/kotlin/com/facebook/react/tasks/BuildCodegenCLITask.kt +58 -0
- package/src/main/kotlin/com/facebook/react/tasks/BundleHermesCTask.kt +200 -0
- package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenArtifactsTask.kt +83 -0
- package/src/main/kotlin/com/facebook/react/tasks/GenerateCodegenSchemaTask.kt +82 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareBoostTask.kt +46 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareGlogTask.kt +79 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareJSCTask.kt +50 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PrepareLibeventTask.kt +51 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/PreparePrefabHeadersTask.kt +62 -0
- package/src/main/kotlin/com/facebook/react/tasks/internal/utils/PrefabPreprocessingEntry.kt +27 -0
- package/src/main/kotlin/com/facebook/react/utils/AgpConfiguratorUtils.kt +54 -0
- package/src/main/kotlin/com/facebook/react/utils/BackwardCompatUtils.kt +48 -0
- package/src/main/kotlin/com/facebook/react/utils/DependencyUtils.kt +109 -0
- package/src/main/kotlin/com/facebook/react/utils/FileUtils.kt +20 -0
- package/src/main/kotlin/com/facebook/react/utils/JsonUtils.kt +21 -0
- package/src/main/kotlin/com/facebook/react/utils/NdkConfiguratorUtils.kt +147 -0
- package/src/main/kotlin/com/facebook/react/utils/Os.kt +44 -0
- package/src/main/kotlin/com/facebook/react/utils/PathUtils.kt +231 -0
- package/src/main/kotlin/com/facebook/react/utils/ProjectUtils.kt +55 -0
- package/src/main/kotlin/com/facebook/react/utils/TaskUtils.kt +28 -0
|
@@ -0,0 +1,212 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react
|
|
9
|
+
|
|
10
|
+
import com.android.build.api.variant.AndroidComponentsExtension
|
|
11
|
+
import com.android.build.gradle.AppExtension
|
|
12
|
+
import com.android.build.gradle.internal.tasks.factory.dependsOn
|
|
13
|
+
import com.facebook.react.internal.PrivateReactExtension
|
|
14
|
+
import com.facebook.react.tasks.BuildCodegenCLITask
|
|
15
|
+
import com.facebook.react.tasks.GenerateCodegenArtifactsTask
|
|
16
|
+
import com.facebook.react.tasks.GenerateCodegenSchemaTask
|
|
17
|
+
import com.facebook.react.utils.AgpConfiguratorUtils.configureBuildConfigFields
|
|
18
|
+
import com.facebook.react.utils.AgpConfiguratorUtils.configureDevPorts
|
|
19
|
+
import com.facebook.react.utils.BackwardCompatUtils.configureBackwardCompatibilityReactMap
|
|
20
|
+
import com.facebook.react.utils.DependencyUtils.configureDependencies
|
|
21
|
+
import com.facebook.react.utils.DependencyUtils.configureRepositories
|
|
22
|
+
import com.facebook.react.utils.DependencyUtils.readVersionAndGroupStrings
|
|
23
|
+
import com.facebook.react.utils.JsonUtils
|
|
24
|
+
import com.facebook.react.utils.NdkConfiguratorUtils.configureReactNativeNdk
|
|
25
|
+
import com.facebook.react.utils.ProjectUtils.needsCodegenFromPackageJson
|
|
26
|
+
import com.facebook.react.utils.findPackageJsonFile
|
|
27
|
+
import java.io.File
|
|
28
|
+
import kotlin.system.exitProcess
|
|
29
|
+
import org.gradle.api.Plugin
|
|
30
|
+
import org.gradle.api.Project
|
|
31
|
+
import org.gradle.api.Task
|
|
32
|
+
import org.gradle.internal.jvm.Jvm
|
|
33
|
+
|
|
34
|
+
class ReactPlugin : Plugin<Project> {
|
|
35
|
+
override fun apply(project: Project) {
|
|
36
|
+
checkJvmVersion(project)
|
|
37
|
+
val extension = project.extensions.create("react", ReactExtension::class.java, project)
|
|
38
|
+
|
|
39
|
+
// We register a private extension on the rootProject so that project wide configs
|
|
40
|
+
// like codegen config can be propagated from app project to libraries.
|
|
41
|
+
val rootExtension =
|
|
42
|
+
project.rootProject.extensions.findByType(PrivateReactExtension::class.java)
|
|
43
|
+
?: project.rootProject.extensions.create(
|
|
44
|
+
"privateReact", PrivateReactExtension::class.java, project)
|
|
45
|
+
|
|
46
|
+
// App Only Configuration
|
|
47
|
+
project.pluginManager.withPlugin("com.android.application") {
|
|
48
|
+
// We wire the root extension with the values coming from the app (either user populated or
|
|
49
|
+
// defaults).
|
|
50
|
+
rootExtension.root.set(extension.root)
|
|
51
|
+
rootExtension.reactNativeDir.set(extension.reactNativeDir)
|
|
52
|
+
rootExtension.codegenDir.set(extension.codegenDir)
|
|
53
|
+
rootExtension.nodeExecutableAndArgs.set(extension.nodeExecutableAndArgs)
|
|
54
|
+
|
|
55
|
+
project.afterEvaluate {
|
|
56
|
+
val reactNativeDir = extension.reactNativeDir.get().asFile
|
|
57
|
+
val propertiesFile = File(reactNativeDir, "ReactAndroid/gradle.properties")
|
|
58
|
+
val versionAndGroupStrings = readVersionAndGroupStrings(propertiesFile)
|
|
59
|
+
val versionString = versionAndGroupStrings.first
|
|
60
|
+
val groupString = versionAndGroupStrings.second
|
|
61
|
+
configureDependencies(project, versionString, groupString)
|
|
62
|
+
configureRepositories(project, reactNativeDir)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
configureReactNativeNdk(project, extension)
|
|
66
|
+
configureBuildConfigFields(project)
|
|
67
|
+
configureDevPorts(project)
|
|
68
|
+
configureBackwardCompatibilityReactMap(project)
|
|
69
|
+
|
|
70
|
+
project.extensions.getByType(AndroidComponentsExtension::class.java).apply {
|
|
71
|
+
onVariants(selector().all()) { variant ->
|
|
72
|
+
project.configureReactTasks(variant = variant, config = extension)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// This is a legacy AGP api. Needed as AGP 7.3 is not consuming generated resources correctly.
|
|
77
|
+
// Can be removed as we bump to AGP 7.4 stable.
|
|
78
|
+
// This registers the $buildDir/generated/res/react/<variant> folder as a
|
|
79
|
+
// res folder to be consumed with the old AGP Apis which are not broken.
|
|
80
|
+
project.extensions.getByType(AppExtension::class.java).apply {
|
|
81
|
+
this.applicationVariants.all { variant ->
|
|
82
|
+
val isDebuggableVariant =
|
|
83
|
+
extension.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) }
|
|
84
|
+
val targetName = variant.name.replaceFirstChar { it.uppercase() }
|
|
85
|
+
val bundleTaskName = "createBundle${targetName}JsAndAssets"
|
|
86
|
+
if (!isDebuggableVariant) {
|
|
87
|
+
variant.registerGeneratedResFolders(
|
|
88
|
+
project.layout.buildDirectory.files("generated/res/react/${variant.name}"))
|
|
89
|
+
variant.mergeResourcesProvider.get().dependsOn(bundleTaskName)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
configureCodegen(project, extension, rootExtension, isLibrary = false)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Library Only Configuration
|
|
97
|
+
project.pluginManager.withPlugin("com.android.library") {
|
|
98
|
+
configureCodegen(project, extension, rootExtension, isLibrary = true)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private fun checkJvmVersion(project: Project) {
|
|
103
|
+
val jvmVersion = Jvm.current()?.javaVersion?.majorVersion
|
|
104
|
+
if ((jvmVersion?.toIntOrNull() ?: 0) <= 8) {
|
|
105
|
+
project.logger.error(
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
********************************************************************************
|
|
109
|
+
|
|
110
|
+
ERROR: requires JDK11 or higher.
|
|
111
|
+
Incompatible major version detected: '$jvmVersion'
|
|
112
|
+
|
|
113
|
+
********************************************************************************
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
.trimIndent())
|
|
117
|
+
exitProcess(1)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** This function sets up `react-native-codegen` in our Gradle plugin. */
|
|
122
|
+
@Suppress("UnstableApiUsage")
|
|
123
|
+
private fun configureCodegen(
|
|
124
|
+
project: Project,
|
|
125
|
+
localExtension: ReactExtension,
|
|
126
|
+
rootExtension: PrivateReactExtension,
|
|
127
|
+
isLibrary: Boolean
|
|
128
|
+
) {
|
|
129
|
+
// First, we set up the output dir for the codegen.
|
|
130
|
+
val generatedSrcDir = File(project.buildDir, "generated/source/codegen")
|
|
131
|
+
|
|
132
|
+
// We specify the default value (convention) for jsRootDir.
|
|
133
|
+
// It's the root folder for apps (so ../../ from the Gradle project)
|
|
134
|
+
// and the package folder for library (so ../ from the Gradle project)
|
|
135
|
+
if (isLibrary) {
|
|
136
|
+
localExtension.jsRootDir.convention(project.layout.projectDirectory.dir("../"))
|
|
137
|
+
} else {
|
|
138
|
+
localExtension.jsRootDir.convention(localExtension.root)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
val buildCodegenTask =
|
|
142
|
+
project.tasks.register("buildCodegenCLI", BuildCodegenCLITask::class.java) {
|
|
143
|
+
it.codegenDir.set(rootExtension.codegenDir)
|
|
144
|
+
val bashWindowsHome = project.findProperty("REACT_WINDOWS_BASH") as String?
|
|
145
|
+
it.bashWindowsHome.set(bashWindowsHome)
|
|
146
|
+
|
|
147
|
+
// Please note that appNeedsCodegen is triggering a read of the package.json at
|
|
148
|
+
// configuration time as we need to feed the onlyIf condition of this task.
|
|
149
|
+
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
|
|
150
|
+
val needsCodegenFromPackageJson = project.needsCodegenFromPackageJson(rootExtension.root)
|
|
151
|
+
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// We create the task to produce schema from JS files.
|
|
155
|
+
val generateCodegenSchemaTask =
|
|
156
|
+
project.tasks.register(
|
|
157
|
+
"generateCodegenSchemaFromJavaScript", GenerateCodegenSchemaTask::class.java) { it ->
|
|
158
|
+
it.dependsOn(buildCodegenTask)
|
|
159
|
+
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
|
|
160
|
+
it.codegenDir.set(rootExtension.codegenDir)
|
|
161
|
+
it.generatedSrcDir.set(generatedSrcDir)
|
|
162
|
+
|
|
163
|
+
// We're reading the package.json at configuration time to properly feed
|
|
164
|
+
// the `jsRootDir` @Input property of this task & the onlyIf. Therefore, the
|
|
165
|
+
// parsePackageJson should be invoked inside this lambda.
|
|
166
|
+
val packageJson = findPackageJsonFile(project, rootExtension.root)
|
|
167
|
+
val parsedPackageJson = packageJson?.let { JsonUtils.fromCodegenJson(it) }
|
|
168
|
+
|
|
169
|
+
val jsSrcsDirInPackageJson = parsedPackageJson?.codegenConfig?.jsSrcsDir
|
|
170
|
+
if (jsSrcsDirInPackageJson != null) {
|
|
171
|
+
it.jsRootDir.set(File(packageJson.parentFile, jsSrcsDirInPackageJson))
|
|
172
|
+
} else {
|
|
173
|
+
it.jsRootDir.set(localExtension.jsRootDir)
|
|
174
|
+
}
|
|
175
|
+
val needsCodegenFromPackageJson =
|
|
176
|
+
project.needsCodegenFromPackageJson(rootExtension.root)
|
|
177
|
+
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// We create the task to generate Java code from schema.
|
|
181
|
+
val generateCodegenArtifactsTask =
|
|
182
|
+
project.tasks.register(
|
|
183
|
+
"generateCodegenArtifactsFromSchema", GenerateCodegenArtifactsTask::class.java) {
|
|
184
|
+
it.dependsOn(generateCodegenSchemaTask)
|
|
185
|
+
it.reactNativeDir.set(rootExtension.reactNativeDir)
|
|
186
|
+
it.nodeExecutableAndArgs.set(rootExtension.nodeExecutableAndArgs)
|
|
187
|
+
it.generatedSrcDir.set(generatedSrcDir)
|
|
188
|
+
it.packageJsonFile.set(findPackageJsonFile(project, rootExtension.root))
|
|
189
|
+
it.codegenJavaPackageName.set(localExtension.codegenJavaPackageName)
|
|
190
|
+
it.libraryName.set(localExtension.libraryName)
|
|
191
|
+
|
|
192
|
+
// Please note that appNeedsCodegen is triggering a read of the package.json at
|
|
193
|
+
// configuration time as we need to feed the onlyIf condition of this task.
|
|
194
|
+
// Therefore, the appNeedsCodegen needs to be invoked inside this lambda.
|
|
195
|
+
val needsCodegenFromPackageJson =
|
|
196
|
+
project.needsCodegenFromPackageJson(rootExtension.root)
|
|
197
|
+
it.onlyIf { isLibrary || needsCodegenFromPackageJson }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// We update the android configuration to include the generated sources.
|
|
201
|
+
// This equivalent to this DSL:
|
|
202
|
+
//
|
|
203
|
+
// android { sourceSets { main { java { srcDirs += "$generatedSrcDir/java" } } } }
|
|
204
|
+
project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext ->
|
|
205
|
+
ext.sourceSets.getByName("main").java.srcDir(File(generatedSrcDir, "java"))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// `preBuild` is one of the base tasks automatically registered by AGP.
|
|
209
|
+
// This will invoke the codegen before compiling the entire project.
|
|
210
|
+
project.tasks.named("preBuild", Task::class.java).dependsOn(generateCodegenArtifactsTask)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react
|
|
9
|
+
|
|
10
|
+
import com.android.build.api.variant.Variant
|
|
11
|
+
import com.facebook.react.tasks.BundleHermesCTask
|
|
12
|
+
import com.facebook.react.utils.NdkConfiguratorUtils.configureJsEnginePackagingOptions
|
|
13
|
+
import com.facebook.react.utils.NdkConfiguratorUtils.configureNewArchPackagingOptions
|
|
14
|
+
import com.facebook.react.utils.ProjectUtils.isHermesEnabled
|
|
15
|
+
import com.facebook.react.utils.detectedCliFile
|
|
16
|
+
import com.facebook.react.utils.detectedEntryFile
|
|
17
|
+
import java.io.File
|
|
18
|
+
import org.gradle.api.Project
|
|
19
|
+
|
|
20
|
+
@Suppress("SpreadOperator", "UnstableApiUsage")
|
|
21
|
+
internal fun Project.configureReactTasks(variant: Variant, config: ReactExtension) {
|
|
22
|
+
val targetName = variant.name.replaceFirstChar { it.uppercase() }
|
|
23
|
+
val targetPath = variant.name
|
|
24
|
+
|
|
25
|
+
// Resources: generated/assets/react/<variant>/index.android.bundle
|
|
26
|
+
val resourcesDir = File(buildDir, "generated/res/react/$targetPath")
|
|
27
|
+
// Bundle: generated/assets/react/<variant>/index.android.bundle
|
|
28
|
+
val jsBundleDir = File(buildDir, "generated/assets/react/$targetPath")
|
|
29
|
+
// Sourcemap: generated/sourcemaps/react/<variant>/index.android.bundle.map
|
|
30
|
+
val jsSourceMapsDir = File(buildDir, "generated/sourcemaps/react/$targetPath")
|
|
31
|
+
// Intermediate packager:
|
|
32
|
+
// intermediates/sourcemaps/react/<variant>/index.android.bundle.packager.map
|
|
33
|
+
// Intermediate compiler:
|
|
34
|
+
// intermediates/sourcemaps/react/<variant>/index.android.bundle.compiler.map
|
|
35
|
+
val jsIntermediateSourceMapsDir = File(buildDir, "intermediates/sourcemaps/react/$targetPath")
|
|
36
|
+
|
|
37
|
+
// The location of the cli.js file for React Native
|
|
38
|
+
val cliFile = detectedCliFile(config)
|
|
39
|
+
|
|
40
|
+
val isHermesEnabledInProject = project.isHermesEnabled
|
|
41
|
+
val isHermesEnabledInThisVariant =
|
|
42
|
+
if (config.enableHermesOnlyInVariants.get().isNotEmpty()) {
|
|
43
|
+
config.enableHermesOnlyInVariants.get().contains(variant.name) && isHermesEnabledInProject
|
|
44
|
+
} else {
|
|
45
|
+
isHermesEnabledInProject
|
|
46
|
+
}
|
|
47
|
+
val isDebuggableVariant =
|
|
48
|
+
config.debuggableVariants.get().any { it.equals(variant.name, ignoreCase = true) }
|
|
49
|
+
|
|
50
|
+
configureNewArchPackagingOptions(project, variant)
|
|
51
|
+
configureJsEnginePackagingOptions(config, variant, isHermesEnabledInThisVariant)
|
|
52
|
+
|
|
53
|
+
if (!isDebuggableVariant) {
|
|
54
|
+
val entryFileEnvVariable = System.getenv("ENTRY_FILE")
|
|
55
|
+
val bundleTask =
|
|
56
|
+
tasks.register("createBundle${targetName}JsAndAssets", BundleHermesCTask::class.java) {
|
|
57
|
+
it.root.set(config.root)
|
|
58
|
+
it.nodeExecutableAndArgs.set(config.nodeExecutableAndArgs)
|
|
59
|
+
it.cliFile.set(cliFile)
|
|
60
|
+
it.bundleCommand.set(config.bundleCommand)
|
|
61
|
+
it.entryFile.set(detectedEntryFile(config, entryFileEnvVariable))
|
|
62
|
+
it.extraPackagerArgs.set(config.extraPackagerArgs)
|
|
63
|
+
it.bundleConfig.set(config.bundleConfig)
|
|
64
|
+
it.bundleAssetName.set(config.bundleAssetName)
|
|
65
|
+
it.jsBundleDir.set(jsBundleDir)
|
|
66
|
+
it.resourcesDir.set(resourcesDir)
|
|
67
|
+
it.hermesEnabled.set(isHermesEnabledInThisVariant)
|
|
68
|
+
it.minifyEnabled.set(!isHermesEnabledInThisVariant)
|
|
69
|
+
it.devEnabled.set(false)
|
|
70
|
+
it.jsIntermediateSourceMapsDir.set(jsIntermediateSourceMapsDir)
|
|
71
|
+
it.jsSourceMapsDir.set(jsSourceMapsDir)
|
|
72
|
+
it.hermesCommand.set(config.hermesCommand)
|
|
73
|
+
it.hermesFlags.set(config.hermesFlags)
|
|
74
|
+
it.reactNativeDir.set(config.reactNativeDir)
|
|
75
|
+
}
|
|
76
|
+
// Currently broken inside AGP 7.3 We need to wait for a release of AGP 7.4 in order to use
|
|
77
|
+
// the addGeneratedSourceDirectory API.
|
|
78
|
+
// variant.sources.res?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::resourcesDir)
|
|
79
|
+
variant.sources.assets?.addGeneratedSourceDirectory(bundleTask, BundleHermesCTask::jsBundleDir)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.internal
|
|
9
|
+
|
|
10
|
+
import javax.inject.Inject
|
|
11
|
+
import org.gradle.api.Project
|
|
12
|
+
import org.gradle.api.file.DirectoryProperty
|
|
13
|
+
import org.gradle.api.provider.ListProperty
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A private extension we set on the rootProject to make easier to share values at execution time
|
|
17
|
+
* between app project and library project.
|
|
18
|
+
*
|
|
19
|
+
* Specifically, the [codegenDir], [reactNativeDir] and other properties should be provided by apps
|
|
20
|
+
* (for setups like a monorepo which are app specific) and libraries should honor those values.
|
|
21
|
+
*
|
|
22
|
+
* Users are not supposed to access directly this extension from their build.gradle file.
|
|
23
|
+
*/
|
|
24
|
+
abstract class PrivateReactExtension @Inject constructor(project: Project) {
|
|
25
|
+
|
|
26
|
+
private val objects = project.objects
|
|
27
|
+
|
|
28
|
+
val root: DirectoryProperty =
|
|
29
|
+
objects
|
|
30
|
+
.directoryProperty()
|
|
31
|
+
.convention(
|
|
32
|
+
// This is the default for the project root if the users hasn't specified anything.
|
|
33
|
+
// If the project is called "react-native-github"
|
|
34
|
+
// - We're inside the Github Repo -> root is defined by RN Tester (so no default
|
|
35
|
+
// needed)
|
|
36
|
+
// - We're inside an includedBuild as we're performing a build from source
|
|
37
|
+
// (then we're inside `node_modules/react-native`, so default should be ../../)
|
|
38
|
+
// If the project is called in any other name
|
|
39
|
+
// - We're inside a user project, so inside the ./android folder. Default should be
|
|
40
|
+
// ../
|
|
41
|
+
// User can always override this default by setting a `root =` inside the template.
|
|
42
|
+
if (project.rootProject.name == "react-native-github") {
|
|
43
|
+
project.rootProject.layout.projectDirectory.dir("../../")
|
|
44
|
+
} else {
|
|
45
|
+
project.rootProject.layout.projectDirectory.dir("../")
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
val reactNativeDir: DirectoryProperty =
|
|
49
|
+
objects.directoryProperty().convention(root.dir("node_modules/react-native"))
|
|
50
|
+
|
|
51
|
+
val nodeExecutableAndArgs: ListProperty<String> =
|
|
52
|
+
objects.listProperty(String::class.java).convention(listOf("node"))
|
|
53
|
+
|
|
54
|
+
val codegenDir: DirectoryProperty =
|
|
55
|
+
objects.directoryProperty().convention(root.dir("node_modules/react-native-codegen"))
|
|
56
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.model
|
|
9
|
+
|
|
10
|
+
data class ModelCodegenConfig(
|
|
11
|
+
val name: String?,
|
|
12
|
+
val type: String?,
|
|
13
|
+
val jsSrcsDir: String?,
|
|
14
|
+
val android: ModelCodegenConfigAndroid?
|
|
15
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.model
|
|
9
|
+
|
|
10
|
+
data class ModelCodegenConfigAndroid(val javaPackageName: String?)
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.model
|
|
9
|
+
|
|
10
|
+
data class ModelPackageJson(val codegenConfig: ModelCodegenConfig?)
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.tasks
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.utils.Os.unixifyPath
|
|
11
|
+
import com.facebook.react.utils.windowsAwareBashCommandLine
|
|
12
|
+
import org.gradle.api.file.DirectoryProperty
|
|
13
|
+
import org.gradle.api.file.FileCollection
|
|
14
|
+
import org.gradle.api.provider.Property
|
|
15
|
+
import org.gradle.api.tasks.*
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A Task that will call the `scripts/oss/build.sh` script to trigger the creation of the codegen
|
|
19
|
+
* lib artifacts.
|
|
20
|
+
*
|
|
21
|
+
* NOTE: This task is required when using react-native-codegen from source, instead of npm.
|
|
22
|
+
*/
|
|
23
|
+
abstract class BuildCodegenCLITask : Exec() {
|
|
24
|
+
|
|
25
|
+
@get:Internal abstract val codegenDir: DirectoryProperty
|
|
26
|
+
|
|
27
|
+
@get:Internal abstract val bashWindowsHome: Property<String>
|
|
28
|
+
|
|
29
|
+
@get:InputFiles
|
|
30
|
+
val input: FileCollection by lazy {
|
|
31
|
+
codegenDir.get().files("scripts", "src", "package.json", ".babelrc", ".prettierrc")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@get:OutputDirectories
|
|
35
|
+
val output: FileCollection by lazy { codegenDir.get().files("lib", "node_modules") }
|
|
36
|
+
|
|
37
|
+
init {
|
|
38
|
+
// We need this condition as we want a single instance of BuildCodegenCLITask to execute
|
|
39
|
+
// per project. Therefore we can safely skip the task if the lib/cli/ folder is available.
|
|
40
|
+
onlyIf {
|
|
41
|
+
val cliDir = codegenDir.file("lib/cli/").get().asFile
|
|
42
|
+
!cliDir.exists() || cliDir.listFiles()?.size == 0
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun exec() {
|
|
47
|
+
commandLine(
|
|
48
|
+
windowsAwareBashCommandLine(
|
|
49
|
+
codegenDir.asFile.get().canonicalPath.unixifyPath().plus(BUILD_SCRIPT_PATH),
|
|
50
|
+
bashWindowsHome = bashWindowsHome.orNull,
|
|
51
|
+
))
|
|
52
|
+
super.exec()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
companion object {
|
|
56
|
+
private const val BUILD_SCRIPT_PATH = "/scripts/oss/build.sh"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
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
|
+
|
|
8
|
+
package com.facebook.react.tasks
|
|
9
|
+
|
|
10
|
+
import com.facebook.react.utils.Os.cliPath
|
|
11
|
+
import com.facebook.react.utils.detectOSAwareHermesCommand
|
|
12
|
+
import com.facebook.react.utils.moveTo
|
|
13
|
+
import com.facebook.react.utils.windowsAwareCommandLine
|
|
14
|
+
import java.io.File
|
|
15
|
+
import org.gradle.api.DefaultTask
|
|
16
|
+
import org.gradle.api.file.ConfigurableFileTree
|
|
17
|
+
import org.gradle.api.file.DirectoryProperty
|
|
18
|
+
import org.gradle.api.file.RegularFileProperty
|
|
19
|
+
import org.gradle.api.provider.ListProperty
|
|
20
|
+
import org.gradle.api.provider.Property
|
|
21
|
+
import org.gradle.api.tasks.*
|
|
22
|
+
|
|
23
|
+
abstract class BundleHermesCTask : DefaultTask() {
|
|
24
|
+
|
|
25
|
+
init {
|
|
26
|
+
group = "react"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@get:Internal abstract val root: DirectoryProperty
|
|
30
|
+
|
|
31
|
+
@get:InputFiles
|
|
32
|
+
val sources: ConfigurableFileTree =
|
|
33
|
+
project.fileTree(root) {
|
|
34
|
+
it.include("**/*.js")
|
|
35
|
+
it.include("**/*.jsx")
|
|
36
|
+
it.include("**/*.ts")
|
|
37
|
+
it.include("**/*.tsx")
|
|
38
|
+
it.exclude("**/android/**/*")
|
|
39
|
+
it.exclude("**/ios/**/*")
|
|
40
|
+
it.exclude("**/build/**/*")
|
|
41
|
+
it.exclude("**/node_modules/**/*")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@get:Input abstract val nodeExecutableAndArgs: ListProperty<String>
|
|
45
|
+
|
|
46
|
+
@get:InputFile abstract val cliFile: RegularFileProperty
|
|
47
|
+
|
|
48
|
+
@get:Internal abstract val reactNativeDir: DirectoryProperty
|
|
49
|
+
|
|
50
|
+
@get:Input abstract val bundleCommand: Property<String>
|
|
51
|
+
|
|
52
|
+
@get:InputFile abstract val entryFile: RegularFileProperty
|
|
53
|
+
|
|
54
|
+
@get:InputFile @get:Optional abstract val bundleConfig: RegularFileProperty
|
|
55
|
+
|
|
56
|
+
@get:Input abstract val bundleAssetName: Property<String>
|
|
57
|
+
|
|
58
|
+
@get:Input abstract val minifyEnabled: Property<Boolean>
|
|
59
|
+
|
|
60
|
+
@get:Input abstract val hermesEnabled: Property<Boolean>
|
|
61
|
+
|
|
62
|
+
@get:Input abstract val devEnabled: Property<Boolean>
|
|
63
|
+
|
|
64
|
+
@get:Input abstract val extraPackagerArgs: ListProperty<String>
|
|
65
|
+
|
|
66
|
+
@get:Input abstract val hermesCommand: Property<String>
|
|
67
|
+
|
|
68
|
+
@get:Input abstract val hermesFlags: ListProperty<String>
|
|
69
|
+
|
|
70
|
+
@get:OutputDirectory abstract val jsBundleDir: DirectoryProperty
|
|
71
|
+
|
|
72
|
+
@get:OutputDirectory abstract val resourcesDir: DirectoryProperty
|
|
73
|
+
|
|
74
|
+
@get:OutputDirectory abstract val jsIntermediateSourceMapsDir: RegularFileProperty
|
|
75
|
+
|
|
76
|
+
@get:OutputDirectory abstract val jsSourceMapsDir: DirectoryProperty
|
|
77
|
+
|
|
78
|
+
@TaskAction
|
|
79
|
+
fun run() {
|
|
80
|
+
jsBundleDir.get().asFile.mkdirs()
|
|
81
|
+
resourcesDir.get().asFile.mkdirs()
|
|
82
|
+
jsIntermediateSourceMapsDir.get().asFile.mkdirs()
|
|
83
|
+
jsSourceMapsDir.get().asFile.mkdirs()
|
|
84
|
+
val bundleAssetFilename = bundleAssetName.get()
|
|
85
|
+
|
|
86
|
+
val bundleFile = File(jsBundleDir.get().asFile, bundleAssetFilename)
|
|
87
|
+
val packagerSourceMap = resolvePackagerSourceMapFile(bundleAssetFilename)
|
|
88
|
+
|
|
89
|
+
val bundleCommand = getBundleCommand(bundleFile, packagerSourceMap)
|
|
90
|
+
runCommand(bundleCommand)
|
|
91
|
+
|
|
92
|
+
if (hermesEnabled.get()) {
|
|
93
|
+
val detectedHermesCommand = detectOSAwareHermesCommand(root.get().asFile, hermesCommand.get())
|
|
94
|
+
val bytecodeFile = File("${bundleFile}.hbc")
|
|
95
|
+
val outputSourceMap = resolveOutputSourceMap(bundleAssetFilename)
|
|
96
|
+
val compilerSourceMap = resolveCompilerSourceMap(bundleAssetFilename)
|
|
97
|
+
|
|
98
|
+
val hermesCommand = getHermescCommand(detectedHermesCommand, bytecodeFile, bundleFile)
|
|
99
|
+
runCommand(hermesCommand)
|
|
100
|
+
bytecodeFile.moveTo(bundleFile)
|
|
101
|
+
|
|
102
|
+
if (hermesFlags.get().contains("-output-source-map")) {
|
|
103
|
+
val hermesTempSourceMapFile = File("$bytecodeFile.map")
|
|
104
|
+
hermesTempSourceMapFile.moveTo(compilerSourceMap)
|
|
105
|
+
|
|
106
|
+
val reactNativeDir = reactNativeDir.get().asFile
|
|
107
|
+
val composeScriptFile = File(reactNativeDir, "scripts/compose-source-maps.js")
|
|
108
|
+
val composeSourceMapsCommand =
|
|
109
|
+
getComposeSourceMapsCommand(
|
|
110
|
+
composeScriptFile, packagerSourceMap, compilerSourceMap, outputSourceMap)
|
|
111
|
+
runCommand(composeSourceMapsCommand)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
internal fun resolvePackagerSourceMapFile(bundleAssetName: String) =
|
|
117
|
+
if (hermesEnabled.get()) {
|
|
118
|
+
File(jsIntermediateSourceMapsDir.get().asFile, "$bundleAssetName.packager.map")
|
|
119
|
+
} else {
|
|
120
|
+
resolveOutputSourceMap(bundleAssetName)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
internal fun resolveOutputSourceMap(bundleAssetName: String) =
|
|
124
|
+
File(jsSourceMapsDir.get().asFile, "$bundleAssetName.map")
|
|
125
|
+
|
|
126
|
+
internal fun resolveCompilerSourceMap(bundleAssetName: String) =
|
|
127
|
+
File(jsIntermediateSourceMapsDir.get().asFile, "$bundleAssetName.compiler.map")
|
|
128
|
+
|
|
129
|
+
private fun runCommand(command: List<Any>) {
|
|
130
|
+
val process = ProcessBuilder(command.map { it.toString() })
|
|
131
|
+
.directory(root.get().asFile)
|
|
132
|
+
.redirectErrorStream(true)
|
|
133
|
+
.start()
|
|
134
|
+
val exitCode = process.waitFor()
|
|
135
|
+
if (exitCode != 0) {
|
|
136
|
+
throw org.gradle.api.GradleException("Command failed with exit code $exitCode: $command")
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
internal fun getBundleCommand(bundleFile: File, sourceMapFile: File): List<Any> =
|
|
141
|
+
windowsAwareCommandLine(
|
|
142
|
+
buildList {
|
|
143
|
+
val rootFile = root.get().asFile
|
|
144
|
+
addAll(nodeExecutableAndArgs.get())
|
|
145
|
+
add(cliFile.get().asFile.cliPath(rootFile))
|
|
146
|
+
add(bundleCommand.get())
|
|
147
|
+
add("--platform")
|
|
148
|
+
add("android")
|
|
149
|
+
add("--dev")
|
|
150
|
+
add(devEnabled.get().toString())
|
|
151
|
+
add("--reset-cache")
|
|
152
|
+
add("--entry-file")
|
|
153
|
+
add(entryFile.get().asFile.cliPath(rootFile))
|
|
154
|
+
add("--bundle-output")
|
|
155
|
+
add(bundleFile.cliPath(rootFile))
|
|
156
|
+
add("--assets-dest")
|
|
157
|
+
add(resourcesDir.get().asFile.cliPath(rootFile))
|
|
158
|
+
add("--sourcemap-output")
|
|
159
|
+
add(sourceMapFile.cliPath(rootFile))
|
|
160
|
+
if (bundleConfig.isPresent) {
|
|
161
|
+
add("--config")
|
|
162
|
+
add(bundleConfig.get().asFile.cliPath(rootFile))
|
|
163
|
+
}
|
|
164
|
+
add("--minify")
|
|
165
|
+
add(minifyEnabled.get().toString())
|
|
166
|
+
addAll(extraPackagerArgs.get())
|
|
167
|
+
add("--verbose")
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
internal fun getHermescCommand(
|
|
171
|
+
hermesCommand: String,
|
|
172
|
+
bytecodeFile: File,
|
|
173
|
+
bundleFile: File
|
|
174
|
+
): List<Any> {
|
|
175
|
+
val rootFile = root.get().asFile
|
|
176
|
+
return windowsAwareCommandLine(
|
|
177
|
+
hermesCommand,
|
|
178
|
+
"-emit-binary",
|
|
179
|
+
"-out",
|
|
180
|
+
bytecodeFile.cliPath(rootFile),
|
|
181
|
+
bundleFile.cliPath(rootFile),
|
|
182
|
+
*hermesFlags.get().toTypedArray())
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
internal fun getComposeSourceMapsCommand(
|
|
186
|
+
composeScript: File,
|
|
187
|
+
packagerSourceMap: File,
|
|
188
|
+
compilerSourceMap: File,
|
|
189
|
+
outputSourceMap: File
|
|
190
|
+
): List<Any> {
|
|
191
|
+
val rootFile = root.get().asFile
|
|
192
|
+
return windowsAwareCommandLine(
|
|
193
|
+
*nodeExecutableAndArgs.get().toTypedArray(),
|
|
194
|
+
composeScript.cliPath(rootFile),
|
|
195
|
+
packagerSourceMap.cliPath(rootFile),
|
|
196
|
+
compilerSourceMap.cliPath(rootFile),
|
|
197
|
+
"-o",
|
|
198
|
+
outputSourceMap.cliPath(rootFile))
|
|
199
|
+
}
|
|
200
|
+
}
|