mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Extract bundle task
Summary: Changelog: [Internal] Extracts task definition for bundling and hermes binary into separate tasks in the new plugin. Reviewed By: mdvacca Differential Revision: D25915057 fbshipit-source-id: b1d8a4b5e8789c3b7832efea13274435c9391ccb
This commit is contained in:
committed by
Facebook GitHub Bot
parent
dbbc1c1624
commit
959e135d80
+4
-3
@@ -9,14 +9,15 @@ package com.facebook.react
|
||||
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
|
||||
open class ReactAppExtension(private val projectDir: File) {
|
||||
open class ReactAppExtension(private val project: Project) {
|
||||
var composeSourceMapsPath: String = "node_modules/react-native/scripts/compose-source-maps.js"
|
||||
var bundleAssetName: String = "index.android.bundle"
|
||||
var entryFile: File? = null
|
||||
var bundleCommand: String = "bundle"
|
||||
var reactRoot: File = File(projectDir, "../../")
|
||||
var reactRoot: File = File(project.projectDir, "../../")
|
||||
var inputExcludes: List<String> = listOf("android/**", "ios/**")
|
||||
var bundleConfig: String? = null
|
||||
var enableVmCleanup: Boolean = true
|
||||
@@ -39,7 +40,7 @@ open class ReactAppExtension(private val projectDir: File) {
|
||||
|
||||
internal val detectedCliPath: String
|
||||
get() = detectCliPath(
|
||||
projectDir = projectDir,
|
||||
projectDir = project.projectDir,
|
||||
reactRoot = reactRoot,
|
||||
preconfuredCliPath = cliPath
|
||||
)
|
||||
|
||||
+1
-2
@@ -17,8 +17,7 @@ import org.gradle.kotlin.dsl.getByType
|
||||
|
||||
class ReactAppPlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
// todo rename codegen or combine extensions
|
||||
val config = project.extensions.create<ReactAppExtension>("reactApp", project.projectDir)
|
||||
val config = project.extensions.create<ReactAppExtension>("reactApp", project)
|
||||
|
||||
project.afterEvaluate {
|
||||
val androidConfiguration = extensions.getByType<BaseExtension>()
|
||||
|
||||
+51
-98
@@ -10,16 +10,18 @@ package com.facebook.react
|
||||
import com.android.build.gradle.api.ApplicationVariant
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import com.android.build.gradle.api.LibraryVariant
|
||||
import com.facebook.react.tasks.windowsAwareCommandLine
|
||||
import com.facebook.react.tasks.BundleJsAndAssetsTask
|
||||
import com.facebook.react.tasks.HermesBinaryTask
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.kotlin.dsl.withGroovyBuilder
|
||||
import org.gradle.kotlin.dsl.create
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import java.io.File
|
||||
|
||||
private const val REACT_GROUP = "react"
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppExtension) {
|
||||
val targetName = variant.name.capitalize()
|
||||
@@ -38,43 +40,26 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
|
||||
val jsOutputSourceMapFile = File(jsSourceMapsDir, "${config.bundleAssetName}.map")
|
||||
|
||||
// Additional node and packager commandline arguments
|
||||
val nodeExecutableAndArgs = config.nodeExecutableAndArgs.toTypedArray()
|
||||
val nodeExecutableAndArgs = config.nodeExecutableAndArgs
|
||||
val cliPath = config.detectedCliPath
|
||||
|
||||
val execCommand = nodeExecutableAndArgs + cliPath
|
||||
val enableHermes = config.enableHermesForVariant(variant)
|
||||
val bundleEnabled = variant.checkBundleEnabled(config)
|
||||
|
||||
val currentBundleTask = tasks.create<Exec>("bundle${targetName}JsAndAssets") {
|
||||
group = "react"
|
||||
description = "bundle JS and assets for $targetName."
|
||||
val bundleTask = tasks.register<BundleJsAndAssetsTask>("bundle${targetName}JsAndAssets") {
|
||||
val task = this
|
||||
task.group = REACT_GROUP
|
||||
task.description = "bundle JS and assets for $targetName."
|
||||
|
||||
// Create dirs if they are not there (e.g. the "clean" task just ran)
|
||||
doFirst {
|
||||
jsBundleDir.deleteRecursively()
|
||||
jsBundleDir.mkdirs()
|
||||
resourcesDir.deleteRecursively()
|
||||
resourcesDir.mkdirs()
|
||||
jsIntermediateSourceMapsDir.deleteRecursively()
|
||||
jsIntermediateSourceMapsDir.mkdirs()
|
||||
jsSourceMapsDir.deleteRecursively()
|
||||
jsSourceMapsDir.mkdirs()
|
||||
task.reactRoot = config.reactRoot
|
||||
task.sources = fileTree(config.reactRoot) {
|
||||
setExcludes(config.inputExcludes)
|
||||
}
|
||||
|
||||
// Set up inputs and outputs so gradle can cache the result
|
||||
inputs.files(
|
||||
fileTree(config.reactRoot) {
|
||||
setExcludes(config.inputExcludes)
|
||||
}
|
||||
)
|
||||
outputs.dir(jsBundleDir)
|
||||
outputs.dir(resourcesDir)
|
||||
|
||||
// Set up the call to the react-native cli
|
||||
workingDir(config.reactRoot)
|
||||
|
||||
// Set up dev mode
|
||||
val devEnabled = !(variant.name in config.devDisabledInVariants || variant.isRelease)
|
||||
task.execCommand = execCommand
|
||||
task.bundleCommand = config.bundleCommand
|
||||
task.devEnabled = !(variant.name in config.devDisabledInVariants || isRelease)
|
||||
task.entryFile = config.detectedEntryFile
|
||||
|
||||
val extraArgs = mutableListOf<String>()
|
||||
|
||||
@@ -91,79 +76,48 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
|
||||
|
||||
extraArgs.addAll(config.extraPackagerArgs)
|
||||
|
||||
windowsAwareCommandLine(
|
||||
*execCommand,
|
||||
config.bundleCommand,
|
||||
"--platform", "android",
|
||||
"--dev", "$devEnabled",
|
||||
"--reset-cache",
|
||||
"--entry-file", config.detectedEntryFile,
|
||||
"--bundle-output", jsBundleFile,
|
||||
"--assets-dest", resourcesDir,
|
||||
"--sourcemap-output", if (enableHermes) jsPackagerSourceMapFile else jsOutputSourceMapFile,
|
||||
*extraArgs.toTypedArray()
|
||||
)
|
||||
task.extraArgs = emptyList()
|
||||
|
||||
if (enableHermes) {
|
||||
doLast {
|
||||
val hermesFlags = if (isRelease) {
|
||||
config.hermesFlagsRelease
|
||||
} else {
|
||||
config.hermesFlagsDebug
|
||||
}.toTypedArray()
|
||||
|
||||
val hbcTempFile = file("$jsBundleFile.hbc")
|
||||
exec {
|
||||
windowsAwareCommandLine(
|
||||
config.osAwareHermesCommand,
|
||||
"-emit-binary",
|
||||
"-out", hbcTempFile, jsBundleFile,
|
||||
*hermesFlags
|
||||
)
|
||||
}
|
||||
ant.withGroovyBuilder {
|
||||
"move"(
|
||||
"file" to hbcTempFile,
|
||||
"toFile" to jsBundleFile
|
||||
)
|
||||
}
|
||||
if (hermesFlags.contains("-output-source-map")) {
|
||||
ant.withGroovyBuilder {
|
||||
"move"(
|
||||
"file" to "$jsBundleFile.hbc.map",
|
||||
"toFile" to jsCompilerSourceMapFile
|
||||
)
|
||||
}
|
||||
exec {
|
||||
// TODO: set task dependencies for caching
|
||||
|
||||
// Set up the call to the compose-source-maps script
|
||||
workingDir(config.reactRoot)
|
||||
windowsAwareCommandLine(
|
||||
*nodeExecutableAndArgs,
|
||||
config.composeSourceMapsPath,
|
||||
jsPackagerSourceMapFile,
|
||||
jsCompilerSourceMapFile,
|
||||
"-o", jsOutputSourceMapFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
task.jsBundleDir = jsBundleDir
|
||||
task.jsBundleFile = jsBundleFile
|
||||
task.resourcesDir = resourcesDir
|
||||
task.jsIntermediateSourceMapsDir = jsIntermediateSourceMapsDir
|
||||
task.jsSourceMapsDir = jsSourceMapsDir
|
||||
task.jsSourceMapsFile = if (enableHermes) jsPackagerSourceMapFile else jsOutputSourceMapFile
|
||||
|
||||
enabled = bundleEnabled
|
||||
}
|
||||
|
||||
val hermesTask = tasks.register<HermesBinaryTask>("emit${targetName}HermesResources") {
|
||||
val task = this
|
||||
task.group = REACT_GROUP
|
||||
task.description = "bundle hermes resources for $targetName"
|
||||
|
||||
task.reactRoot = config.reactRoot
|
||||
task.hermesCommand = config.osAwareHermesCommand
|
||||
task.hermesFlags = if (isRelease) config.hermesFlagsRelease else config.hermesFlagsDebug
|
||||
task.jsBundleFile = jsBundleFile
|
||||
task.composeSourceMapsCommand = nodeExecutableAndArgs + config.composeSourceMapsPath
|
||||
task.jsPackagerSourceMapFile = jsPackagerSourceMapFile
|
||||
task.jsCompilerSourceMapFile = jsCompilerSourceMapFile
|
||||
task.jsOutputSourceMapFile = jsOutputSourceMapFile
|
||||
|
||||
task.dependsOn(bundleTask)
|
||||
|
||||
enabled = bundleEnabled && enableHermes
|
||||
}
|
||||
|
||||
// todo expose bundle task and its generated folders
|
||||
val generatedResFolders = files(resourcesDir).builtBy(currentBundleTask)
|
||||
// val generatedAssetsFolders = files(jsBundleDir).builtBy(currentBundleTask)
|
||||
val generatedResFolders = files(resourcesDir).builtBy(hermesTask, bundleTask)
|
||||
//val generatedAssetsFolders = files(jsBundleDir).builtBy(hermesTask, bundleTask)
|
||||
|
||||
variant.registerGeneratedResFolders(generatedResFolders)
|
||||
variant.mergeResourcesProvider.get().dependsOn(currentBundleTask)
|
||||
variant.mergeResourcesProvider.get().dependsOn(bundleTask, hermesTask)
|
||||
|
||||
val packageTask = when (variant) {
|
||||
is ApplicationVariant -> variant.packageApplicationProvider.get()
|
||||
is LibraryVariant -> variant.packageLibraryProvider.get()
|
||||
else -> tasks.findByName("package$targetName")!!
|
||||
else -> tasks.findByName("package$targetName") ?: error("Couldn't find a package task for $targetName")
|
||||
}
|
||||
|
||||
// pre bundle build task for Android plugin 3.2+
|
||||
@@ -178,9 +132,9 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
|
||||
from(resourcesDir)
|
||||
into(file(resourcesDirConfigValue))
|
||||
|
||||
dependsOn(currentBundleTask)
|
||||
dependsOn(bundleTask)
|
||||
|
||||
enabled = currentBundleTask.enabled
|
||||
enabled = bundleEnabled
|
||||
}
|
||||
|
||||
packageTask.dependsOn(currentCopyResTask)
|
||||
@@ -215,7 +169,7 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
|
||||
// mergeAssets must run first, as it clears the intermediates directory
|
||||
dependsOn(variant.mergeAssetsProvider.get())
|
||||
|
||||
enabled = currentBundleTask.enabled
|
||||
enabled = bundleEnabled
|
||||
}
|
||||
|
||||
// mergeResources task runs before the bundle file is copied to the intermediate asset directory from Android plugin 4.1+.
|
||||
@@ -262,8 +216,7 @@ internal fun Project.configureReactTasks(variant: BaseVariant, config: ReactAppE
|
||||
}
|
||||
|
||||
if (config.enableVmCleanup) {
|
||||
val task = tasks.findByName("package$targetName")
|
||||
task?.doFirst(vmSelectionAction)
|
||||
packageTask.doFirst(vmSelectionAction)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
open class BundleJsAndAssetsTask : DefaultTask() {
|
||||
lateinit var reactRoot: File
|
||||
|
||||
@get:InputFiles
|
||||
@Suppress("UNUSED") // used to invalidate caches
|
||||
lateinit var sources: FileTree
|
||||
@get:Input
|
||||
lateinit var execCommand: List<String>
|
||||
@get:Input
|
||||
lateinit var bundleCommand: String
|
||||
@get:Input
|
||||
var devEnabled: Boolean = true
|
||||
@get:Input
|
||||
lateinit var entryFile: File
|
||||
@get:Input
|
||||
var extraArgs: List<String> = emptyList()
|
||||
|
||||
@get:OutputDirectory
|
||||
lateinit var jsBundleDir: File
|
||||
@get:OutputFile
|
||||
lateinit var jsBundleFile: File
|
||||
@get:OutputDirectory
|
||||
lateinit var resourcesDir: File
|
||||
@get:OutputDirectory
|
||||
lateinit var jsIntermediateSourceMapsDir: File
|
||||
@get:OutputDirectory
|
||||
lateinit var jsSourceMapsDir: File
|
||||
@get:OutputFile
|
||||
lateinit var jsSourceMapsFile: File
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
cleanOutputDirectories()
|
||||
executeBundleCommand()
|
||||
}
|
||||
|
||||
private fun cleanOutputDirectories() {
|
||||
jsBundleDir.recreateDir()
|
||||
resourcesDir.recreateDir()
|
||||
jsIntermediateSourceMapsDir.recreateDir()
|
||||
jsSourceMapsDir.recreateDir()
|
||||
}
|
||||
|
||||
private fun executeBundleCommand() {
|
||||
project.exec {
|
||||
workingDir(reactRoot)
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
windowsAwareCommandLine(
|
||||
*execCommand.toTypedArray(),
|
||||
bundleCommand,
|
||||
"--platform", "android",
|
||||
"--dev", devEnabled,
|
||||
"--reset-cache",
|
||||
"--entry-file", entryFile,
|
||||
"--bundle-output", jsBundleFile,
|
||||
"--assets-dest", resourcesDir,
|
||||
"--sourcemap-output", jsSourceMapsFile,
|
||||
*extraArgs.toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.recreateDir() {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
open class HermesBinaryTask : DefaultTask() {
|
||||
lateinit var reactRoot: File
|
||||
|
||||
@get:Input
|
||||
lateinit var hermesCommand: String
|
||||
@get:Input
|
||||
var hermesFlags: List<String> = emptyList()
|
||||
@get:InputFile
|
||||
lateinit var jsBundleFile: File
|
||||
|
||||
@get:Input
|
||||
lateinit var composeSourceMapsCommand: List<String>
|
||||
@get:Input
|
||||
lateinit var jsPackagerSourceMapFile: File
|
||||
|
||||
@get:OutputFile
|
||||
lateinit var jsCompilerSourceMapFile: File
|
||||
@get:OutputFile
|
||||
lateinit var jsOutputSourceMapFile: File
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val bytecodeTempFile = File("$jsBundleFile.hbc")
|
||||
emitHermesBinary(outputFile = bytecodeTempFile)
|
||||
bytecodeTempFile.moveTo(jsBundleFile)
|
||||
|
||||
if (hermesFlags.contains("-output-source-map")) {
|
||||
val hermesTempSourceMapFile = File("$bytecodeTempFile.map")
|
||||
hermesTempSourceMapFile.moveTo(jsCompilerSourceMapFile)
|
||||
composeSourceMaps()
|
||||
}
|
||||
}
|
||||
|
||||
private fun emitHermesBinary(outputFile: File) {
|
||||
project.exec {
|
||||
@Suppress("SpreadOperator")
|
||||
windowsAwareCommandLine(
|
||||
hermesCommand,
|
||||
"-emit-binary",
|
||||
"-out", outputFile,
|
||||
jsBundleFile,
|
||||
*hermesFlags.toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun composeSourceMaps() {
|
||||
project.exec {
|
||||
workingDir(reactRoot)
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
windowsAwareCommandLine(
|
||||
*composeSourceMapsCommand.toTypedArray(),
|
||||
jsPackagerSourceMapFile,
|
||||
jsCompilerSourceMapFile,
|
||||
"-o", jsOutputSourceMapFile
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.moveTo(destination: File) {
|
||||
copyTo(destination, overwrite = true)
|
||||
delete()
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -10,11 +10,10 @@ package com.facebook.react.tasks
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import org.gradle.process.ExecSpec
|
||||
|
||||
@Suppress("SpreadOperator")
|
||||
internal fun ExecSpec.windowsAwareCommandLine(vararg args: Any) {
|
||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
commandLine("cmd", "/c", *args)
|
||||
commandLine(listOf("cmd", "/c") + args)
|
||||
} else {
|
||||
commandLine(*args)
|
||||
commandLine(args.toList())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user