第5条:共享的 libs.versions.toml 的冒险
发布于 27 September 2025
介绍
在我们创建插件的追求中`site-baker`我们一直致力于保持代码库的整洁和集中化。现代 Gradle 生态系统中最佳实践之一是使用版本目录(libs.versions.toml) 用于管理依赖项。但是当你的项目变得更复杂时,会发生什么情况,例如一个构建复合在哪里需要将一个独立的构建(我们的插件)包含在另一个构建中?
正是在这里,我们的冒险迎来了意想不到的转折。我们希望我们的插件`site-baker`, 它本身是一个 Gradle 项目,使用与我们主项目相同的版本目录。本文是我们系列的第五篇,讲述了我们如何解决了这个挑战。
1. 版本目录 (libs.versions.toml) : 一个提醒
文件`gradle/libs.versions.toml`是Gradle的一项功能,用于集中管理项目依赖的版本和坐标。它通常被结构为四个部分:
-
[versions]: 为版本号定义别名(例如:kotlin = "1.9.20"). -
[libraries]`定义完整依赖项的别名,使用上面定义的版本 (例如:`kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }). -
[bundles]: 将多个库归组到一个别名下 (ex:`jackson = ["jackson-core", "jackson-databind"]`). -
[plugins]: 为 Gradle 插件设置别名。
一旦定义,Gradle 会自动生成类型化的访问器,这使得您的`build.gradle.kts`更易读:
dependencies {
// Au lieu de : implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
implementation(libs.kotlin.stdlib)
}
@startuml !theme plain file "gradle/libs.versions.toml" as Toml node "Gradle" as G file "build.gradle.kts" as BuildScript Toml --> G : "被读取" G --> BuildScript : "生成访问器 `libs`" BuildScript -> G : "使用 `libs` 声明依赖" @enduml
2. 问题:复合构建与两个独立的世界
我们的项目结构是一个构建复合体. 主要项目 (thymeleaf.cheroliv.com) 包含插件项目 (site-baker) 通过命令`includeBuild("site-baker")在文件中`settings.gradle.kts.
@startuml
!theme plain
package "主要项目" {
file "settings.gradle.kts" as MainSettings
folder "gradle" {
file "libs.versions.toml" as MainToml
}
}
package "插件 `site-baker` (内部构建)" {
file "settings.gradle.kts" as PluginSettings
file "build.gradle.kts" as PluginBuild
}
MainSettings -> PluginSettings : `includeBuild("site-baker")`
PluginBuild ..> MainToml : 想要访问...
note right on link: ...但做不到!
@enduml
问题是,默认情况下,一个包含的构建是一个独立的世界. 它有自己的配置,自己的生命周期,并且它看不到该文件`libs.versions.toml`主构建。 我们的`plugin/build.gradle.kts`试图使用`libs.plugins.kotlin.jvm`, 但该对象`libs`它不是从正确的 TOML 文件生成的,导致构建错误。
3. 解决方案:共享依赖解析
经过多次研究,解决方案被证明是Gradle专为这种情况设计的功能:dependencyResolutionManagement。
在文件中`settings.gradle.kts` du 构建包容(site-baker/settings.gradle.kts), 我们可以告诉 Gradle 在哪里找到要使用的版本目录。
以下是我们添加的配置`site-baker/settings.gradle.kts`:
// site-baker/settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
gradlePluginPortal()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "site-baker"
include("plugin")
让我们分析关键部分 :
versionCatalogs {
create("libs") { // Crée un catalogue nommé 'libs'
from(files("../gradle/libs.versions.toml")) // En utilisant ce fichier
}
}
-
create("libs"): 我们声明一个版本目录,将可通过别名访问`libs`。 -
from(files("../gradle/libs.versions.toml")): 这就是魔法。我们告诉 Gradle 此目录的来源是位于该目录下的 TOML 文件`gradle` du 父项目(
</think> (../)
使用此配置,构建`site-baker`现在他知道他必须使用主项目的版本目录。对象`libs`已正确生成,并且依赖关系按预期解决。
4. 结论:管理良好的组合构建的力量
这段经历非常充实。版本目录是提高可维护性的绝佳工具,但在复合构建场景中的行为并不总是直观。
关键是要记住,被包含的构建仍然是一个独立的构建。要共享诸如版本目录之类的配置,必须使用 Gradle 提供的显式机制,例如代码块。dependencyResolutionManagement`在`settings.gradle.kts.
通过解决此问题,我们不仅使构建更加整洁,还增强了项目的一致性,确保插件和主项目共享唯一的事实来源来管理它们的依赖项。
相关文章
31 May 2026
14 May 2026
12 May 2026