diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt index 1d8990f10cb..2049ce9e2d1 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsGradlePluginIT.kt @@ -530,7 +530,7 @@ abstract class AbstractKotlin2JsGradlePluginIT(protected val irBackend: Boolean) ":compileTestKotlin2Js" ) if (irBackend) { - assertFileInProjectExists("build/kotlin2js/main/default/manifest") + assertFileInProjectExists("build/kotlin2js/main/module.js/default/manifest") } else { assertFileInProjectExists("build/kotlin2js/main/module.js") } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle index f8c09c062b9..da2613bc19c 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin2JsProjectWithCustomSourceset/build.gradle @@ -37,7 +37,7 @@ if (isIrBackend) { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" - integrationTestImplementation files(file(compileKotlin2Js.kotlinOptions.outputFile).parent) + integrationTestImplementation files(compileKotlin2Js.destinationDirectory) integrationTestImplementation "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index d617be5fc85..fc7a28474a2 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -156,7 +156,11 @@ internal abstract class KotlinSourceSetProcessor>( protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) { taskConfiguration.configureTask { it.description = taskDescription - it.destinationDirectory.convention(defaultKotlinDestinationDir) + if (it is Kotlin2JsCompile) { + it.defaultDestinationDirectory.convention(defaultKotlinDestinationDir) + } else { + it.destinationDirectory.convention(defaultKotlinDestinationDir) + } it.libraries.from({ kotlinCompilation.compileDependencyFiles }) } } @@ -252,46 +256,11 @@ internal class Kotlin2JsSourceSetProcessor( kotlinCompilation.javaSourceSet.clearJavaSrcDirs() } - // outputFile can be set later during the configuration phase, get it only after the phase: + project.whenEvaluated { - kotlinTask.configure { kotlinTaskInstance -> - val kotlinOptions = kotlinTaskInstance.kotlinOptions - val outputFile = kotlinTaskInstance.outputFileProperty.get() - val outputDir: File = outputFile.parentFile - kotlinOptions.outputFile = if (!kotlinOptions.isProduceUnzippedKlib()) { - outputFile.absolutePath - } else { - outputFile.parentFile.absolutePath - } - if (outputDir.isParentOf(project.rootDir)) - throw InvalidUserDataException( - "The output directory '$outputDir' (defined by outputFile of $kotlinTaskInstance) contains or " + - "matches the project root directory '${project.rootDir}'.\n" + - "Gradle will not be able to build the project because of the root directory lock.\n" + - "To fix this, consider using the default outputFile location instead of providing it explicitly." - ) - kotlinTaskInstance.destinationDirectory.set(outputDir) - - if ( - kotlinOptions.freeCompilerArgs.contains(PRODUCE_JS) || - kotlinOptions.freeCompilerArgs.contains(PRODUCE_UNZIPPED_KLIB) || - kotlinOptions.freeCompilerArgs.contains(PRODUCE_ZIPPED_KLIB) - ) { - // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). - val baseName = if (kotlinCompilation.isMainCompilationData()) { - project.name - } else { - "${project.name}_${kotlinCompilation.compilationPurpose}" - } - kotlinTaskInstance.kotlinOptions.freeCompilerArgs += "$MODULE_NAME=${project.klibModuleName(baseName)}" - } - } - - project.whenEvaluated { - val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) - if (kotlinCompilation is KotlinCompilation<*>) { // FIXME support compiler plugins with PM20 - subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation) - } + val subpluginEnvironment: SubpluginEnvironment = SubpluginEnvironment.loadSubplugins(project) + if (kotlinCompilation is KotlinCompilation<*>) { // FIXME support compiler plugins with PM20 + subpluginEnvironment.addSubpluginOptions(project, kotlinCompilation) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt index 753a4d68b70..98c49b70a04 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/binaryen/BinaryenExec.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.targets.js.binaryen import org.gradle.api.file.RegularFileProperty import org.gradle.api.tasks.* import org.gradle.work.NormalizeLineEndings -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.newFileProperty @@ -75,7 +74,7 @@ constructor() : AbstractExecTask(BinaryenExec::class.java) { it.binaryen = binaryen it.executable = binaryen.requireConfigured().executablePath.absolutePath it.dependsOn(binaryen.setupTaskProvider) - it.dependsOn(compilation.compileKotlinTaskProvider) + it.dependsOn(compilation.compileTaskProvider) it.configuration() } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt index 8ab9f5ba377..580a421d894 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions - /** * @see [compiler/testData/cli/js/jsExtraHelp.out] */ @@ -30,6 +28,3 @@ internal const val PER_MODULE = "-Xir-per-module" internal const val PER_MODULE_OUTPUT_NAME = "-Xir-per-module-output-name" internal const val WASM_BACKEND = "-Xwasm" - -fun KotlinJsOptions.isProduceUnzippedKlib() = PRODUCE_UNZIPPED_KLIB in freeCompilerArgs -fun KotlinJsOptions.isProduceZippedKlib() = PRODUCE_ZIPPED_KLIB in freeCompilerArgs \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt index d1ee7cebb59..3ee3775cb69 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.Task +import org.gradle.api.file.RegularFile import org.gradle.api.provider.Provider import org.gradle.api.tasks.Copy import org.gradle.language.base.plugins.LifecycleBasePlugin @@ -117,9 +118,12 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : ), listOf(compilation) ) { task -> + task.dependsOn(binary.linkSyncTask) val entryFileProvider = binary.linkSyncTask.flatMap { syncTask -> - binary.linkTask.map { - syncTask.destinationDir.resolve(it.outputFileProperty.get().name) + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + syncTask.destinationDir.resolve(it.name) + } } } @@ -203,9 +207,13 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : ), listOf(compilation) ) { task -> - val entryFileProvider = binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + task.dependsOn(binary.linkSyncTask) + val entryFileProvider = binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } + } } task.description = "build webpack ${mode.name.toLowerCase()} bundle" @@ -266,9 +274,7 @@ abstract class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : configureOptimization(mode) - entryProperty.set( - project.layout.file(entryFileProvider) - ) + entryProperty.fileProvider(entryFileProvider) configurationActions.forEach { configure -> configure() diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt index 7eecec75509..7e0b2df8698 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt @@ -33,13 +33,15 @@ abstract class KotlinD8Ir @Inject constructor(target: KotlinJsIrTarget) : val runTaskHolder = D8Exec.create(binary.compilation, name) { group = taskGroupName - inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + dependsOn(binary.linkSyncTask) + inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) } target.runTask.dependsOn(runTaskHolder) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt index 0a36791c46f..bb331e924be 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.targets.js.subtargets.DefaultDistribution import org.jetbrains.kotlin.gradle.targets.js.subtargets.KotlinJsSubTarget import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName -import java.io.File import javax.inject.Inject open class KotlinJsBinaryContainer @@ -43,10 +42,7 @@ constructor( private fun configureBinaryen(binary: JsIrBinary, binaryenDsl: BinaryenExec.() -> Unit) { val linkTask = binary.linkTask - val compiledMjsFile = linkTask.map { link -> - link.kotlinOptions.outputFile?.let(::File) - ?: link.destinationDirectory.locationOnly.get().asFile.resolve("${link.compilation.ownModuleName}.mjs") - } + val compiledMjsFile = linkTask.flatMap { it.outputFileProperty } val compiledWasmFile = compiledMjsFile.map { it.parentFile.resolve("${it.nameWithoutExtension}.wasm") @@ -54,12 +50,15 @@ constructor( //TODO This is temporary solution that overrides compiled files that triggers recompile and reoptimize wasm every time (when binaryen is enabled) val binaryenTask = BinaryenExec.create(binary.compilation, "${linkTask.name}Optimize") { + dependsOn(linkTask) inputFileProperty.fileProvider(compiledWasmFile) outputFileProperty.fileProvider(compiledWasmFile) binaryenDsl() } - binary.compilation.compileKotlinTask.finalizedBy(binaryenTask) + binary.compilation.compileTaskProvider.configure { + it.finalizedBy(binaryenTask) + } binary.linkSyncTask.configure { it.dependsOn(binaryenTask) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index 5bfe17798fa..ef77d4d13c2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection -import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* @@ -17,15 +16,12 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments import org.jetbrains.kotlin.compilerRunner.ArgumentUtils import org.jetbrains.kotlin.gradle.dsl.CompilerJsOptionsDefault -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT -import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile -import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.toHexString import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics @@ -38,7 +34,6 @@ import javax.inject.Inject abstract class KotlinJsIrLink @Inject constructor( objectFactory: ObjectFactory, workerExecutor: WorkerExecutor, - private val projectLayout: ProjectLayout ) : Kotlin2JsCompile( objectFactory.newInstance(CompilerJsOptionsDefault::class.java), objectFactory, @@ -61,10 +56,6 @@ abstract class KotlinJsIrLink @Inject constructor( @get:Internal internal lateinit var compilation: KotlinCompilationData<*> - private val platformType by project.provider { - compilation.platformType - } - @Transient @get:Internal internal val propertiesProvider = PropertiesProvider(project) @@ -95,23 +86,12 @@ abstract class KotlinJsIrLink @Inject constructor( @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val entryModule: DirectoryProperty + @Deprecated( + message = "Replace with destinationDirectory", + replaceWith = ReplaceWith("destinationDirectory") + ) @get:Internal - override val destinationDirectory: DirectoryProperty = objectFactory.directoryProperty() - - @get:OutputDirectory - val normalizedDestinationDirectory: DirectoryProperty = objectFactory - .directoryProperty() - .apply { - set( - destinationDirectory.map { dir -> - if (compilerOptions.outputFile.orNull != null) { - projectLayout.dir(outputFileProperty.map { it.parentFile }).get() - } else { - dir - } - } - ) - } + val normalizedDestinationDirectory: DirectoryProperty get() = destinationDirectory @get:Internal val rootCacheDirectory by lazy { @@ -132,6 +112,9 @@ abstract class KotlinJsIrLink @Inject constructor( KotlinJsIrOutputGranularity.WHOLE_PROGRAM.name.toLowerCase() ) } + + args.includes = entryModule.get().asFile.canonicalPath + if (incrementalJsIr && mode == DEVELOPMENT) { val digest = MessageDigest.getInstance("SHA-256") args.cacheDirectories = args.libraries?.splitByPathSeparator() @@ -161,45 +144,4 @@ abstract class KotlinJsIrLink @Inject constructor( .toTypedArray() .filterNot { it.isEmpty() } } - - override fun setupCompilerArgs( - args: K2JSCompilerArguments, - defaultsOnly: Boolean, - ignoreClasspathResolutionErrors: Boolean - ) { - when (mode) { - PRODUCTION -> { - args.configureOptions(ENABLE_DCE, GENERATE_D_TS, MINIMIZED_MEMBER_NAMES) - } - - DEVELOPMENT -> { - args.configureOptions(GENERATE_D_TS) - } - } - val alreadyDefinedOutputMode = compilerOptions.freeCompilerArgs.get() - .any { it.startsWith(PER_MODULE) } - if (!alreadyDefinedOutputMode) { - args.freeArgs += outputGranularity.toCompilerArgument() - } - super.setupCompilerArgs(args, defaultsOnly, ignoreClasspathResolutionErrors) - } - - private fun K2JSCompilerArguments.configureOptions(vararg additionalCompilerArgs: String) { - freeArgs = freeArgs + ( - additionalCompilerArgs - .mapNotNull { arg -> - if (compilerOptions.freeCompilerArgs.get().any { it.startsWith(arg) }) { - null - } else { - arg - } - } + - PRODUCE_JS + - "$ENTRY_IR_MODULE=${entryModule.get().asFile.canonicalPath}" - ) - - if (platformType == KotlinPlatformType.wasm) { - freeArgs = freeArgs + WASM_BACKEND - } - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt index 0bdf2595116..a8f61a23f64 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt @@ -121,13 +121,15 @@ abstract class KotlinJsIrSubTarget( KotlinJsBinaryMode.DEVELOPMENT ).single() - testJs.inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + testJs.dependsOn(binary.linkSyncTask) + testJs.inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) configureTestDependencies(testJs) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt index f388b0e345b..b0d7ef5a10d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt @@ -5,22 +5,18 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.gradle.api.InvalidUserDataException import org.gradle.api.attributes.Usage import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.bundling.Zip -import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions +import org.jetbrains.kotlin.gradle.dsl.CompilerJsOptions +import org.jetbrains.kotlin.gradle.dsl.JsModuleKind +import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages -import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun -import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName -import org.jetbrains.kotlin.gradle.utils.isParentOf -import org.jetbrains.kotlin.gradle.utils.klibModuleName -import java.io.File open class KotlinJsIrTargetConfigurator() : KotlinOnlyTargetConfigurator(true), @@ -73,70 +69,30 @@ open class KotlinJsIrTargetConfigurator() : super.configureCompilations(target) target.compilations.all { compilation -> - compilation.kotlinOptions { + compilation.compilerOptions.configure { configureOptions() if (target.platformType == KotlinPlatformType.wasm) { - freeCompilerArgs = freeCompilerArgs + WASM_BACKEND + freeCompilerArgs.add(WASM_BACKEND) } - var produceUnzippedKlib = isProduceUnzippedKlib() - val produceZippedKlib = isProduceZippedKlib() - - freeCompilerArgs = freeCompilerArgs + DISABLE_PRE_IR - - val isMainCompilation = compilation.isMain() - - if (!produceUnzippedKlib && !produceZippedKlib) { - freeCompilerArgs = freeCompilerArgs + PRODUCE_UNZIPPED_KLIB - produceUnzippedKlib = true - } - - // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). - val baseName = if (isMainCompilation) { - target.project.name - } else { - "${target.project.name}_${compilation.name}" - } - - compilation.compileKotlinTaskProvider.configure { task -> - val outputFilePath = outputFile ?: if (produceUnzippedKlib) { - task.destinationDirectory.get().asFile.absoluteFile.normalize().absolutePath - } else { - File(task.destinationDirectory.get().asFile, "$baseName.$KLIB_TYPE").absoluteFile.normalize().absolutePath - } - outputFile = outputFilePath - - val taskOutputDir = if (produceUnzippedKlib) File(outputFilePath) else File(outputFilePath).parentFile - if (taskOutputDir.isParentOf(task.project.rootDir)) - throw InvalidUserDataException( - "The output directory '$taskOutputDir' (defined by outputFile of $task) contains or " + - "matches the project root directory '${task.project.rootDir}'.\n" + - "Gradle will not be able to build the project because of the root directory lock.\n" + - "To fix this, consider using the default outputFile location instead of providing it explicitly." - ) - - task.destinationDirectory.set(taskOutputDir) - } - - val klibModuleName = target.project.klibModuleName(baseName) - freeCompilerArgs = freeCompilerArgs + "$MODULE_NAME=$klibModuleName" + freeCompilerArgs.add(DISABLE_PRE_IR) } compilation.binaries .withType(JsIrBinary::class.java) .all { binary -> binary.linkTask.configure { linkTask -> - linkTask.kotlinOptions.configureOptions() + linkTask.compilerOptions.configureOptions() } } } } - private fun KotlinJsOptions.configureOptions() { - moduleKind = "umd" - sourceMap = true - sourceMapEmbedSources = "never" + private fun CompilerJsOptions.configureOptions() { + moduleKind.set(JsModuleKind.MODULE_UMD) + sourceMap.set(true) + sourceMapEmbedSources.set(JsSourceMapEmbedMode.SOURCE_MAP_SOURCE_CONTENT_NEVER) } override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt index d3c05a4607a..3f4a5f955fb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt @@ -34,13 +34,15 @@ abstract class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) : val runTaskHolder = NodeJsExec.create(binary.compilation, name) { group = taskGroupName - inputFileProperty.set( - project.layout.file( - binary.linkSyncTask.map { - it.destinationDir - .resolve(binary.linkTask.get().outputFileProperty.get().name) + dependsOn(binary.linkSyncTask) + inputFileProperty.fileProvider( + binary.linkSyncTask.flatMap { linkSyncTask -> + binary.linkTask.flatMap { linkTask -> + linkTask.outputFileProperty.map { + linkSyncTask.destinationDir.resolve(it.name) + } } - ) + } ) } target.runTask.dependsOn(runTaskHolder) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt index 33c64c85697..7af81ce8482 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinBrowserJs.kt @@ -289,14 +289,16 @@ abstract class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) : KotlinJsBinaryMode.DEVELOPMENT -> devDceTaskProvider } + dependsOn(actualDceTaskProvider) + entryProperty.set( - project.layout.file( - actualDceTaskProvider - .map { - it.destinationDirectory.file(compilation.compileKotlinTask.outputFileProperty.get().name) - } - .flatMap { it.map { it.asFile } } - ) + actualDceTaskProvider.flatMap { dceTask -> + compilation.compileTaskProvider.flatMap { compileTask -> + dceTask.destinationDirectory.file( + compileTask.outputFileProperty.map { it.name } + ) + } + } ) resolveFromModulesFirst = true diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt index 9bbf7f9a20c..c54563498ac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/subtargets/KotlinJsSubTarget.kt @@ -98,7 +98,7 @@ abstract class KotlinJsSubTarget( testRun.subtargetTestTaskName(), listOf(compilation) ) { testJs -> - val compileTask = compilation.compileKotlinTaskProvider + val compileTask = compilation.compileTaskProvider testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP testJs.description = testTaskDescription diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt index 5e40df833cb..54dceb104f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt @@ -102,7 +102,11 @@ constructor( @get:PathSensitive(PathSensitivity.ABSOLUTE) @get:InputFile @get:NormalizeLineEndings - val entryProperty: RegularFileProperty = objects.fileProperty().fileProvider(compilation.compileKotlinTask.outputFileProperty) + val entryProperty: RegularFileProperty = objects + .fileProperty() + .fileProvider( + compilation.compileTaskProvider.flatMap { it.outputFileProperty } + ) init { onlyIf { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index e6f4cea8df9..ec3120f57c2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -6,14 +6,12 @@ package org.jetbrains.kotlin.gradle.tasks import groovy.lang.Closure -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.Project -import org.gradle.api.Task +import org.gradle.api.* import org.gradle.api.file.* import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logger import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.provider.SetProperty @@ -57,6 +55,11 @@ import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.BuildReportsService import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJvmOptionsCompat +import org.jetbrains.kotlin.gradle.targets.js.ir.* +import org.jetbrains.kotlin.gradle.targets.js.ir.DISABLE_PRE_IR +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_JS +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_UNZIPPED_KLIB +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_ZIPPED_KLIB import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled @@ -940,25 +943,32 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Input internal var incrementalJsKlib: Boolean = true - override fun isIncrementalCompilationEnabled(): Boolean = - when { - "-Xir-produce-js" in kotlinOptions.freeCompilerArgs -> { - false - } - "-Xir-produce-klib-dir" in kotlinOptions.freeCompilerArgs -> { + override fun isIncrementalCompilationEnabled(): Boolean { + val freeArgs = enhancedFreeCompilerArgs.get() + return when { + PRODUCE_JS in freeArgs -> false + + PRODUCE_UNZIPPED_KLIB in freeArgs -> { KotlinBuildStatsService.applyIfInitialised { it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) } incrementalJsKlib } - "-Xir-produce-klib-file" in kotlinOptions.freeCompilerArgs -> { + + PRODUCE_ZIPPED_KLIB in freeArgs -> { KotlinBuildStatsService.applyIfInitialised { it.report(BooleanMetrics.JS_KLIB_INCREMENTAL, incrementalJsKlib) } incrementalJsKlib } + else -> incremental } + } + + // Workaround to be able to use default value and change it later based on external input + @get:Internal + internal abstract val defaultDestinationDirectory: DirectoryProperty // This can be file or directory @get:Internal @@ -973,6 +983,14 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Optional abstract val optionalOutputFile: RegularFileProperty + // Workaround to add additional compiler args based on the exising one + // Currently there is a logic to add additional compiler arguments based on already existing one. + // And it is not possible to update compilerOptions.freeCompilerArgs using some kind of .map + // or .flatMap call - this will cause StackOverlowException as upstream source will be updated + // and .map will be called again. + @get:Input + internal abstract val enhancedFreeCompilerArgs: ListProperty + override fun createCompilerArgs(): K2JSCompilerArguments = K2JSCompilerArguments() @@ -992,6 +1010,14 @@ abstract class Kotlin2JsCompile @Inject constructor( if (defaultsOnly) return (compilerOptions as CompilerJsOptionsDefault).fillCompilerArguments(args) + if (!args.sourceMapPrefix.isNullOrEmpty()) { + args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath + } + // Rewriting default outputFile property back to outputFilePropertyValue + args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath + // Overriding freeArgs from compilerOptions with enhanced one + // containing additional arguments based on the js compilation configuration + args.freeArgs = enhancedFreeCompilerArgs.get() } @get:InputFiles @@ -1018,26 +1044,32 @@ abstract class Kotlin2JsCompile @Inject constructor( private fun isHybridKotlinJsLibrary(file: File): Boolean = JsLibraryUtils.isKotlinJavascriptLibrary(file) && isKotlinLibrary(file) - private fun KotlinJsOptions.isPreIrBackendDisabled(): Boolean = - listOf( - "-Xir-only", - "-Xir-produce-js", - "-Xir-produce-klib-file" - ).any(freeCompilerArgs::contains) + private val preIrBackendCompilerFlags = listOf( + DISABLE_PRE_IR, + PRODUCE_JS, + PRODUCE_ZIPPED_KLIB + ) + + private fun isPreIrBackendDisabled(): Boolean = enhancedFreeCompilerArgs + .get() + .any { preIrBackendCompilerFlags.contains(it) } // see also isIncrementalCompilationEnabled - private fun KotlinJsOptions.isIrBackendEnabled(): Boolean = - listOf( - "-Xir-produce-klib-dir", - "-Xir-produce-js", - "-Xir-produce-klib-file" - ).any(freeCompilerArgs::contains) + private val irBackendCompilerFlags = listOf( + PRODUCE_UNZIPPED_KLIB, + PRODUCE_JS, + PRODUCE_ZIPPED_KLIB + ) + + private fun isIrBackendEnabled(): Boolean = enhancedFreeCompilerArgs + .get() + .any { irBackendCompilerFlags.contains(it) } private val File.asLibraryFilterCacheKey: LibraryFilterCachingService.LibraryFilterCacheKey get() = LibraryFilterCachingService.LibraryFilterCacheKey( this, - irEnabled = kotlinOptions.isIrBackendEnabled(), - preIrDisabled = kotlinOptions.isPreIrBackendDisabled() + irEnabled = isIrBackendEnabled(), + preIrDisabled = isPreIrBackendDisabled() ) // Kotlin/JS can operate in 3 modes: @@ -1045,8 +1077,8 @@ abstract class Kotlin2JsCompile @Inject constructor( // 2) purely IR backend // 3) hybrid pre-IR and IR backend. Can only accept libraries with both JS and IR parts. private val libraryFilterBody: (File) -> Boolean - get() = if (kotlinOptions.isIrBackendEnabled()) { - if (kotlinOptions.isPreIrBackendDisabled()) { + get() = if (isIrBackendEnabled()) { + if (isPreIrBackendDisabled()) { //::isKotlinLibrary // Workaround for KT-47797 { isKotlinLibrary(it) } @@ -1088,7 +1120,9 @@ abstract class Kotlin2JsCompile @Inject constructor( ) { logger.debug("Calling compiler") - if (kotlinOptions.isIrBackendEnabled()) { + validateOutputDirectory() + + if (isIrBackendEnabled()) { logger.info(USING_JS_IR_BACKEND_MESSAGE) } @@ -1103,11 +1137,6 @@ abstract class Kotlin2JsCompile @Inject constructor( } args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath } - - if (!args.sourceMapPrefix.isNullOrEmpty()) { - args.sourceMapBaseDirs = sourceMapBaseDir.get().asFile.absolutePath - } - args.legacyDeprecatedNoWarn = jsLegacyNoWarn.get() logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}") @@ -1141,6 +1170,22 @@ abstract class Kotlin2JsCompile @Inject constructor( taskOutputsBackup ) } + + private val projectRootDir = project.rootDir + + private fun validateOutputDirectory() { + val outputFile = outputFileProperty.get() + val outputDir = outputFile.parentFile + + if (outputDir.isParentOf(projectRootDir)) { + throw InvalidUserDataException( + "The output directory '$outputDir' (defined by outputFile of ':$name') contains or " + + "matches the project root directory '${projectRootDir}'.\n" + + "Gradle will not be able to build the project because of the root directory lock.\n" + + "To fix this, consider using the default outputFile location instead of providing it explicitly." + ) + } + } } data class KotlinCompilerPluginData( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt index b5f35682a7b..80bf55adfc8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt @@ -7,8 +7,13 @@ package org.jetbrains.kotlin.gradle.tasks.configuration import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData -import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData +import org.jetbrains.kotlin.gradle.targets.js.ir.* +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_JS +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_UNZIPPED_KLIB +import org.jetbrains.kotlin.gradle.targets.js.ir.PRODUCE_ZIPPED_KLIB import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile +import org.jetbrains.kotlin.gradle.utils.klibModuleName import java.io.File internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig @@ -27,18 +32,96 @@ internal open class BaseKotlin2JsCompileConfig( task.incremental = propertiesProvider.incrementalJs ?: true task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true - task.outputFileProperty.value(task.project.provider { - val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" - task.compilerOptions.outputFile.orNull?.let(::File) - ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}$extensionName") - }).disallowChanges() + configureAdditionalFreeCompilerArguments(task, compilation) - task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile -> - task.project.provider { - outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() } + @Suppress("DEPRECATION") + task.compilerOptions.outputFile.convention( + task.defaultDestinationDirectory.zip(task.enhancedFreeCompilerArgs) { destDir, freeArgs -> + val baseName = if (compilation.isMainCompilationData()) { + project.name + } else { + "${project.name}_${compilation.compilationPurpose}" + } + + if (freeArgs.contains(PRODUCE_UNZIPPED_KLIB)) { + destDir.asFile.absoluteFile.normalize().absolutePath + } else { + if (compilation is KotlinJsIrCompilation) { + destDir.asFile.resolve("$baseName.$KLIB_TYPE").absoluteFile.normalize().absolutePath + } else { + val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" + destDir.asFile.resolve("${compilation.ownModuleName}$extensionName").absolutePath + } + } } - }).disallowChanges() + ) + + @Suppress("DEPRECATION") + task.outputFileProperty.value( + task.compilerOptions.outputFile.map { File(it) } + ) + + task.destinationDirectory + .fileProvider( + task.outputFileProperty.zip(task.enhancedFreeCompilerArgs) { outputFile, freeArgs -> + if (freeArgs.contains(PRODUCE_UNZIPPED_KLIB)) { + outputFile + } else { + outputFile.parentFile + } + } + ) + .disallowChanges() + + task.optionalOutputFile.fileProvider( + task.outputFileProperty.flatMap { outputFile -> + task.enhancedFreeCompilerArgs.flatMap { freeArgs -> + task.project.providers.provider { + outputFile.takeUnless { + freeArgs.contains(PRODUCE_UNZIPPED_KLIB) + } + } + } + } + ).disallowChanges() task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() } } } + + protected open fun configureAdditionalFreeCompilerArguments( + task: TASK, + compilation: KotlinCompilationData<*> + ) { + task.enhancedFreeCompilerArgs.value( + task.compilerOptions.freeCompilerArgs.map { freeArgs -> + freeArgs.toMutableList().apply { + commonJsAdditionalCompilerFlags(compilation) + } + } + ).disallowChanges() + } + + protected fun MutableList.commonJsAdditionalCompilerFlags( + compilation: KotlinCompilationData<*> + ) { + if (contains(DISABLE_PRE_IR) && + !contains(PRODUCE_UNZIPPED_KLIB) && + !contains(PRODUCE_ZIPPED_KLIB) + ) { + add(PRODUCE_UNZIPPED_KLIB) + } + + if (contains(PRODUCE_JS) || + contains(PRODUCE_UNZIPPED_KLIB) || + contains(PRODUCE_ZIPPED_KLIB) + ) { + // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). + val baseName = if (compilation.isMainCompilationData()) { + project.name + } else { + "${project.name}_${compilation.compilationPurpose}" + } + add("$MODULE_NAME=${project.klibModuleName(baseName)}") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt index d134c024dc0..883b3d2747d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt @@ -5,8 +5,11 @@ package org.jetbrains.kotlin.gradle.tasks.configuration -import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation -import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink +import org.gradle.api.InvalidUserDataException +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode +import org.jetbrains.kotlin.gradle.targets.js.ir.* internal open class KotlinJsIrLinkConfig( compilation: KotlinJsIrCompilation @@ -17,9 +20,70 @@ internal open class KotlinJsIrLinkConfig( // Link tasks are not affected by compiler plugin, so set to empty task.pluginClasspath.setFrom(objectFactory.fileCollection()) - task.entryModule.fileProvider(compilation.output.classesDirs.elements.map { it.single().asFile }).disallowChanges() + task.dependsOn(compilation.compileTaskProvider) + task.dependsOn(compilation.output.classesDirs) + task.entryModule.fileProvider( + compilation.output.classesDirs.elements.flatMap { + task.project.providers.provider { + it.single().asFile + } + } + ).disallowChanges() task.compilation = compilation - task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile }) + } + } + + override fun configureAdditionalFreeCompilerArguments( + task: KotlinJsIrLink, + compilation: KotlinCompilationData<*> + ) { + task.enhancedFreeCompilerArgs.value( + task.compilerOptions.freeCompilerArgs.zip(task.modeProperty) { freeArgs, mode -> + freeArgs.toMutableList().apply { + commonJsAdditionalCompilerFlags(compilation) + + when (mode) { + KotlinJsBinaryMode.PRODUCTION -> { + configureOptions( + compilation, + ENABLE_DCE, + GENERATE_D_TS, + MINIMIZED_MEMBER_NAMES + ) + } + + KotlinJsBinaryMode.DEVELOPMENT -> { + configureOptions( + compilation, + GENERATE_D_TS + ) + } + else -> throw InvalidUserDataException( + "Unknown KotlinJsBinaryMode to configure the build: $mode" + ) + } + + val alreadyDefinedOutputMode = any { it.startsWith(PER_MODULE) } + if (!alreadyDefinedOutputMode) { + add(task.outputGranularity.toCompilerArgument()) + } + } + } + ).disallowChanges() + } + + private fun MutableList.configureOptions( + compilation: KotlinCompilationData<*>, + vararg additionalCompilerArgs: String + ) { + additionalCompilerArgs.forEach { arg -> + if (none { it.startsWith(arg) }) add(arg) + } + + add(PRODUCE_JS) + + if (compilation.platformType == KotlinPlatformType.wasm) { + add(WASM_BACKEND) } } } \ No newline at end of file