[Gradle, JS] Use unpacked klib as a dependency for JS compiler

[Gradle, JS] Use artifact view and if for js platform type

[Gradle, JS] KotlinJsTest compatible with directories

[Gradle, JS] No need to js jar for friends artifacts

[Gradle, JS] Unique artifact type for js klib artifact type

[Gradle, JS] Fix pom rewriting and klib incremental

[Gradle, JS] Compile

[Gradle, JS] Only IR unpacked

[Gradle, JS] Rebase on master

[Gradle, JS] Not unzip for wasm

[Gradle, JS] Register in source set processor

[Gradle, JS] Fix variant aware test

[Gradle, JS] Fix tests

[Gradle, JS] Fix tests

[Gradle, JS] Move incremental test only to IR

[Gradle, JS] Ignore if file does not exist

[Gradle, JS] Depends kotlin-dom-api-compat on custom configuration
diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt
index 289886a..c0cb150 100644
--- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt
+++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/multiproject/ModulesApiHistory.kt
@@ -8,6 +8,7 @@
 import org.jetbrains.kotlin.incremental.IncrementalModuleEntry
 import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
 import org.jetbrains.kotlin.incremental.util.Either
+import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME
 import java.io.File
 import java.nio.file.Path
 import java.nio.file.Paths
@@ -41,6 +42,8 @@
         val jarFiles = ArrayList<File>()
         val classFiles = ArrayList<File>()
 
+        val manifestFiles = ArrayList<File>()
+
         for (file in changedFiles) {
             val extension = file.extension
 
@@ -53,9 +56,11 @@
                 }
                 extension.equals("klib", ignoreCase = true) -> {
                     // TODO: shouldn't jars and klibs be tracked separately?
-                    // TODO: what to do with `in-directory` klib?
                     jarFiles.add(file)
                 }
+                file.name == KLIB_MANIFEST_FILE_NAME -> {
+                    manifestFiles.add(file)
+                }
             }
         }
 
@@ -75,6 +80,13 @@
             }
         }
 
+        for (manifest in manifestFiles) {
+            when (val historyEither = getBuildHistoryForDir(manifest.parentFile)) {
+                is Either.Success<Set<File>> -> result.addAll(historyEither.value)
+                is Either.Error -> return historyEither
+            }
+        }
+
         return Either.Success(result)
     }
 
