Skip to content

Commit

Permalink
updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Morfly committed Dec 11, 2023
1 parent 4084b33 commit 989df0b
Showing 1 changed file with 116 additions and 0 deletions.
116 changes: 116 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ airin {
include<JetpackComposeFeature>()
include<HiltFeature>()
include<ParcelizeFeature>()
...
}
register<JvmLibraryModule>()

Expand Down Expand Up @@ -220,8 +221,123 @@ abstract class JetpackComposeFeature : FeatureComponent() {
`onInvoke` is invoked during the Gradle Execution phase and contains the main logic of the component. Its purpose is to modify Bazel files generated by a related module component as well as manage the dependencies of the module.

### Dependency overrides
When migrating Gradle modules to Bazel, an obvious task is to preserve a correct dependency graph including internal module dependencies and third-party artifacts. As it turns out, the same module might have a different set of dependencies in Gradle and Bazel.

To address such scenarios, feature components offer dependency override API.

```kotlin
// FeatureComponent.onInvoke
onDependency(MavenCoordinates("com.google.dagger", "hilt-android")) {
overrideWith(BazelLabel(path = "", target = "hilt-android"))
}
```
In addition, you can ignore certain Gradle dependencies in Bazel by leaving the `onDependency` block empty.
```kotlin
// FeatureComponent.onInvoke
onDependency(MavenCoordinates("com.google.dagger", "hilt-android")) {
// ignored
}
```

### Configuration overrides
When setting up a Gradle module, it involves not only specifying dependencies but also assigning them to a specific **configuration**, providing instructions to Gradle on how to treat each dependency.
```kotlin
// build.gradle.kts
dependencies {
implementation(...)
api(...)
ksp(...)
...
}
```
In Bazel, targets are declared using function calls. As an analogue to Gradle configurations, we use specific function parameters for various types of dependencies.
```python
# BUILD.bazel
kt_android_library(
...
deps = [...],
exports = [...],
plugins = [...],
)
```
Similar to dependency overrides, feature components also allow the overriding of configurations. In the example below, all `implementation` dependencies will be declared as `deps` in Bazel.

```kotlin
// FeatureComponent.onInvoke
onConfiguration("implementation") {
overrideWith("deps")
}
```
For exporting transitive dependencies, `deps` and `exports` are used as an equivalent to Gradle’s `api` configuration.
```kotlin
// FeatureComponent.onInvoke
onConfiguration("api") {
overrideWith("deps")
overrideWith("exports")
}
```

### File modifiers
Beyond handling dependencies, feature components can also make contributions to the Bazel files generated by module components.

Let’s revisit the code snippet from the `AndroidLibraryModule` component that we used in the [module components](#module-components) section, but this time, let’s make a slight update to it.
```kotlin
// ModuleComponent.onInvoke
val file = BUILD.bazel {
_id = "build_file"

load("@io_bazel_rules_kotlin//kotlin:android.bzl", "kt_android_library")

kt_android_library {
_id = "android_library_target"

name = module.name
srcs = glob("src/main/**/*.kt")
custom_package = module.androidMetadata?.packageName
manifest = "src/main/AndroidManifest.xml"
resource_files = glob("src/main/res/**")
for ((config, deps) in module.dependencies) {
config `=` deps.map { it.asBazelLabel().toString() }
}
}
}
```

A notable addition here is the introduction of `_id` fields. These can be defined within any code block enclosed by curly brackets `{}`. Once defined, you gain the flexibility to edit the contents of these code blocks externally.

Let’s modify the contents of the generated Bazel file using our feature component. To achieve this, within the `onInvoke` function, use the `onContext` call, specifying the type of the context to be modified, along with its identifier.

```kotlin
// FeatureComponent.onInvoke
onContext<BuildContext>(id = "build_file") {
`package`(default_visibility = list["//visibility:public"])
}


onContext<KtAndroidLibraryContext>(id = "android_library_target") {
enable_data_binding = true
}
```
As a result, when the `AndroidLibraryModule` component is invoked, it will incorporate all the modifications, including the added `enable_data_binding` argument, as well as the top-level `package` function call.

```python
load("@io_bazel_rules_kotlin//kotlin:android.bzl", "kt_android_library")
load("@rules_jvm_external//:defs.bzl", "artifact")

kt_android_library(
name = "my-library",
srcs = glob(["src/main/**/*.kt"]),
custom_package = "com.turo.mylibrary",
manifest = "src/main/AndroidManifest.xml",
resource_files = glob(["src/main/res/**"]),
deps = [...],
enable_data_binding = True, # added by a feature component
)

# added by a feature component
package(default_visibility = ["//visibility:public"])
```

## Shared components
The purpose of shared components is to enable feature components to contribute into multiple module components.

Expand Down

0 comments on commit 989df0b

Please sign in to comment.