Skip to content

Commit 9c4e9bc

Browse files
authored
feat: add rnbrownfield-gradle-plugin (#89)
1 parent bf5312d commit 9c4e9bc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3076
-1
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cd ./gradle-plugins/react && ./gradlew build || exit 1
2+
./gradlew :brownfield:publishToMavenLocal

gradle-plugins/react/.gitattributes

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# https://help.github.com/articles/dealing-with-line-endings/
3+
#
4+
# Linux start script should use lf
5+
/gradlew text eol=lf
6+
7+
# These are Windows script files and should use crlf
8+
*.bat text eol=crlf
9+

gradle-plugins/react/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignore Gradle project-specific cache directory
2+
.gradle
3+
4+
# Ignore Gradle build output directory
5+
build

gradle-plugins/react/README.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
### React Native Brownfield Gradle Plugin
2+
3+
This plugin helps you convert your react-native brownfield implementation into a fat Aar.
4+
5+
#### Installation
6+
7+
##### From Remote
8+
9+
- TBA
10+
11+
##### From Local
12+
13+
- From the root of this repository, run `yarn brownfield:plugin:publish:local` and it will publish the plugin to your local maven
14+
- Then add the following patch to your react-native brownfield `build.gradle` files:
15+
16+
```diff
17+
diff --git a/android/build.gradle b/android/build.gradle
18+
index 3dd1ac9..0db4ded 100644
19+
--- a/android/build.gradle
20+
+++ b/android/build.gradle
21+
@@ -16,6 +16,7 @@ buildscript {
22+
}
23+
+ mavenLocal()
24+
google()
25+
mavenCentral()
26+
}
27+
@@ -23,7 +24,7 @@ buildscript {
28+
classpath("com.android.tools.build:gradle")
29+
classpath("com.facebook.react:react-native-gradle-plugin")
30+
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
31+
+ classpath("com.callstack.react:brownfield:0.1.0")
32+
}
33+
}
34+
35+
diff --git a/android/rnbrownfield/build.gradle.kts b/android/rnbrownfield/build.gradle.kts
36+
index b915003..e387075 100644
37+
--- a/android/rnbrownfield/build.gradle.kts
38+
+++ b/android/rnbrownfield/build.gradle.kts
39+
@@ -1,7 +1,7 @@
40+
plugins {
41+
id("com.android.library")
42+
id("org.jetbrains.kotlin.android")
43+
+ id("com.callstack.react.brownfield")
44+
`maven-publish`
45+
id("com.facebook.react")
46+
}
47+
@@ -10,8 +10,8 @@ react {
48+
autolinkLibrariesWithApp()
49+
}
50+
51+
val appProject = project(":app")
52+
```
53+
54+
#### API Usage
55+
56+
- **About Dependencies**
57+
58+
You can `embed` dependencies in your Aar by using this configuration. It is as simple as doing the following:
59+
60+
```kts
61+
dependencies {
62+
embed("com.facebook.react:hermes-android:0.77.0")
63+
embed("com.google.android.material:material:0.7.0")
64+
}
65+
```
66+
67+
The `embed` configuration is useful, only if you want to bundle these dependencies within your fat Aar. Be careful that it can result in clashes between the bundled version of a dependency and the version used by the App. What this means is consider you embedded dependencyA with version 0.0.1 and the native App which will use your Aar also uses dependencyA but with version 0.0.2, it will produce a clash.
68+
69+
If you are sure that the native App will never use the dependency you have embedded within your Aar, you should be fine with using `embed`. But if you know before hand that those dependencies can be used by the native App then it's better for you to avoid embedding and instead use either of `implementation` and `compileOnly` configuration and surface it with the native team that the Aar relies on the App to provide these dependencies.
70+
71+
When you use `implementation` or `compileOnly`, this plugin does not bundle those dependencies in your Aar and instead just uses them to provide for the compile time. Using these configuration is as simple as:
72+
73+
```kts
74+
dependencies {
75+
implementation("com.facebook.react:hermes-android:0.77.0")
76+
compileOnly("com.google.android.material:material:0.7.0")
77+
}
78+
```
79+
80+
There is one more configuration called `api` and it is often the one you should use. The reason is that this configuration tells gradle to provide for these dependencies in compile time while developing and also provide these when the generated Aar is consumed by the native App. For the latter, you will need to use it in combination with `pom.xml` as the latter will only work if you have dependencies marked with `api` listed in `pom.xml`.
81+
82+
```kts
83+
api("com.facebook.react:react-android:0.77.0")
84+
api("com.facebook.react:hermes-android:0.77.0")
85+
implementation("com.google.android.material:material:0.7.0")
86+
```
87+
88+
In react-native brownfield, when we want to use `react-android` and `hermes-android` in the Aar, we can use `api` to allow us developing and also tell gradle to provide these dependencies and it's transitive ones as well, using `pom.xml`. If the native App uses one of the transitive dependency say `javax.inject`, gradle will automatically pick the highest version. This is often the ideal usage scenario where we don't want the native App team to worry about react-native's dependencies and transitive dependencies.
89+
90+
<hr/>
91+
92+
We can use `exclude` to not embed a nested dependency:
93+
94+
```kts
95+
dependencies {
96+
embed("com.facebook.fbjni:fbjni:0.4.0") {
97+
exclude("com.facebook.soloader")
98+
}
99+
}
100+
```
101+
102+
<hr/>
103+
104+
#### Tooling
105+
106+
- We are using `ktlint` and `detekt` for formatting and linting
107+
- You can run `./gradlew :brownfield:lint` to auto-format and detect linting issues
108+
109+
110+
#### Architecture
111+
112+
Below is a flow diagram of how the files are being used in this gradle plugin from an overview:
113+
114+
![react-brownfield-architecture](../../screenshots/react-brownfield-arch.png)
115+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
plugins {
2+
alias(libs.plugins.kotlinJvm)
3+
`java-gradle-plugin`
4+
alias(libs.plugins.ktlint)
5+
alias(libs.plugins.detekt)
6+
`maven-publish`
7+
}
8+
9+
ktlint {
10+
debug.set(false)
11+
verbose.set(true)
12+
android.set(false)
13+
outputToConsole.set(true)
14+
ignoreFailures.set(false)
15+
enableExperimentalRules.set(true)
16+
17+
filter {
18+
exclude("**/generated/**")
19+
include("**/kotlin/**")
20+
}
21+
}
22+
23+
detekt {
24+
toolVersion = libs.versions.detekt.get()
25+
config.setFrom(file("config/detekt/detekt.yml"))
26+
buildUponDefaultConfig = true
27+
}
28+
29+
group = property("GROUP").toString()
30+
version = property("VERSION").toString()
31+
32+
gradlePlugin {
33+
plugins {
34+
create("reactBrownfieldGradlePlugin") {
35+
id = property("PROJECT_ID").toString()
36+
implementationClass = property("IMPLEMENTATION_CLASS").toString()
37+
}
38+
}
39+
}
40+
41+
publishing {
42+
publications.withType<MavenPublication>().configureEach {
43+
artifactId = property("ARTIFACT_ID").toString()
44+
}
45+
}
46+
47+
repositories {
48+
mavenCentral()
49+
google()
50+
}
51+
52+
dependencies {
53+
implementation(libs.agp)
54+
implementation(libs.common)
55+
implementation(libs.asm.commons)
56+
}
57+
58+
tasks.named("detekt").configure {
59+
dependsOn(":ktlintFormat")
60+
}
61+
62+
tasks.register("lint") {
63+
dependsOn(":ktlintFormat")
64+
}

0 commit comments

Comments
 (0)