Support Kotlin JS targets in Compose Gradle plugin

This commit is contained in:
Alexey Tsvetkov
2021-04-28 12:24:50 +03:00
committed by Alexey Tsvetkov
parent cab2ac642e
commit 7a47ba8dd8
8 changed files with 147 additions and 9 deletions

View File

@@ -17,4 +17,6 @@ object BuildProperties {
fun deployVersion(project: Project): String =
System.getenv("COMPOSE_GRADLE_PLUGIN_VERSION")
?: project.findProperty("deploy.version") as String
fun isComposeWithWeb(project: Project): Boolean =
project.findProperty("compose.with.web") == "true"
}

View File

@@ -25,6 +25,7 @@ buildConfig {
packageName = "org.jetbrains.compose"
clsName = "ComposeBuildConfig"
buildConfigField("String", "composeVersion", BuildProperties.composeVersion(project))
buildConfigField("Boolean", "isComposeWithWeb", BuildProperties.isComposeWithWeb(project).toString())
}
val embedded by configurations.creating

View File

@@ -6,23 +6,48 @@
package org.jetbrains.compose
import org.gradle.api.provider.Provider
import org.jetbrains.compose.internal.webExt
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
class ComposeCompilerKotlinSupportPlugin : KotlinCompilerPluginSupportPlugin {
override fun getCompilerPluginId(): String =
"org.jetbrains.compose"
"androidx.compose.compiler.plugins.kotlin"
override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean {
val targetPlatform = kotlinCompilation.target.platformType
return targetPlatform != KotlinPlatformType.js
&& targetPlatform != KotlinPlatformType.native
override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean =
when (kotlinCompilation.target.platformType) {
KotlinPlatformType.common -> true
KotlinPlatformType.jvm -> true
KotlinPlatformType.js -> isApplicableJsTarget(kotlinCompilation.target)
KotlinPlatformType.androidJvm -> true
KotlinPlatformType.native -> false
}
override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
val target = kotlinCompilation.target
return target.project.provider {
platformPluginOptions[target.platformType] ?: emptyList()
}
}
override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> =
kotlinCompilation.target.project.provider { emptyList() }
override fun getPluginArtifact(): SubpluginArtifact =
SubpluginArtifact(
groupId = "org.jetbrains.compose.compiler", artifactId = "compiler", version = composeVersion
)
private fun isApplicableJsTarget(kotlinTarget: KotlinTarget): Boolean {
if (kotlinTarget !is KotlinJsIrTarget) return false
val project = kotlinTarget.project
val webExt = project.webExt ?: return false
return kotlinTarget in webExt.targetsToConfigure(project)
}
private val platformPluginOptions = mapOf(
KotlinPlatformType.js to options("generateDecoys" to "true")
)
private fun options(vararg options: Pair<String, String>): List<SubpluginOption> =
options.map { SubpluginOption(it.first, it.second) }
}

View File

@@ -16,6 +16,7 @@ import org.jetbrains.compose.desktop.DesktopExtension
import org.jetbrains.compose.desktop.application.internal.configureApplicationImpl
import org.jetbrains.compose.desktop.application.internal.currentTarget
import org.jetbrains.compose.desktop.preview.internal.initializePreview
import org.jetbrains.compose.web.internal.initializeWeb
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -37,8 +38,11 @@ class ComposePlugin : Plugin<Project> {
}
project.initializePreview()
if (ComposeBuildConfig.isComposeWithWeb) {
project.initializeWeb(composeExtension)
}
project.pluginManager.apply(ComposeCompilerKotlinSupportPlugin::class.java)
project.plugins.apply(ComposeCompilerKotlinSupportPlugin::class.java)
project.afterEvaluate {
if (desktopExtension._isApplicationInitialized) {
@@ -112,6 +116,9 @@ class ComposePlugin : Plugin<Project> {
val runtime get() = composeDependency("org.jetbrains.compose.runtime:runtime")
val ui get() = composeDependency("org.jetbrains.compose.ui:ui")
val materialIconsExtended get() = composeDependency("org.jetbrains.compose.material:material-icons-extended")
val web: WebDependencies =
if (ComposeBuildConfig.isComposeWithWeb) WebDependencies
else error("This version of Compose plugin does not support 'compose.web.*' dependencies")
}
object DesktopDependencies {
@@ -141,6 +148,12 @@ class ComposePlugin : Plugin<Project> {
composeDependency("org.jetbrains.compose.desktop:desktop-jvm-${currentTarget.id}")
}
}
object WebDependencies {
val web by lazy {
composeDependency("org.jetbrains.compose.web:web")
}
}
}
fun KotlinDependencyHandler.compose(groupWithArtifact: String) = composeDependency(groupWithArtifact)

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.internal
import org.gradle.api.Project
import org.jetbrains.compose.ComposeExtension
import org.jetbrains.compose.web.WebExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
internal val Project.composeExt: ComposeExtension?
get() = extensions.findByType(ComposeExtension::class.java)
internal val Project.webExt: WebExtension?
get() = composeExt?.extensions?.findByType(WebExtension::class.java)
internal val Project.mppExt: KotlinMultiplatformExtension?
get() = extensions.findByType(KotlinMultiplatformExtension::class.java)

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.web
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.jetbrains.compose.internal.mppExt
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
abstract class WebExtension : ExtensionAware {
private var requestedTargets: Set<KotlinJsIrTarget>? = null
private var targetsToConfigure: Set<KotlinJsIrTarget>? = null
// public api
@Suppress("unused")
fun targets(vararg targets: KotlinTarget) {
check(requestedTargets == null) {
"compose.web.targets() was already set!"
}
val jsIrTargets = linkedSetOf<KotlinJsIrTarget>()
for (target in targets) {
check(target is KotlinJsIrTarget) {
"""|'${target.name}' is not a JS(IR) target:
|* add `kotlin.js.compiler=ir` to gradle properties;
|* define target as `kotlin { js(IR) { ... } }`
""".trimMargin()
}
jsIrTargets.add(target)
}
requestedTargets = jsIrTargets
}
internal fun targetsToConfigure(project: Project): Set<KotlinJsIrTarget> {
targetsToConfigure =
targetsToConfigure
?: requestedTargets
?: defaultJsTargetsToConfigure(project)
return targetsToConfigure!!
}
private fun defaultJsTargetsToConfigure(project: Project): Set<KotlinJsIrTarget> {
val mppTargets = project.mppExt?.targets?.asMap?.values ?: emptySet()
val jsIRTargets = mppTargets.filterIsInstanceTo(LinkedHashSet<KotlinJsIrTarget>())
return if (jsIRTargets.size > 1) {
project.logger.error(
"w: Default configuration for Compose Web is disabled: " +
"multiple Kotlin JS IR targets are defined. " +
"Specify Compose Web Kotlin targets by using `compose.web.targets()`"
)
emptySet()
} else jsIRTargets
}
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.web.internal
import org.gradle.api.Project
import org.jetbrains.compose.ComposeExtension
import org.jetbrains.compose.web.WebExtension
internal fun Project.initializeWeb(composeExtension: ComposeExtension) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
composeExtension.extensions.create("web", WebExtension::class.java)
}
}

View File

@@ -7,6 +7,7 @@ kotlin.code.style=official
#
# __LATEST_COMPOSE_RELEASE_VERSION__
compose.version=0.4.0-build182
compose.with.web=false
# A version of Gradle plugin, that will be published,
# unless overridden by COMPOSE_GRADLE_PLUGIN_VERSION env var.