Разобрался в этом вопросе полностью, почему так происходит в композитном проекте и всё заставить работать.
Первое на что обратил внимание - это почему проблемы не возникает с аддоном темы? Это объясняется тем, что у аддона с темой и “функционального” аддона разные шаблоны, которые прописывают в build.gradle
разные плагины. У аддона с темой указан плагин java
, а у “функционального” java-library
- и по факту именно в этом проблема.
Если почитать описание в документации gradle на The Java Library Plugin, то можно найти такое:
A feature of the java-library plugin is that projects which consume the library only require the classes folder for compilation, instead of the full JAR.
То есть, если мы в аддоне используем плагин java-library
, то потребители этого аддона, в нашем случае проект demo, просто использует скомпилированные классы этого аддона (из папки с классами), вместо того, чтобы “тащить” JAR-архив.
А путь то к стилям прописыватся именно в процессе сборки jar, в манифесте:
jar.manifest {
attributes(['Vaadin-Stylesheets': 'VAADIN/addons/asup-reference/asup-reference.scss'])
}
Подебажить это можно взяв исходники jmix
плагина для gradle. Там можно найти класс ThemeCompile
и в нём (среди прочих) пару методов (collectAddonIncludes
- который собирает стили из аддонов, и walkDependencies
- который рекурсивно шарится по зависимостям) и в walkDependencies
увидим такую проверку:
if (artifact.getFile().getName().endsWith(".jar")) {
artifactAction.accept(artifact); // Consumer который извлекёт стили
}
Вокруг можно добавить пару выводов в консоль и увидеть из каких аддонов темы извлекаются, а из каких нет.
То есть, если артифакт не являеться JAR’ом, то ничего не происходит, и стили не извлекаются. А так как аддон использует плагин java-library
, то (по умолчанию) в композитном проекте потребители в качестве артефактов берут скомпилированные классы, а не jar.
Поэтому когда аддон исключается из композитного проекта и загружается из репозитория, то тут уж, конечно, артифактом являеться JAR-файл и всё работает.
Чтобы в композитном проекте заставить аддон работать, есть два решения:
-
Использовать в аддоне плагин java
вместо java-library
. Но тут, из минусов, например, то что не получиться использовать конфигурацию api()
, потому что она есть только в java-library
.
-
“Заставить” потребителя тащить JAR вместо классов. Подглядел тут, но там с ошибкой, решение ниже исправленное. Для этого в build.gradle
проекта можно указать, что для всех зависимостей, которые включены к compileClasspath
в качестве артифакта нужно брать JAR:
configurations.compileClasspath {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, project.objects.named(LibraryElements, LibraryElements.JAR))
}
}
Думаю можно сделать и более тонкую настройку - указать для каких аддонов брать jar, а для каких классы.
Тут тоже есть минусы. Из тех что увидел - это ошибка о том что нет jar-файла аддона. Она появляеться если очистить билд (gradle clean
), что логично, ведь мы удалили jar. При последующих сборках ошибка не появляется, но не знаю, будут ли ещё какие-то побочные эффекты.
Так же у меня был вопрос про транзитивные зависимости на аддоны и стили из них.
Допустим, в проекте demo
используется addon2
, который в свою очередь использует addon1
с UI компонентами и стилями для них. Хотелось бы, добавив в demo
зависимость только на addon2
получить и стили addon1
, чтобы UI компоненты выглядили корректно.
В документации gradle написано следующее:
Dependencies appearing in the api configurations will be transitively exposed to consumers of the library, and as such will appear on the compile classpath of consumers. Dependencies found in the implementation configuration will, on the other hand, not be exposed to consumers, and therefore not leak into the consumers’ compile classpath.
То есть, если в addon2
добавить зависимость на addon1
в конфигурацию implementation
, то ничего не получиться, нужно использовать api
.
dependencies {
api 'my.company:addon1-starter:0.0.1'
}
В demo
зависимость на addon2
можно добавить уже в implementation
.
Таким образом addon1
попадёт в compileClasspath demo
проекта, где задача compileThemes
его сможет найти и добавить стили из addon1
.
Получается, что в addon1
нужно использовать плагин java-library
для gradle, а demo
настроить так, чтобы он тащил jar-файлы для своих зависимостей (как я описал вше в решение 2).
Однако тут появляется другая проблема. Так как мы “заставили” demo
тащить jar-файлы в качестве артефакта аддона, то при изменении стилей в аддоне теперь, перед вызовом compileThemes
, нужно собрать новые jar’ы.
Эту задачу можно упростить, добавив в build.gradle
композитного проекта новый task для компиляции темы (и запускать его):
task compileDemoThemes {
dependsOn gradle.includedBuild('addon1-addon').task(':addon1:jar')
dependsOn gradle.includedBuild('addon2-addon').task(':addon2:jar')
dependsOn gradle.includedBuild('demo').task(':compileThemes')
}
Вероятно, описанные выше решения не оптимальны, и у них точно есть минусы, которые, в принципе, описаны в документации на gradle, но надеюсь кому-то ещё это пригодиться. Мне пригодилось, выходные убиты не в пустую).