diff --git a/modules/gradle-plugin/build.gradle.kts b/modules/gradle-plugin/build.gradle.kts index 9a209ad..089ae54 100644 --- a/modules/gradle-plugin/build.gradle.kts +++ b/modules/gradle-plugin/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { implementation(libs.android.gradle.plugin) implementation(libs.compose.gradle.plugin) implementation(libs.kotlin.poet) + testImplementation(libs.junit) } group = "org.jetbrains.compose.storytale" diff --git a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsMultiplatformTasks.kt b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsMultiplatformTasks.kt index b0f37b2..cdd0d7a 100644 --- a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsMultiplatformTasks.kt +++ b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsMultiplatformTasks.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinBrowserJsIr import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget import org.jetbrains.kotlin.gradle.targets.js.ir.WebpackConfigurator +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile fun Project.processJsCompilation(extension: StorytaleExtension, target: KotlinJsIrTarget) { @@ -101,9 +102,26 @@ private fun Project.createJsStorytaleGenerateSourceTask(extension: StorytaleExte title = target.name outputResourcesDir = file("$storytaleBuildDir/resources") outputSourcesDir = file("$storytaleBuildDir/sources") + scriptFileName.convention(project.provider { resolveScriptFileName(target) }) } } +internal fun Project.resolveScriptFileName(target: KotlinJsIrTarget): String { + val webpackTasks = tasks.withType(KotlinWebpack::class.java) + .matching { it.name.startsWith(target.name) && it.name.contains("Stories") } + val webpackFileName = webpackTasks.firstOrNull()?.mainOutputFileName?.orNull + if (!webpackFileName.isNullOrBlank()) { + return if (webpackFileName.endsWith(".js")) webpackFileName else "$webpackFileName.js" + } + + val outputModuleName = target.outputModuleName.orNull + if (!outputModuleName.isNullOrBlank()) { + return "$outputModuleName.js" + } + + return "${project.name}.js" +} + fun Project.createWasmAndJsStorytaleExecTask(compilation: KotlinJsIrCompilation) { afterEvaluate { val browser = compilation.target.browser as KotlinBrowserJsIr @@ -112,5 +130,10 @@ fun Project.createWasmAndJsStorytaleExecTask(compilation: KotlinJsIrCompilation) setupBuild(compilation) setupRun(compilation) } + + val storytaleWebTaskPrefix = "${compilation.target.name}Browser${compilation.name}" + tasks.matching { it.name.startsWith(storytaleWebTaskPrefix) }.configureEach { + group = StorytaleGradlePlugin.STORYTALE_TASK_GROUP + } } } diff --git a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsSourceGeneratorTask.kt b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsSourceGeneratorTask.kt index 84b8de2..833a8ce 100644 --- a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsSourceGeneratorTask.kt +++ b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/JsSourceGeneratorTask.kt @@ -3,6 +3,7 @@ package org.jetbrains.compose.storytale.plugin import com.squareup.kotlinpoet.FileSpec import java.io.File import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory @@ -14,6 +15,9 @@ open class JsSourceGeneratorTask : DefaultTask() { @Input lateinit var title: String + @Input + val scriptFileName: Property = project.objects.property(String::class.java).convention(SCRIPT_FILE_NAME) + @OutputDirectory lateinit var outputResourcesDir: File @@ -51,7 +55,7 @@ open class JsSourceGeneratorTask : DefaultTask() { stylesFile.writeText(webStylesCssContent) val index = File(outputResourcesDir, "index.html") - index.writeText(webIndexHtmlContent(SCRIPT_FILE_NAME)) + index.writeText(webIndexHtmlContent(scriptFileName.get())) } companion object { diff --git a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmMultiplatformTasks.kt b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmMultiplatformTasks.kt index 7bfa294..79f3962 100644 --- a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmMultiplatformTasks.kt +++ b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmMultiplatformTasks.kt @@ -20,5 +20,6 @@ private fun Project.createWasmStorytaleGenerateSourceTask(extension: StorytaleEx title = target.name outputSourcesDir = file("$storytaleBuildDir/sources") outputResourcesDir = file("$storytaleBuildDir/resources") + scriptFileName.convention(project.provider { resolveScriptFileName(target) }) } } diff --git a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmSourceGeneratorTask.kt b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmSourceGeneratorTask.kt index ae4e59e..d0b8c65 100644 --- a/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmSourceGeneratorTask.kt +++ b/modules/gradle-plugin/src/main/kotlin/org/jetbrains/compose/storytale/plugin/WasmSourceGeneratorTask.kt @@ -5,6 +5,7 @@ import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.FileSpec import java.io.File import org.gradle.api.DefaultTask +import org.gradle.api.provider.Property import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.OutputDirectory @@ -15,6 +16,9 @@ open class WasmSourceGeneratorTask : DefaultTask() { @Input lateinit var title: String + @Input + val scriptFileName: Property = project.objects.property(String::class.java).convention(JsSourceGeneratorTask.SCRIPT_FILE_NAME) + @OutputDirectory lateinit var outputResourcesDir: File @@ -53,7 +57,7 @@ open class WasmSourceGeneratorTask : DefaultTask() { val index = File(outputResourcesDir, "index.html") index.writeText( webIndexHtmlContent( - jsFileName = JsSourceGeneratorTask.SCRIPT_FILE_NAME, + jsFileName = scriptFileName.get(), addSkikoJs = false, ), ) diff --git a/modules/gradle-plugin/src/test/kotlin/org/jetbrains/compose/storytale/plugin/ResolveScriptFileNameTest.kt b/modules/gradle-plugin/src/test/kotlin/org/jetbrains/compose/storytale/plugin/ResolveScriptFileNameTest.kt new file mode 100644 index 0000000..ad89203 --- /dev/null +++ b/modules/gradle-plugin/src/test/kotlin/org/jetbrains/compose/storytale/plugin/ResolveScriptFileNameTest.kt @@ -0,0 +1,78 @@ +package org.jetbrains.compose.storytale.plugin + +import org.gradle.testfixtures.ProjectBuilder +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack +import org.junit.Assert.assertEquals +import org.junit.Test + +@OptIn(ExperimentalWasmDsl::class) +class ResolveScriptFileNameTest { + + @Test + fun testResolveScriptFileName_composeApp() { + val project = ProjectBuilder.builder().withName("composeApp").build() + project.plugins.apply("org.jetbrains.kotlin.multiplatform") + val kotlin = project.extensions.getByType(KotlinMultiplatformExtension::class.java) + val target = kotlin.wasmJs() as KotlinJsIrTarget + + val scriptName = project.resolveScriptFileName(target) + assertEquals("composeApp.js", scriptName) + } + + @Test + fun testResolveScriptFileName_shared() { + val project = ProjectBuilder.builder().withName("shared").build() + project.plugins.apply("org.jetbrains.kotlin.multiplatform") + val kotlin = project.extensions.getByType(KotlinMultiplatformExtension::class.java) + val target = kotlin.wasmJs() as KotlinJsIrTarget + + val scriptName = project.resolveScriptFileName(target) + assertEquals("shared.js", scriptName) + } + + @Test + fun testResolveScriptFileName_nestedAppShared() { + val root = ProjectBuilder.builder().withName("root").build() + val app = ProjectBuilder.builder().withName("app").withParent(root).build() + val shared = ProjectBuilder.builder().withName("shared").withParent(app).build() + shared.plugins.apply("org.jetbrains.kotlin.multiplatform") + val kotlin = shared.extensions.getByType(KotlinMultiplatformExtension::class.java) + val target = kotlin.wasmJs() as KotlinJsIrTarget + + val scriptName = shared.resolveScriptFileName(target) + assertEquals("root-app-shared.js", scriptName) + } + + @Test + fun testResolveScriptFileName_outputModuleNameOverride() { + val project = ProjectBuilder.builder().withName("shared").build() + project.plugins.apply("org.jetbrains.kotlin.multiplatform") + val kotlin = project.extensions.getByType(KotlinMultiplatformExtension::class.java) + val target = kotlin.wasmJs() as KotlinJsIrTarget + target.outputModuleName.set("customModule") + + val scriptName = project.resolveScriptFileName(target) + assertEquals("customModule.js", scriptName) + } + + @Test + fun testResolveScriptFileName_webpackTaskMainOutputFileName() { + val project = ProjectBuilder.builder().withName("shared").build() + project.plugins.apply("org.jetbrains.kotlin.multiplatform") + val kotlin = project.extensions.getByType(KotlinMultiplatformExtension::class.java) + val target = kotlin.wasmJs { + browser() + } as KotlinJsIrTarget + + val compilation = target.compilations.getByName("main") + project.tasks.register("wasmJsStoriesDevelopmentWebpack", KotlinWebpack::class.java, compilation).configure { + mainOutputFileName.set("customBundle.js") + } + + val scriptName = project.resolveScriptFileName(target) + assertEquals("customBundle.js", scriptName) + } +}