mirror of
https://github.com/facebook/react-native.git
synced 2024-11-21 21:27:46 +00:00
codegen Gradle: introduce com.facebook.react.codegen plugin to replace architecture.gradle script
Summary: Instead of applying configs from gradle scripts, this introduces a proper Gradle plugin to enable Codegen in an application or library project. In the build.gradle, one enables it by: ``` plugins { id("com.android.application") id("com.facebook.react.codegen") // <--- } // ... react { // <--- the new plugin extension enableCodegen = System.getenv("USE_CODEGEN") jsRootDir = file("$rootDir/RNTester") reactNativeRootDir = file("$rootDir") } ``` The plugin supports `react` plugin extension as demonstrated above. Adding this: * automatically generates all TurboModule Java files via react-native-codegen **before the `preBuild` Gradle task** * automatically adds the files to the `android {}` project configuration * is done per project (build.gradle) This will be the foundation for future React Native gradle plugin beyond just for react-native-codegen. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D23065685 fbshipit-source-id: 4ea67e48fab33b238c0973463cdb00de8cdadfcc
This commit is contained in:
parent
b7d6b325c2
commit
e8c1eeeb06
@ -123,7 +123,7 @@ android {
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
javaMaxHeapSize "4g"
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
|
||||
flavorDimensions "vm"
|
||||
@ -222,3 +222,9 @@ dependencies {
|
||||
androidTestImplementation('com.wix:detox:+') { transitive = true }
|
||||
androidTestImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
react {
|
||||
enableCodegen = System.getenv("USE_CODEGEN") ?: false
|
||||
jsRootDir = file("$rootDir/RNTester")
|
||||
reactNativeRootDir = file("$rootDir")
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("com.facebook.react.codegen")
|
||||
id("maven")
|
||||
id("de.undercouch.download")
|
||||
id("com.facebook.react.codegen")
|
||||
}
|
||||
|
||||
import java.nio.file.Paths
|
||||
@ -465,8 +465,9 @@ dependencies {
|
||||
}
|
||||
|
||||
apply(from: "release.gradle")
|
||||
apply(from: "../architecture.gradle");
|
||||
generateNativeArtifactsFromJavaScript([
|
||||
enableCodegen: System.getenv("USE_CODEGEN"),
|
||||
jsRootDir: "${file('../Libraries')}",
|
||||
])
|
||||
|
||||
react {
|
||||
enableCodegen = System.getenv("USE_CODEGEN") ?: false
|
||||
jsRootDir = file("../Libraries")
|
||||
reactNativeRootDir = file("$rootDir")
|
||||
}
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
def codegenDir = "$rootDir/packages/react-native-codegen";
|
||||
def codegenGenerateSchemaCli = "$codegenDir/lib/cli/combine/combine-js-to-schema-cli.js";
|
||||
def codegenGenerateNativeModuleSpecsCli = "$rootDir/scripts/generate-native-modules-specs-cli.js";
|
||||
def schemaFile = "schema.json";
|
||||
|
||||
// TODO: Consider building Gradle plugin instead.
|
||||
|
||||
/**
|
||||
* The config is derived from app-level `project.react`.
|
||||
*/
|
||||
ext.generateNativeArtifactsFromJavaScript = { Map config ->
|
||||
def nodeExecutableAndArgs = config.nodeExecutableAndArgs ?: ["node"];
|
||||
def jsRootDir = config.jsRootDir ?: config.root;
|
||||
|
||||
if (!config.enableCodegen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Create build dir
|
||||
def generatedSrcDir = file("$buildDir/generated/source/codegen");
|
||||
|
||||
// 2. Produce schema from JS files.
|
||||
task generateCodegenSchemaFromJavaScript(type: Exec) {
|
||||
doFirst {
|
||||
generatedSrcDir.deleteDir()
|
||||
generatedSrcDir.mkdirs()
|
||||
}
|
||||
|
||||
def schemaOutputFile = file("$generatedSrcDir/$schemaFile");
|
||||
|
||||
inputs.files fileTree(dir: codegenDir)
|
||||
inputs.files fileTree(dir: jsRootDir)
|
||||
outputs.file(schemaOutputFile)
|
||||
|
||||
def execCommands = ["yarn"] + nodeExecutableAndArgs + [
|
||||
codegenGenerateSchemaCli,
|
||||
"$schemaOutputFile",
|
||||
jsRootDir,
|
||||
];
|
||||
commandLine execCommands
|
||||
|
||||
ext.schema = {
|
||||
schemaOutputFile
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Generate Java code from schema
|
||||
task generateCodegenArtifactsFromSchema(dependsOn: 'generateCodegenSchemaFromJavaScript', type: Exec) {
|
||||
|
||||
def generatedSchema = tasks.generateCodegenSchemaFromJavaScript.schema();
|
||||
def javaPackageName = config.codegenJavaPackageName ?: "com.facebook.fbreact.specs.beta";
|
||||
def javaPackageDir = javaPackageName.replace(".", "/");
|
||||
def outputDir = file("$generatedSrcDir/java/$javaPackageDir");
|
||||
|
||||
inputs.files fileTree(dir: codegenDir)
|
||||
inputs.files generatedSchema
|
||||
outputs.dir(outputDir)
|
||||
|
||||
def execCommands = ["yarn"] + nodeExecutableAndArgs + [
|
||||
codegenGenerateNativeModuleSpecsCli,
|
||||
"android",
|
||||
"$generatedSchema",
|
||||
"$outputDir",
|
||||
];
|
||||
commandLine execCommands
|
||||
}
|
||||
|
||||
// 4. add deps + srcs
|
||||
preBuild.dependsOn generateCodegenArtifactsFromSchema
|
||||
|
||||
android {
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs += "$generatedSrcDir/java"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -19,5 +19,7 @@ gradlePlugin {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.tools.build:gradle:3.5.3'
|
||||
implementation 'com.google.guava:guava:29.0-jre'
|
||||
implementation 'com.squareup:javapoet:1.13.0'
|
||||
}
|
||||
|
@ -7,31 +7,137 @@
|
||||
|
||||
package com.facebook.react.codegen.plugin;
|
||||
|
||||
import com.facebook.react.codegen.generator.JavaGenerator;
|
||||
import java.io.IOException;
|
||||
import com.android.build.gradle.BaseExtension;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import java.io.File;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.Exec;
|
||||
|
||||
/** A Gradle plugin to enable code generation from JavaScript in Gradle environment. */
|
||||
/**
|
||||
* A Gradle plugin to enable react-native-codegen in Gradle environment. See the Gradle API docs for
|
||||
* more information: https://docs.gradle.org/6.5.1/javadoc/org/gradle/api/Project.html
|
||||
*/
|
||||
public class CodegenPlugin implements Plugin<Project> {
|
||||
|
||||
public void apply(final Project project) {
|
||||
// Register a task
|
||||
final CodegenPluginExtension extension =
|
||||
project.getExtensions().create("react", CodegenPluginExtension.class, project);
|
||||
|
||||
// 1. Set up build dir.
|
||||
final File generatedSrcDir = new File(project.getBuildDir(), "generated/source/codegen");
|
||||
final File generatedSchemaFile = new File(generatedSrcDir, "schema.json");
|
||||
|
||||
// 2. Task: produce schema from JS files.
|
||||
project
|
||||
.getTasks()
|
||||
.register(
|
||||
"generateJava",
|
||||
"generateCodegenSchemaFromJavaScript",
|
||||
Exec.class,
|
||||
task -> {
|
||||
task.doLast(
|
||||
if (!extension.enableCodegen) {
|
||||
return;
|
||||
}
|
||||
|
||||
task.doFirst(
|
||||
s -> {
|
||||
if (System.getenv("USE_CODEGEN").isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JavaGenerator generator = new JavaGenerator("", "");
|
||||
generator.build();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
generatedSrcDir.delete();
|
||||
generatedSrcDir.mkdirs();
|
||||
});
|
||||
|
||||
task.getInputs()
|
||||
.files(project.fileTree(ImmutableMap.of("dir", extension.codegenDir())));
|
||||
task.getInputs()
|
||||
.files(
|
||||
project.fileTree(
|
||||
ImmutableMap.of(
|
||||
"dir",
|
||||
extension.jsRootDir,
|
||||
"includes",
|
||||
ImmutableList.of("**/*.js"))));
|
||||
task.getOutputs().file(generatedSchemaFile);
|
||||
|
||||
ImmutableList<String> execCommands =
|
||||
new ImmutableList.Builder<String>()
|
||||
.add("yarn")
|
||||
.addAll(ImmutableList.copyOf(extension.nodeExecutableAndArgs))
|
||||
.add(extension.codegenGenerateSchemaCLI().getAbsolutePath())
|
||||
.add(generatedSchemaFile.getAbsolutePath())
|
||||
.add(extension.jsRootDir.getAbsolutePath())
|
||||
.build();
|
||||
task.commandLine(execCommands);
|
||||
});
|
||||
|
||||
// 3. Task: generate Java code from schema.
|
||||
project
|
||||
.getTasks()
|
||||
.register(
|
||||
"generateCodegenArtifactsFromSchema",
|
||||
Exec.class,
|
||||
task -> {
|
||||
if (!extension.enableCodegen) {
|
||||
return;
|
||||
}
|
||||
|
||||
task.dependsOn("generateCodegenSchemaFromJavaScript");
|
||||
|
||||
// TODO: The codegen tool should produce this outputDir structure based on
|
||||
// the provided Java package name.
|
||||
File outputDir =
|
||||
new File(
|
||||
generatedSrcDir,
|
||||
"java/" + extension.codegenJavaPackageName.replace(".", "/"));
|
||||
|
||||
task.getInputs()
|
||||
.files(project.fileTree(ImmutableMap.of("dir", extension.codegenDir())));
|
||||
task.getInputs().files(generatedSchemaFile);
|
||||
task.getOutputs().dir(outputDir);
|
||||
|
||||
ImmutableList<String> execCommands =
|
||||
new ImmutableList.Builder<String>()
|
||||
.add("yarn")
|
||||
.addAll(ImmutableList.copyOf(extension.nodeExecutableAndArgs))
|
||||
.add(extension.codegenGenerateNativeModuleSpecsCLI().getAbsolutePath())
|
||||
.add("android")
|
||||
.add(generatedSchemaFile.getAbsolutePath())
|
||||
.add(outputDir.getAbsolutePath())
|
||||
.build();
|
||||
task.commandLine(execCommands);
|
||||
});
|
||||
|
||||
// 4. Add dependencies & generated sources to the project.
|
||||
// Note: This last step needs to happen after the project has been evaluated.
|
||||
project.afterEvaluate(
|
||||
s -> {
|
||||
if (!extension.enableCodegen) {
|
||||
return;
|
||||
}
|
||||
|
||||
// `preBuild` is one of the base tasks automatically registered by Gradle.
|
||||
// This will invoke the codegen before compiling the entire project.
|
||||
Task preBuild = project.getTasks().findByName("preBuild");
|
||||
if (preBuild != null) {
|
||||
preBuild.dependsOn("generateCodegenArtifactsFromSchema");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally, update the android configuration to include the generated sources. This
|
||||
* equivalent to this DSL:
|
||||
*
|
||||
* <p>android { sourceSets { main { java { srcDirs += "$generatedSrcDir/java" } } } }
|
||||
*
|
||||
* <p>See documentation at
|
||||
* https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.BaseExtension.html.
|
||||
*/
|
||||
BaseExtension android = (BaseExtension) project.getExtensions().getByName("android");
|
||||
android
|
||||
.getSourceSets()
|
||||
.getByName("main")
|
||||
.getJava()
|
||||
.srcDir(new File(generatedSrcDir, "java"));
|
||||
// TODO: Add JNI sources.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.codegen.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import org.gradle.api.Project;
|
||||
|
||||
public class CodegenPluginExtension {
|
||||
// TODO: Remove beta.
|
||||
public String codegenJavaPackageName = "com.facebook.fbreact.specs.beta";
|
||||
public boolean enableCodegen;
|
||||
public File jsRootDir;
|
||||
public String[] nodeExecutableAndArgs = {"node"};
|
||||
public File reactNativeRootDir;
|
||||
|
||||
public CodegenPluginExtension(Project project) {
|
||||
this.reactNativeRootDir = new File(project.getRootDir(), "node_modules/react-native");
|
||||
}
|
||||
|
||||
public File codegenDir() {
|
||||
return new File(this.reactNativeRootDir, "packages/react-native-codegen");
|
||||
}
|
||||
|
||||
public File codegenGenerateSchemaCLI() {
|
||||
return new File(this.codegenDir(), "lib/cli/combine/combine-js-to-schema-cli.js");
|
||||
}
|
||||
|
||||
public File codegenGenerateNativeModuleSpecsCLI() {
|
||||
return new File(this.reactNativeRootDir, "scripts/generate-native-modules-specs-cli.js");
|
||||
}
|
||||
}
|
@ -5,6 +5,14 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenLocal()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'react-native-codegen'
|
||||
|
||||
include(":generator")
|
||||
|
@ -349,6 +349,3 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply(from: "$rootDir/architecture.gradle");
|
||||
generateNativeArtifactsFromJavaScript(project.react);
|
||||
|
@ -5,6 +5,14 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
mavenLocal()
|
||||
google()
|
||||
}
|
||||
}
|
||||
|
||||
include(
|
||||
":ReactAndroid",
|
||||
":RNTester:android:app"
|
||||
|
Loading…
Reference in New Issue
Block a user