diff --git a/libraries/kotlin-dom-api-compat/build.gradle.kts b/libraries/kotlin-dom-api-compat/build.gradle.kts
index 7710006..cdb9681 100644
--- a/libraries/kotlin-dom-api-compat/build.gradle.kts
+++ b/libraries/kotlin-dom-api-compat/build.gradle.kts
@@ -1,5 +1,6 @@
 import plugins.configureDefaultPublishing
 import plugins.configureKotlinPomAttributes
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
 
 plugins {
     `maven-publish`
@@ -10,6 +11,25 @@
 
 kotlin {
     js(IR) {
+        // it is necessary because standard configuration api is resolved during configuration phase
+        // making unusable unzip it before kotlin-stdlib-js assembled
+        val jsApi = configurations.maybeCreate(
+            "jsApi"
+        ).apply {
+            isVisible = false
+            isCanBeResolved = true
+            isCanBeConsumed = false
+            attributes.attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_API))
+        }
+
+        compilations["main"].compileKotlinTaskProvider.configure {
+            libraries.setFrom(jsApi)
+        }
+
+        compilations["test"].compileKotlinTaskProvider.configure {
+            libraries.setFrom(jsApi)
+        }
+
         sourceSets {
             val main by getting {
                 if (!kotlinBuildProperties.isInIdeaSync) {
@@ -26,6 +46,10 @@
     }
 }
 
+dependencies {
+    "jsApi"(project(":kotlin-stdlib-js"))
+}
+
 tasks.withType<org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile>().configureEach {
     compilerOptions.freeCompilerArgs
         .addAll(
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JsConfigurationCacheIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JsConfigurationCacheIT.kt
index e5a200d..3f88a1c9 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JsConfigurationCacheIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/JsConfigurationCacheIT.kt
@@ -94,7 +94,7 @@
     }
 
     @DisplayName("configuration cache is reused when idea.version system property is changed in node project")
-    @GradleTestVersions(minVersion = TestVersions.Gradle.G_7_5, maxVersion = TestVersions.Gradle.G_7_5)
+    @GradleTestVersions(minVersion = TestVersions.Gradle.G_8_0, maxVersion = TestVersions.Gradle.G_8_0)
     @GradleTest
     fun testNodeJsOnIdeaPropertyChange(gradleVersion: GradleVersion) {
         project("kotlin-js-nodejs-project", gradleVersion) {
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 b0c3359..0dd21c2 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
@@ -498,6 +498,36 @@
             }
         }
     }
+
+    @DisplayName("incremental compilation for js works")
+    @GradleTest
+    fun testIncrementalCompilation(gradleVersion: GradleVersion) {
+        val buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
+        project("kotlin2JsICProject", gradleVersion, buildOptions = buildOptions) {
+            build("compileKotlinJs", "compileTestKotlinJs") {
+                checkIrCompilationMessage()
+                assertOutputContains(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
+                assertCompiledKotlinSources(projectPath.allKotlinFiles.relativizeTo(projectPath), output)
+            }
+
+            build("compileKotlinJs", "compileTestKotlinJs") {
+                assertCompiledKotlinSources(emptyList(), output)
+            }
+
+            val modifiedFile = subProject("lib").kotlinSourcesDir().resolve("A.kt") ?: error("No A.kt file in test project")
+            modifiedFile.modify {
+                it.replace("val x = 0", "val x = \"a\"")
+            }
+            build("compileKotlinJs", "compileTestKotlinJs") {
+                checkIrCompilationMessage()
+                assertOutputContains(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
+                val affectedFiles = listOf("A.kt", "useAInLibMain.kt", "useAInAppMain.kt", "useAInAppTest.kt", "useAInLibTest.kt").mapNotNull {
+                    projectPath.findInPath(it)
+                }
+                assertCompiledKotlinSources(affectedFiles.relativizeTo(projectPath), output)
+            }
+        }
+    }
 }
 
 @JsGradlePluginTests
@@ -903,36 +933,6 @@
         }
     }
 
-    @DisplayName("incremental compilation for js works")
-    @GradleTest
-    fun testIncrementalCompilation(gradleVersion: GradleVersion) {
-        val buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
-        project("kotlin2JsICProject", gradleVersion, buildOptions = buildOptions) {
-            build("compileKotlinJs", "compileTestKotlinJs") {
-                checkIrCompilationMessage()
-                assertOutputContains(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
-                assertCompiledKotlinSources(projectPath.allKotlinFiles.relativizeTo(projectPath), output)
-            }
-
-            build("compileKotlinJs", "compileTestKotlinJs") {
-                assertCompiledKotlinSources(emptyList(), output)
-            }
-
-            val modifiedFile = subProject("lib").kotlinSourcesDir().resolve("A.kt") ?: error("No A.kt file in test project")
-            modifiedFile.modify {
-                it.replace("val x = 0", "val x = \"a\"")
-            }
-            build("compileKotlinJs", "compileTestKotlinJs") {
-                checkIrCompilationMessage()
-                assertOutputContains(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
-                val affectedFiles = listOf("A.kt", "useAInLibMain.kt", "useAInAppMain.kt", "useAInAppTest.kt").mapNotNull {
-                    projectPath.findInPath(it)
-                }
-                assertCompiledKotlinSources(affectedFiles.relativizeTo(projectPath), output)
-            }
-        }
-    }
-
     @DisplayName("non-incremental compilation works")
     @GradleTest
     fun testIncrementalCompilationDisabled(gradleVersion: GradleVersion) {
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt
index 6a8e996..f995683 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt
@@ -137,7 +137,7 @@
                 // 2 for lib.klib + 1 for stdlib + 1 for dom-api-compat + 1 for main
                 assertEquals(5, klibCacheDirs?.size, "cache should contain 5 dirs")
 
-                val libKlibCacheDirs = klibCacheDirs?.filter { dir -> dir.startsWith("lib.klib.") }
+                val libKlibCacheDirs = klibCacheDirs?.filter { dir -> dir.startsWith("main.") }
                 assertEquals(2, libKlibCacheDirs?.size, "cache should contain 2 dirs for lib.klib")
 
                 var lib = false
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesMppIT.kt
index 94451fc..5a86e4b 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesMppIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesMppIT.kt
@@ -39,7 +39,7 @@
             gradleBuildScript(innerProject.projectName).appendText("\ndependencies { implementation rootProject }")
 
             testResolveAllConfigurations(subproject = innerProject.projectName) {
-                assertContains(">> :${innerProject.projectName}:runtimeClasspath --> sample-lib-nodejs-1.0.klib")
+                assertContains(">> :${innerProject.projectName}:runtimeClasspath --> main")
             }
 
             @Suppress("DEPRECATION")
@@ -288,24 +288,23 @@
             val testGradleVersion = chooseWrapperVersionOrFinishTest()
             val isAtLeastGradle75 = GradleVersion.version(testGradleVersion) >= GradleVersion.version("7.5")
 
-            listOf("jvm6" to "Classpath", "nodeJs" to "Classpath").forEach { (target, suffix) ->
-                build("dependencyInsight", "--configuration", "${target}Compile$suffix", "--dependency", "sample-lib") {
+            listOf("jvm6" to null, "nodeJs" to "unpacked").forEach { (target, prefix) ->
+                val variantPrefix = prefix?.let { it + target.capitalize() } ?: target
+                build("dependencyInsight", "--configuration", "${target}CompileClasspath", "--dependency", "sample-lib") {
                     assertSuccessful()
                     if (isAtLeastGradle75) {
-                        assertContains("Variant ${target}ApiElements")
+                        assertContains("Variant ${variantPrefix}ApiElements")
                     } else {
-                        assertContains("variant \"${target}ApiElements\" [")
+                        assertContains("variant \"${variantPrefix}ApiElements\" [")
                     }
                 }
 
-                if (suffix == "Classpath") {
-                    build("dependencyInsight", "--configuration", "${target}Runtime$suffix", "--dependency", "sample-lib") {
-                        assertSuccessful()
-                        if (isAtLeastGradle75) {
-                            assertContains("Variant ${target}RuntimeElements")
-                        } else {
-                            assertContains("variant \"${target}RuntimeElements\" [")
-                        }
+                build("dependencyInsight", "--configuration", "${target}RuntimeClasspath", "--dependency", "sample-lib") {
+                    assertSuccessful()
+                    if (isAtLeastGradle75) {
+                        assertContains("Variant ${variantPrefix}RuntimeElements")
+                    } else {
+                        assertContains("variant \"${variantPrefix}RuntimeElements\" [")
                     }
                 }
             }
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/lib/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/lib/build.gradle.kts
index f5df9e7..5de311f 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/lib/build.gradle.kts
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/lib/build.gradle.kts
@@ -17,7 +17,9 @@
         val runtimeOnly by configurations.getting
         runtimeOnly.extendsFrom(otherDist)
         artifacts {
-            add(otherDist.name, tasks.named("otherKlib").map { it.outputs.files.files.first() })
+            add(otherDist.name, otherCompilation.compileTaskProvider.flatMap { it.destinationDirectory }) {
+                builtBy(otherCompilation.compileTaskProvider)
+            }
         }
         useCommonJs()
         browser {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsIrSourceSetProcessor.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsIrSourceSetProcessor.kt
index 57f5015..64ba31b 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsIrSourceSetProcessor.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsIrSourceSetProcessor.kt
@@ -12,9 +12,10 @@
 import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
 import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
 import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlin2JsCompileConfig
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlinCompileConfig
 import org.jetbrains.kotlin.gradle.tasks.configuration.Kotlin2JsCompileConfig
 import org.jetbrains.kotlin.gradle.tasks.configuration.KotlinJsIrLinkConfig
-import org.jetbrains.kotlin.gradle.utils.filesProvider
 
 internal class KotlinJsIrSourceSetProcessor(
     tasksProvider: KotlinTasksProvider,
@@ -41,13 +42,24 @@
 
         val compilation = compilationInfo.tcsOrNull?.compilation as KotlinJsIrCompilation
 
+        BaseKotlin2JsCompileConfig.registerTransformsOnce(project)
+
+        if (compilation.target.platformType == KotlinPlatformType.js) {
+            kotlinTask.configure {
+                it.libraries.from(compilation.compileDirectoryFiles)
+            }
+        }
+
         compilation.binaries
             .withType(JsIrBinary::class.java)
             .all { binary ->
                 val configAction = KotlinJsIrLinkConfig(binary)
                 configAction.configureTask {
                     it.description = taskDescription
-                    it.libraries.from(compilation.runtimeDependencyFiles)
+                    when (compilation.target.platformType) {
+                        KotlinPlatformType.js -> it.libraries.from(compilation.runtimeDirectoryFiles)
+                        KotlinPlatformType.wasm -> it.libraries.from(compilation.runtimeDependencyFiles)
+                    }
                 }
                 configAction.configureTask { task ->
                     task.modeProperty.set(binary.mode)
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt
index 0d7c382..3b01b1d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt
@@ -50,6 +50,8 @@
 import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
 import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropKlibLibraryElements
 import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
+import org.jetbrains.kotlin.gradle.tasks.configuration.ArtifactTypeCompatibilityRule
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlinCompileConfig
 import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry
 import org.jetbrains.kotlin.gradle.tooling.registerBuildKotlinToolingMetadataTask
 import org.jetbrains.kotlin.gradle.utils.*
@@ -197,6 +199,9 @@
         KotlinPlatformType.setupAttributesMatchingStrategy(this)
         KotlinUsages.setupAttributesMatchingStrategy(this, isKotlinGranularMetadata)
         KotlinJsCompilerAttribute.setupAttributesMatchingStrategy(project.dependencies.attributesSchema)
+        this.attribute(BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE) { strategy ->
+            strategy.compatibilityRules.add(ArtifactTypeCompatibilityRule::class.java)
+        }
         ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
         CInteropKlibLibraryElements.setupAttributesMatchingStrategy(this)
     }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationDependencyConfigurationsFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationDependencyConfigurationsFactories.kt
index 526a768..346fe1c 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationDependencyConfigurationsFactories.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationDependencyConfigurationsFactories.kt
@@ -17,6 +17,8 @@
 import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
 import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
 import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlinCompileConfig
+import org.jetbrains.kotlin.gradle.tasks.configuration.Kotlin2JsCompileConfig
 import org.jetbrains.kotlin.gradle.utils.*
 
 internal sealed class DefaultKotlinCompilationDependencyConfigurationsFactory :
@@ -197,6 +199,12 @@
         isVisible = false
         isCanBeConsumed = false
         attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
+        if (target.platformType == KotlinPlatformType.js && target is KotlinJsIrTarget) {
+            attributes.attribute(
+                BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+            )
+        }
         if (target.platformType != KotlinPlatformType.androidJvm) {
             attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
         }
@@ -211,6 +219,12 @@
             isVisible = false
             isCanBeConsumed = false
             isCanBeResolved = true
+            if (target.platformType == KotlinPlatformType.js && target is KotlinJsIrTarget) {
+                attributes.attribute(
+                    BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                    Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+                )
+            }
             attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.consumerRuntimeUsage(target))
             if (target.platformType != KotlinPlatformType.androidJvm) {
                 attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt
index 9dedd13..d8db501 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt
@@ -21,6 +21,7 @@
 import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent
 import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsageContext.MavenScope
+import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
 import org.jetbrains.kotlin.gradle.utils.getValue
 
 internal data class ModuleCoordinates(
@@ -222,6 +223,8 @@
         configurationName in compilation.relatedConfigurationNames ||
                 configurationName == compilation.target.apiElementsConfigurationName ||
                 configurationName == compilation.target.runtimeElementsConfigurationName ||
-                configurationName == compilation.target.defaultConfigurationName
+                configurationName == compilation.target.defaultConfigurationName ||
+                configurationName == (compilation.target as? KotlinJsIrTarget)?.unpackedApiConfigurationName ||
+                configurationName == (compilation.target as? KotlinJsIrTarget)?.unpackedRuntimeConfigurationName
     }
 }
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt
index c7cc37d..cfdb008 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt
@@ -7,6 +7,34 @@
 
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
 import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationImpl
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlinCompileConfig
+import org.jetbrains.kotlin.gradle.tasks.configuration.Kotlin2JsCompileConfig
 import javax.inject.Inject
 
-open class KotlinJsIrCompilation @Inject internal constructor(compilation: KotlinCompilationImpl) : KotlinJsCompilation(compilation)
\ No newline at end of file
+open class KotlinJsIrCompilation @Inject internal constructor(compilation: KotlinCompilationImpl) : KotlinJsCompilation(compilation) {
+    val compileDirectoryArtifactView = compilation.configurations
+        .compileDependencyConfiguration
+        .incoming
+        .artifactView { artifactView ->
+            artifactView.attributes.attribute(
+                BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+            )
+        }
+
+    val compileDirectoryFiles
+        get() = compileDirectoryArtifactView.files
+
+    val runtimeDirectoryArtifactView = compilation.configurations
+        .runtimeDependencyConfiguration!!
+        .incoming
+        .artifactView { artifactView ->
+            artifactView.attributes.attribute(
+                BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+            )
+        }
+
+    val runtimeDirectoryFiles
+        get() = runtimeDirectoryArtifactView.files
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt
index 3d90dee..4056657 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt
@@ -84,6 +84,18 @@
             "commonFakeApiElements"
         )
 
+    val unpackedApiConfigurationName: String
+        get() = lowerCamelCaseName(
+            "unpacked",
+            apiElementsConfigurationName
+        )
+
+    val unpackedRuntimeConfigurationName: String
+        get() = lowerCamelCaseName(
+            "unpacked",
+            runtimeElementsConfigurationName
+        )
+
     val disambiguationClassifierInPlatform: String?
         get() = if (mixedMode) {
             disambiguationClassifier?.removeJsCompilerSuffix(KotlinJsCompilerType.IR)
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 3b6258f..ab95198 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,7 +5,11 @@
 
 package org.jetbrains.kotlin.gradle.targets.js.ir
 
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.attributes.Category
+import org.gradle.api.attributes.LibraryElements
 import org.gradle.api.attributes.Usage
+import org.gradle.api.internal.artifacts.ArtifactAttributes
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.api.tasks.bundling.Jar
 import org.gradle.api.tasks.bundling.Zip
@@ -15,9 +19,12 @@
 import org.jetbrains.kotlin.gradle.plugin.*
 import org.jetbrains.kotlin.gradle.plugin.internal.BasePluginConfiguration
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
+import org.jetbrains.kotlin.gradle.plugin.mpp.internal
 import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.libsDirectory
 import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
 import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
+import org.jetbrains.kotlin.gradle.tasks.configuration.BaseKotlinCompileConfig.Companion.ARTIFACT_TYPE_ATTRIBUTE
+import org.jetbrains.kotlin.gradle.tasks.configuration.Kotlin2JsCompileConfig
 import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
 import org.jetbrains.kotlin.gradle.testing.testTaskName
 
@@ -69,6 +76,14 @@
 
     override fun createArchiveTasks(target: KotlinJsIrTarget): TaskProvider<out Zip> {
         val libsDirectory = target.project.libsDirectory
+        val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+        target.project.artifacts.add(target.unpackedApiConfigurationName, mainCompilation.compileTaskProvider.flatMap { it.destinationDirectory }) {
+            it.builtBy(mainCompilation.compileTaskProvider)
+        }
+
+        target.project.artifacts.add(target.unpackedRuntimeConfigurationName, mainCompilation.compileTaskProvider.flatMap { it.destinationDirectory }) {
+            it.builtBy(mainCompilation.compileTaskProvider)
+        }
         return super.createArchiveTasks(target).apply {
             configure {
                 it.archiveExtension.set(KLIB_TYPE)
@@ -110,6 +125,45 @@
     override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) {
         super.defineConfigurationsForTarget(target)
 
+        val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
+
+        target.project.configurations.maybeCreate(
+            target.unpackedApiConfigurationName
+        ).apply {
+            description = "Unpacked API elements for main."
+            isVisible = false
+            isCanBeResolved = false
+            isCanBeConsumed = true
+            attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
+            attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
+            extendsFrom(target.project.configurations.maybeCreate(mainCompilation.apiConfigurationName))
+            val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
+            runtimeConfiguration?.let { extendsFrom(it) }
+            usesPlatformOf(target)
+            attributes.attribute(
+                ARTIFACT_TYPE_ATTRIBUTE,
+                Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+            )
+        }
+
+        target.project.configurations.maybeCreate(target.unpackedRuntimeConfigurationName).apply {
+            description = "Unpacked elements of runtime for main."
+            isVisible = false
+            isCanBeConsumed = true
+            isCanBeResolved = false
+            attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
+            attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
+            val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
+            extendsFrom(mainCompilation.internal.configurations.implementationConfiguration)
+            extendsFrom(mainCompilation.internal.configurations.runtimeOnlyConfiguration)
+            runtimeConfiguration?.let { extendsFrom(it) }
+            usesPlatformOf(target)
+            attributes.attribute(
+                ARTIFACT_TYPE_ATTRIBUTE,
+                Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+            )
+        }
+
         if (target.isMpp!!) return
 
         target.project.configurations.maybeCreate(
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt
index 17faa10..95fb928 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt
@@ -12,8 +12,10 @@
 import org.gradle.process.internal.DefaultProcessForkOptions
 import org.gradle.work.NormalizeLineEndings
 import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
+import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
 import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
+import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
 import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.Companion.kotlinNodeJsExtension
 import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
 import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
@@ -81,7 +83,13 @@
     @get:NormalizeLineEndings
     @get:InputFiles
     val runtimeClasspath: FileCollection by lazy {
-        compilation.runtimeDependencyFiles
+        compilation.let { comp ->
+            if (comp.target.platformType == KotlinPlatformType.js && comp is KotlinJsIrCompilation) {
+                comp.runtimeDirectoryFiles
+            } else {
+                comp.runtimeDependencyFiles
+            }
+        }
     }
 
     @Suppress("unused")
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt
index 58913e6..2c6fa77 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Kotlin2JsCompile.kt
@@ -6,6 +6,7 @@
 package org.jetbrains.kotlin.gradle.tasks
 
 import org.gradle.api.InvalidUserDataException
+import org.gradle.api.file.ConfigurableFileCollection
 import org.gradle.api.file.Directory
 import org.gradle.api.file.DirectoryProperty
 import org.gradle.api.file.FileCollection
@@ -42,8 +43,10 @@
 import org.jetbrains.kotlin.gradle.tasks.internal.KotlinJsOptionsCompat
 import org.jetbrains.kotlin.gradle.utils.isParentOf
 import org.jetbrains.kotlin.gradle.utils.newInstance
+import org.jetbrains.kotlin.incremental.ChangedFiles
 import org.jetbrains.kotlin.gradle.utils.toPathsArray
 import org.jetbrains.kotlin.incremental.ClasspathChanges
+import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME
 import org.jetbrains.kotlin.library.impl.isKotlinLibrary
 import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
 import org.jetbrains.kotlin.utils.JsLibraryUtils
@@ -275,13 +278,27 @@
         }
 
     @get:Internal
+    abstract override val libraries: ConfigurableFileCollection
+
+    @get:InputFiles
+    @get:IgnoreEmptyDirectories
+    @get:NormalizeLineEndings
+    @get:PathSensitive(PathSensitivity.RELATIVE)
+    @get:Incremental
+    val realLibraries: FileCollection = libraries + friendDependencies
+
+    @get:Internal
     protected val libraryFilter: (File) -> Boolean
         get() = { file ->
             libraryFilterCacheService.get().getOrCompute(file.asLibraryFilterCacheKey, libraryFilterBody)
         }
 
     override val incrementalProps: List<FileCollection>
-        get() = super.incrementalProps + listOf(friendDependencies)
+        get() = listOfNotNull(
+            sources,
+            realLibraries,
+            commonSourceSet
+        ) + listOf(friendDependencies)
 
     protected open fun processArgsBeforeCompile(args: K2JSCompilerArguments) = Unit
 
@@ -300,7 +317,7 @@
             logger.info(USING_JS_IR_BACKEND_MESSAGE)
         }
 
-        val dependencies = libraries
+        val dependencies = realLibraries
             .filter { it.exists() && libraryFilter(it) }
             .map { it.normalize().absolutePath }
 
@@ -322,8 +339,26 @@
 
         val icEnv = if (isIncrementalCompilationEnabled()) {
             logger.info(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
+            val changedFiles = getChangedFiles(inputChanges, incrementalProps)
+                .let {
+                    if (isIrBackendEnabled()) {
+                        when (it) {
+                            is ChangedFiles.Unknown -> it
+                            is ChangedFiles.Known -> {
+                                val predicate: (File) -> Boolean = { if (it.extension == "kt") true else it.name == KLIB_MANIFEST_FILE_NAME }
+                                ChangedFiles.Known(
+                                    it.modified
+                                        .filter(predicate),
+                                    it.removed
+                                        .filter(predicate),
+                                    it.forDependencies
+                                )
+                            }
+                        }
+                    } else it
+                }
             IncrementalCompilationEnvironment(
-                getChangedFiles(inputChanges, incrementalProps),
+                changedFiles,
                 ClasspathChanges.NotAvailableForJSCompiler,
                 taskBuildCacheableOutputDirectory.get().asFile,
                 multiModuleICSettings = multiModuleICSettings,
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 5056c0c..122053d 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
@@ -5,12 +5,24 @@
 
 package org.jetbrains.kotlin.gradle.tasks.configuration
 
+import org.gradle.api.Project
+import org.gradle.api.artifacts.transform.InputArtifact
+import org.gradle.api.artifacts.transform.TransformAction
+import org.gradle.api.artifacts.transform.TransformOutputs
+import org.gradle.api.artifacts.transform.TransformParameters
+import org.gradle.api.attributes.AttributeCompatibilityRule
+import org.gradle.api.attributes.CompatibilityCheckDetails
+import org.gradle.api.file.ArchiveOperations
+import org.gradle.api.file.FileSystemLocation
+import org.gradle.api.file.FileSystemOperations
+import org.gradle.api.provider.Provider
 import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
 import org.jetbrains.kotlin.gradle.targets.js.internal.LibraryFilterCachingService
 import org.jetbrains.kotlin.gradle.targets.js.ir.*
 import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
 import org.jetbrains.kotlin.gradle.utils.klibModuleName
 import java.io.File
+import javax.inject.Inject
 
 internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig<Kotlin2JsCompile>
 
@@ -104,4 +116,70 @@
             }
         }
     }
+
+    companion object {
+        private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_js_compile_transforms_registered"
+        const val UNPACKED_KLIB_ARTIFACT_TYPE = "unpacked-klib-js"
+
+        fun registerTransformsOnce(project: Project) {
+            if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) {
+                return
+            }
+            project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true
+
+            project.dependencies.registerTransform(Unzip::class.java) {
+                it.from.attribute(BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE, BaseKotlinCompileConfig.JAR_ARTIFACT_TYPE)
+                it.to.attribute(
+                    BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                    Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+                )
+            }
+
+            project.dependencies.registerTransform(Unzip::class.java) {
+                it.from.attribute(BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE, "klib")
+                it.to.attribute(
+                    BaseKotlinCompileConfig.ARTIFACT_TYPE_ATTRIBUTE,
+                    Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE
+                )
+            }
+        }
+    }
+}
+
+class ArtifactTypeCompatibilityRule : AttributeCompatibilityRule<String> {
+    override fun execute(details: CompatibilityCheckDetails<String>) {
+        if (details.consumerValue != Kotlin2JsCompileConfig.UNPACKED_KLIB_ARTIFACT_TYPE) return
+        val producerValue: String = details.producerValue ?: return details.compatible()
+
+        if (producerValue != "jar" && producerValue != "klib") {
+            return details.compatible()
+        }
+
+        details.incompatible()
+    }
+}
+
+abstract class Unzip : TransformAction<TransformParameters.None> {
+    @get:InputArtifact
+    abstract val inputArtifact: Provider<FileSystemLocation>
+
+    @get:Inject
+    abstract val fs: FileSystemOperations
+
+    @get:Inject
+    abstract val archiveOperations: ArchiveOperations
+
+    override
+    fun transform(outputs: TransformOutputs) {
+        val input = inputArtifact.get().asFile
+        val unzipDir = outputs.dir(input.name)
+        unzipTo(input, unzipDir)
+    }
+
+    private fun unzipTo(zipFile: File, unzipDir: File) {
+        fs.copy {
+            it.from(archiveOperations.zipTree(zipFile))
+            it.into(unzipDir)
+        }
+    }
 }
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt
index 3bef6e1..9516254 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt
@@ -108,7 +108,7 @@
 
         val ARTIFACT_TYPE_ATTRIBUTE: Attribute<String> = Attribute.of("artifactType", String::class.java)
         private const val DIRECTORY_ARTIFACT_TYPE = "directory"
-        private const val JAR_ARTIFACT_TYPE = "jar"
+        const val JAR_ARTIFACT_TYPE = "jar"
         const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot"
 
         private fun getDefaultLangSetting(project: Project, ext: KotlinTopLevelExtension): Provider<LanguageSettings> {