diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt index a296b8d3f4d..cdc8183c7b5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/GradleNodeModule.kt @@ -10,4 +10,4 @@ import java.io.File /** * Fake NodeJS module directory created from Gradle external module */ -class GradleNodeModule(val name: String, val version: String, val path: File) \ No newline at end of file +data class GradleNodeModule(val name: String, val version: String, val path: File) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt index b72f0e2c4fd..12149b4d6b7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectPackage.kt @@ -15,5 +15,6 @@ class NpmProjectPackage( val npmProject: NpmProject, val npmDependencies: Collection, val gradleDependencies: NpmGradleDependencies, - val packageJson: PackageJson + val packageJson: PackageJson, + val hasNodeModulesDependentTasks: Boolean ) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt index 7320db7334f..c5dfe5ca3ed 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectVisitor.kt @@ -28,17 +28,16 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project private val byCompilation = mutableMapOf() private val byNpmDependency = mutableMapOf() private val taskRequirements = mutableMapOf>() - private val requiredFromTasksByCompilation = mutableMapOf>() + private val requiredFromTasksByCompilation = mutableMapOf>() private fun addTaskRequirements(task: RequiresNpmDependencies) { val requirements = task.requiredNpmDependencies.toList() taskRequirements[task] = requirements - val requiredDependenciesList = requiredFromTasksByCompilation.getOrPut(task.compilation) { mutableListOf() } - requirements.forEach { requiredDependency -> - requiredDependenciesList.add(requiredDependency.createDependency(project)) - } + requiredFromTasksByCompilation + .getOrPut(task.compilation) { mutableListOf() } + .add(task) } private fun addNpmProject(resolved: NpmProjectPackage) { @@ -111,10 +110,14 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project packageJson.main = npmProject.main val requiredByTasks = requiredFromTasksByCompilation[compilation] + var nodeModulesRequired = false if (requiredByTasks != null && requiredByTasks.isNotEmpty()) { val configuration = project.configurations.create("$name-jsTools") requiredByTasks.forEach { - configuration.dependencies.add(it) + if (it.nodeModulesRequired) nodeModulesRequired = true + it.requiredNpmDependencies.forEach { requirement -> + configuration.dependencies.add(requirement.createDependency(project)) + } } configuration.resolve() visitConfiguration(configuration, npmDependencies, gradleDeps) @@ -139,7 +142,7 @@ internal class NpmProjectVisitor(val resolver: NpmResolver, val project: Project it(packageJson) } - val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson) + val npmPackage = NpmProjectPackage(project, npmProject, npmDependencies, gradleDeps, packageJson, nodeModulesRequired) npmPackage.packageJson.saveTo(npmProject.packageJsonFile) resolver.packageManager.resolveProject(npmPackage) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt index d9be1965253..4efff3f126e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmResolver.kt @@ -9,7 +9,9 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension +import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver.ResolutionCallResult.* +import java.nio.file.Files /** * Generates `package.json` file for [NpmProject] with npm or js dependencies and @@ -92,9 +94,12 @@ internal class NpmResolver private constructor(val rootProject: Project) : AutoC fun resolve() { resolve(rootProject) - if (allNpmPackages.isNotEmpty()) { - removeOutdatedPackages() + removeOutdatedPackages() + + if (allNpmPackages.any { it.npmDependencies.isNotEmpty() }) { packageManager.resolveRootProject(rootProject, allNpmPackages) + } else if (allNpmPackages.any { it.hasNodeModulesDependentTasks }) { + NpmSimpleLinker(rootProject).link(allNpmPackages) } close() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt new file mode 100644 index 00000000000..a31f29af514 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmSimpleLinker.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm + +import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs +import java.nio.file.Files + +/** + * Handles simple case, when there are no npm depenencies required, but some tasks steel needs + * node_modules with symlinked packages and packages_imported + */ +class NpmSimpleLinker(rootProject: Project) { + private val rootProjectNodeModules = rootProject.nodeJs.root.rootPackageDir.resolve(NpmProject.NODE_MODULES) + + fun link(projects: Collection) { + rootProjectNodeModules.listFiles()?.forEach { + val path = it.toPath() + when { + Files.isSymbolicLink(path) -> + Files.delete(path) + else -> it.deleteRecursively() + } + + } + + rootProjectNodeModules.mkdirs() + + // packages + projects.forEach { + Files.createSymbolicLink(getNodeModulePath(it.npmProject.name), it.npmProject.dir.canonicalFile.toPath()) + } + + // packages_imported + projects.flatMapTo(mutableSetOf()) { + it.gradleDependencies.externalModules.map { gradleNodeModule -> gradleNodeModule } + }.forEach { + Files.createSymbolicLink(getNodeModulePath(it.name), it.path.canonicalFile.toPath()) + } + } + + private fun getNodeModulePath(name: String) = + rootProjectNodeModules.resolve(name).canonicalFile.toPath() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/RequiresNpmDependencies.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/RequiresNpmDependencies.kt index 7f487e663aa..0cf81575e23 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/RequiresNpmDependencies.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/RequiresNpmDependencies.kt @@ -10,5 +10,6 @@ import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency interface RequiresNpmDependencies { val compilation: KotlinJsCompilation + val nodeModulesRequired: Boolean val requiredNpmDependencies: Collection } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt index 9b6fc27f062..6e226a3350a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTest.kt @@ -50,6 +50,9 @@ open class KotlinJsTest : KotlinTest(), RequiresNpmDependencies { val nodeModulesToLoad: List @Internal get() = listOf("./" + compilation.npmProject.main) + override val nodeModulesRequired: Boolean + @Internal get() = testFramework!!.nodeModulesRequired + override val requiredNpmDependencies: Collection @Internal get() = testFramework!!.requiredNpmDependencies diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTestFramework.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTestFramework.kt index 12b2085eac7..810cbbb9bd8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTestFramework.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinJsTestFramework.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.js.testing import org.gradle.process.ProcessForkOptions import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec -import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies interface KotlinJsTestFramework : RequiresNpmDependencies { @@ -18,4 +17,7 @@ interface KotlinJsTestFramework : RequiresNpmDependencies { forkOptions: ProcessForkOptions, nodeJsArgs: MutableList ): TCServiceMessagesTestExecutionSpec + + override val nodeModulesRequired: Boolean + get() = true } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt index 2d571aecf57..cbf08b1158a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt @@ -95,6 +95,9 @@ open class KotlinWebpack : DefaultTask(), RequiresNpmDependencies { ) ) + override val nodeModulesRequired: Boolean + @Internal get() = true + override val requiredNpmDependencies: Collection @Internal get() = mutableListOf().also { it.add(versions.webpack)