Skip to content

Commit a8774d3

Browse files
authored
Sh/cp 0922042 web compatibility skip when unavailable (#5395)
This is a cherry-pick of guard safety fixes for compatibility task 0922042 plus 34125bc (which is just a test - without which it would have been difficult to port 0922042) ## Release Notes N/A
2 parents db964f1 + 1b23aa9 commit a8774d3

File tree

49 files changed

+778
-84
lines changed

Some content is hidden

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

49 files changed

+778
-84
lines changed

gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/web/tasks/WebCompatibilityTask.kt

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,24 +133,20 @@ private fun Project.registerWebCompatibilityTask(mppPlugin: KotlinMultiplatformE
133133

134134
mppPlugin.targets.withType(KotlinJsIrTarget::class.java).configureEach { target ->
135135
if (target.platformType == KotlinPlatformType.wasm) {
136-
wasmOutputName.set(
137-
tasks.named(
138-
"${target.name}BrowserProductionWebpack",
139-
KotlinWebpack::class.java
140-
).flatMap { it.mainOutputFileName }
141-
)
136+
tasks.withType(KotlinWebpack::class.java).findByName("${target.name}BrowserProductionWebpack")?.let {
137+
wasmOutputName.set(it.mainOutputFileName)
138+
}
139+
142140
wasmDistFiles.from(
143-
tasks.named("${target.name}BrowserDistribution").map { it.outputs.files }
141+
tasks.matching { it.name == "${target.name}BrowserDistribution" }.map { it.outputs.files }
144142
)
145143
} else if (target.platformType == KotlinPlatformType.js) {
146-
jsOutputName.set(
147-
tasks.named(
148-
"${target.name}BrowserProductionWebpack",
149-
KotlinWebpack::class.java
150-
).flatMap { it.mainOutputFileName }
151-
)
144+
tasks.withType(KotlinWebpack::class.java).findByName("${target.name}BrowserProductionWebpack")?.let {
145+
jsOutputName.set(it.mainOutputFileName)
146+
}
147+
152148
jsDistFiles.from(
153-
tasks.named("${target.name}BrowserDistribution").map { it.outputs.files }
149+
tasks.matching { it.name == "${target.name}BrowserDistribution" }.map { it.outputs.files }
154150
)
155151
}
156152

gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/CompatibilityDistributionTest.kt

Lines changed: 0 additions & 66 deletions
This file was deleted.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package org.jetbrains.compose.test.tests.integration
2+
3+
import org.jetbrains.compose.test.utils.ChecksWrapper
4+
import org.jetbrains.compose.test.utils.GradlePluginTestBase
5+
import org.jetbrains.compose.test.utils.TestProject
6+
import org.jetbrains.compose.test.utils.checkExists
7+
import org.jetbrains.compose.test.utils.checks
8+
import org.junit.jupiter.api.Test
9+
import kotlin.test.assertEquals
10+
import kotlin.test.assertTrue
11+
12+
class WebCompatibilityDistributionTest : GradlePluginTestBase() {
13+
private val defaultDistDir = "./composeApp/build/dist/composeWebCompatibility/productionExecutable"
14+
15+
private fun TestProject.assertCompatibilityDistribution(
16+
dirPath: String,
17+
expectedFileNames: Set<String>
18+
) {
19+
file(dirPath).apply {
20+
checkExists()
21+
assertTrue(isDirectory, "Expected $dirPath to be a directory")
22+
23+
val listed = listFiles()
24+
?: error("Expected to list files in $dirPath but got null")
25+
val distributionNames = listed.map { it.name }
26+
27+
assertTrue(
28+
distributionNames.any { it.endsWith(".wasm") },
29+
"Expected at least one .wasm file in $dirPath, found: $distributionNames"
30+
)
31+
32+
val actualFiles = distributionNames.filterNot { it.endsWith(".wasm") }.toSet()
33+
assertEquals(expectedFileNames, actualFiles, "files mismatch in $dirPath")
34+
}
35+
}
36+
37+
private fun runTaskAndCheck(projectPath: String, taskName: String, onExecution: ChecksWrapper.(project: TestProject) -> Unit) {
38+
with(
39+
testProject(
40+
projectPath,
41+
testEnvironment = defaultTestEnvironment.copy()
42+
)
43+
) {
44+
gradle(taskName).checks {
45+
onExecution(this@with)
46+
}
47+
}
48+
}
49+
50+
private fun assertSuccessfulCompatibilityRun(
51+
projectPath: String,
52+
successfulTasks: List<String>,
53+
distDir: String = defaultDistDir,
54+
expectedFiles: Set<String>
55+
) {
56+
runTaskAndCheck(projectPath, ":composeApp:composeCompatibilityBrowserDistribution") { testProject ->
57+
check.taskSuccessful(":composeApp:composeCompatibilityBrowserDistribution")
58+
successfulTasks.forEach { check.taskSuccessful(it) }
59+
testProject.assertCompatibilityDistribution(dirPath = distDir, expectedFileNames = expectedFiles)
60+
}
61+
}
62+
63+
private fun assertSkippedCompatibilityRun(projectPath: String) {
64+
runTaskAndCheck(projectPath, ":composeApp:composeCompatibilityBrowserDistribution") {
65+
check.taskSkipped(":composeApp:composeCompatibilityBrowserDistribution")
66+
}
67+
}
68+
69+
@Test
70+
fun testWebJsWasm() = assertSuccessfulCompatibilityRun(
71+
projectPath = "application/webJsWasm",
72+
successfulTasks = listOf(
73+
":composeApp:jsBrowserDistribution",
74+
":composeApp:wasmJsBrowserDistribution"
75+
),
76+
expectedFiles = setOf(
77+
"composeApp.js",
78+
"composeResources",
79+
"index.html",
80+
"originJsComposeApp.js",
81+
"originJsComposeApp.js.map",
82+
"originWasmComposeApp.js",
83+
"originWasmComposeApp.js.map",
84+
"styles.css"
85+
)
86+
)
87+
88+
@Test
89+
fun testWebJsOnly() = assertSkippedCompatibilityRun(
90+
projectPath = "application/webJsOnly"
91+
)
92+
93+
@Test
94+
fun testWebWasmOnly() = assertSkippedCompatibilityRun(
95+
projectPath = "application/webWasmOnly"
96+
)
97+
98+
@Test
99+
fun testWebJsNonExecutable() = assertSkippedCompatibilityRun(
100+
projectPath = "application/webJsWasmNonExecutable"
101+
)
102+
103+
@Test
104+
fun testWebJsWasmNonStandard() = assertSuccessfulCompatibilityRun(
105+
projectPath = "application/webJsWasmNonStandard",
106+
successfulTasks = listOf(
107+
":composeApp:webJsBrowserDistribution",
108+
":composeApp:webWasmBrowserDistribution"
109+
),
110+
expectedFiles = setOf(
111+
"composeApp.js",
112+
"composeResources",
113+
"index.html",
114+
"originJsComposeApp.js",
115+
"originJsComposeApp.js.map",
116+
"originWasmComposeApp.js",
117+
"originWasmComposeApp.js.map",
118+
"styles.css"
119+
)
120+
)
121+
122+
@Test
123+
fun testWebJsWasmReconfigured() = assertSuccessfulCompatibilityRun(
124+
projectPath = "application/webJsWasmReconfigured",
125+
successfulTasks = listOf(
126+
":composeApp:wasmRepack",
127+
":composeApp:jsRepack"
128+
),
129+
expectedFiles = setOf(
130+
"composeResources",
131+
"index.html",
132+
"originJsRepackedApp.js",
133+
"originJsRepackedApp.js.map",
134+
"originWasmRepackedApp.js",
135+
"originWasmRepackedApp.js.map",
136+
"repackedApp.js",
137+
"styles.css"
138+
)
139+
)
140+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--install.mutex network
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
plugins {
2+
// this is necessary to avoid the plugins to be loaded multiple times
3+
// in each subproject's classloader
4+
id("org.jetbrains.kotlin.multiplatform") apply false
5+
id("org.jetbrains.compose") apply false
6+
id("org.jetbrains.kotlin.plugin.compose") apply false
7+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
2+
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
3+
4+
plugins {
5+
id("org.jetbrains.kotlin.multiplatform")
6+
id("org.jetbrains.compose")
7+
id("org.jetbrains.kotlin.plugin.compose")
8+
}
9+
10+
kotlin {
11+
js(IR) {
12+
outputModuleName.set("composeApp")
13+
browser {
14+
commonWebpackConfig {
15+
outputFileName = "composeApp.js"
16+
}
17+
}
18+
binaries.executable()
19+
}
20+
21+
sourceSets {
22+
commonMain.dependencies {
23+
implementation(compose.runtime)
24+
}
25+
26+
val webMain by creating {
27+
resources.setSrcDirs(resources.srcDirs)
28+
dependsOn(commonMain.get())
29+
}
30+
31+
val jsMain by getting {
32+
dependsOn(webMain)
33+
}
34+
}
35+
}
36+
37+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.example.project
2+
3+
private class JsPlatform : Platform {
4+
override val name: String = "Web with Kotlin/JS"
5+
}
6+
7+
actual fun getPlatform(): Platform = JsPlatform()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.example.project
2+
3+
private class WasmPlatform : Platform {
4+
override val name: String = "Web with Kotlin/Wasm"
5+
}
6+
7+
actual fun getPlatform(): Platform = WasmPlatform()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.example.project
2+
3+
class Greeting {
4+
private val platform = getPlatform()
5+
6+
fun greet(): String {
7+
return "Hello, ${platform.name}!"
8+
}
9+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.example.project
2+
3+
interface Platform {
4+
val name: String
5+
}
6+
7+
expect fun getPlatform(): Platform

0 commit comments

Comments
 (0)