Gradle: webpack
#KT-31013 Fixed #KT-31014 Fixed
This commit is contained in:
+5
-3
@@ -8,9 +8,11 @@ package org.jetbrains.kotlin.gradle.targets.js
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout
|
||||
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.createOrRegisterTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
|
||||
class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
||||
KotlinTargetConfigurator<KotlinJsCompilation>(true, true, kotlinPluginVersion) {
|
||||
@@ -25,7 +27,7 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
||||
|
||||
platformTarget.compilations.all {
|
||||
it.compileKotlinTask.kotlinOptions {
|
||||
moduleKind = "commonjs"
|
||||
moduleKind = "umd"
|
||||
sourceMap = true
|
||||
sourceMapEmbedSources = null
|
||||
}
|
||||
@@ -34,7 +36,7 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
||||
|
||||
override fun configureTest(target: KotlinOnlyTarget<KotlinJsCompilation>) {
|
||||
val project = target.project
|
||||
val npmProject = NpmProject[project]
|
||||
val npmProject = NpmProjectLayout[project]
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
if (isTestCompilation(compilation)) {
|
||||
|
||||
+63
-5
@@ -5,11 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
import groovy.transform.TailRecursive
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.process.ExecSpec
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.nodeJs
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
import java.io.File
|
||||
|
||||
class NpmProjectLayout(val nodeWorkDir: File) {
|
||||
class NpmProjectLayout(
|
||||
val project: Project,
|
||||
val nodeWorkDir: File,
|
||||
val managed: Boolean
|
||||
) {
|
||||
val nodeModulesDir
|
||||
get() = nodeWorkDir.resolve(NODE_MODULES)
|
||||
|
||||
@@ -18,18 +28,66 @@ class NpmProjectLayout(val nodeWorkDir: File) {
|
||||
return nodeWorkDir.resolve(PACKAGE_JSON)
|
||||
}
|
||||
|
||||
fun useTool(exec: ExecSpec, tool: String, vararg args: String) {
|
||||
NpmResolver.resolve(project)
|
||||
|
||||
exec.workingDir = nodeWorkDir
|
||||
exec.executable = project.nodeJs.root.environment.nodeExecutable
|
||||
exec.args = listOf(findModule(tool)) + args
|
||||
}
|
||||
|
||||
val hoistGradleNodeModules: Boolean
|
||||
get() = project.nodeJs.root.packageManager.getHoistGradleNodeModules(project)
|
||||
|
||||
val gradleNodeModulesDir: File
|
||||
get() =
|
||||
if (hoistGradleNodeModules) project.rootProject.npmProject.nodeModulesDir
|
||||
else nodeModulesDir
|
||||
|
||||
fun moduleOutput(compilationTask: Kotlin2JsCompile): File {
|
||||
return gradleNodeModulesDir.resolve(compilationTask.outputFile.name)
|
||||
}
|
||||
|
||||
@TailRecursive
|
||||
fun findModule(name: String, src: NpmProjectLayout = this): String {
|
||||
val file = nodeModulesDir.resolve(name)
|
||||
if (file.isFile) return file.canonicalPath
|
||||
if (file.isDirectory) {
|
||||
val packageJsonFile = file.resolve("package.json")
|
||||
val main: String = (if (packageJsonFile.isFile) {
|
||||
val packageJson = packageJsonFile.reader().use {
|
||||
Gson().fromJson(it, JsonObject::class.java)
|
||||
}
|
||||
|
||||
packageJson["main"] as? String? ?: packageJson["module"] as? String? ?: packageJson["browser"] as? String?
|
||||
} else null) ?: "index.js"
|
||||
|
||||
val mainFile = file.resolve(main)
|
||||
if (mainFile.isFile) return mainFile.canonicalPath
|
||||
}
|
||||
|
||||
val parent = project.parent
|
||||
return if (!managed || parent == null) error("Cannot find node module $name in $src")
|
||||
else NpmProjectLayout[parent].findModule(name, src)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PACKAGE_JSON = "package.json"
|
||||
const val NODE_MODULES = "node_modules"
|
||||
|
||||
operator fun get(project: Project): NpmProjectLayout {
|
||||
val manageNodeModules = NodeJsPlugin[project].manageNodeModules
|
||||
val nodeJsRootExtension = NodeJsPlugin.apply(project)
|
||||
|
||||
val manageNodeModules = nodeJsRootExtension.root.manageNodeModules
|
||||
|
||||
val nodeWorkDir =
|
||||
if (manageNodeModules) project.rootDir
|
||||
if (manageNodeModules) project.projectDir
|
||||
else project.buildDir
|
||||
|
||||
return NpmProjectLayout(nodeWorkDir)
|
||||
return NpmProjectLayout(project, nodeWorkDir, manageNodeModules)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val Project.npmProject
|
||||
get() = NpmProjectLayout[this]
|
||||
+58
-39
@@ -10,12 +10,12 @@ import com.google.gson.GsonBuilder
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExtension
|
||||
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.*
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,11 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
val resolved = process?.resolved
|
||||
|
||||
return if (resolved != null) AlreadyResolved(resolved)
|
||||
else ResolvedNow(NpmResolver(rootProject).resolve(rootProject, null)!!)
|
||||
else {
|
||||
val resolver = NpmResolver(rootProject)
|
||||
check(resolver.resolve(rootProject, null))
|
||||
ResolvedNow(ResolvedProject(resolver.npmPackages))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +54,10 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
class ResolvedNow(val resolution: ResolvedProject) : ResolutionCallResult()
|
||||
}
|
||||
|
||||
private val nodeJs = NodeJsPlugin[rootProject]
|
||||
private val nodeJs = NodeJsPlugin.apply(rootProject).root
|
||||
private val npmProject = rootProject.npmProject
|
||||
private val packageManager = nodeJs.packageManager
|
||||
private val hoistGradleNodeModules = packageManager.hoistGradleNodeModules
|
||||
private val hoistGradleNodeModules = npmProject.hoistGradleNodeModules
|
||||
private val npmPackages = mutableListOf<NpmPackage>()
|
||||
private val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
@@ -66,7 +71,11 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvedProject(val dependencies: Set<NpmDependency>)
|
||||
class ResolvedProject(val npmPackages: Collection<NpmPackage>) {
|
||||
val dependencies by lazy {
|
||||
npmPackages.flatMapTo(mutableSetOf()) { it.npmDependencies }
|
||||
}
|
||||
}
|
||||
|
||||
class NpmPackage(
|
||||
val project: Project,
|
||||
@@ -91,14 +100,14 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
private fun resolve(
|
||||
project: Project,
|
||||
parentGradleNodeModules: GradleNodeModulesSync?
|
||||
): ResolvedProject? {
|
||||
): Boolean {
|
||||
val existedProcess = ProjectData[project]
|
||||
val process = if (existedProcess != null) {
|
||||
if (existedProcess != null) {
|
||||
if (existedProcess.resolved != null) error("yarn dependencies for $project already resolved")
|
||||
else {
|
||||
// called inside resolution of classpath (from visitTarget)
|
||||
// we should return as we are already in progress
|
||||
return null
|
||||
return false
|
||||
}
|
||||
} else ProjectData().also {
|
||||
ProjectData[project] = it
|
||||
@@ -133,10 +142,7 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
gradleNodeModules.sync()
|
||||
}
|
||||
|
||||
val npmDependencies = npmPackage?.npmDependencies ?: setOf()
|
||||
return ResolvedProject(npmDependencies).also {
|
||||
process.resolved = it
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun newGradleNodeModulesSync(project: Project): GradleNodeModulesSync {
|
||||
@@ -150,40 +156,53 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
||||
gradleComponentsSync: GradleNodeModulesSync
|
||||
): NpmPackage? {
|
||||
val packageJson = PackageJson(project.name, project.version.toString())
|
||||
val transitiveDependencies = mutableListOf<GradleNodeModulesSync.TransitiveNpmDependency>()
|
||||
|
||||
val kotlin = project.kotlinExtension
|
||||
val npmDependencies = mutableSetOf<NpmDependency>()
|
||||
when (kotlin) {
|
||||
is KotlinSingleTargetExtension -> visitTarget(
|
||||
kotlin.target,
|
||||
project,
|
||||
npmDependencies,
|
||||
gradleComponentsSync,
|
||||
transitiveDependencies
|
||||
)
|
||||
is KotlinMultiplatformExtension -> kotlin.targets.forEach {
|
||||
visitTarget(it, project, npmDependencies, gradleComponentsSync, transitiveDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
npmDependencies.forEach {
|
||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
||||
}
|
||||
visitNpmDependencies(project, npmDependencies, gradleComponentsSync, packageJson)
|
||||
|
||||
transitiveDependencies.forEach {
|
||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
||||
}
|
||||
|
||||
NodeJsExtension[project].packageJsonHandlers.forEach {
|
||||
project.nodeJs.packageJsonHandlers.forEach {
|
||||
it(packageJson)
|
||||
}
|
||||
|
||||
if (project == rootProject) {
|
||||
val packageJsonRequired = if (project == rootProject) {
|
||||
packageManager.hookRootPackage(rootProject, packageJson, npmPackages)
|
||||
}
|
||||
} else false
|
||||
|
||||
return if (!packageJson.empty) NpmPackage(project, packageJson, npmDependencies) else null
|
||||
return if (packageJsonRequired || !packageJson.empty) NpmPackage(project, packageJson, npmDependencies) else null
|
||||
}
|
||||
|
||||
private fun visitNpmDependencies(
|
||||
project: Project,
|
||||
npmDependencies: MutableSet<NpmDependency>,
|
||||
gradleComponentsSync: GradleNodeModulesSync,
|
||||
packageJson: PackageJson
|
||||
) {
|
||||
val kotlin = project.kotlinExtensionOrNull
|
||||
|
||||
if (kotlin != null) {
|
||||
val transitiveDependencies = mutableListOf<GradleNodeModulesSync.TransitiveNpmDependency>()
|
||||
|
||||
when (kotlin) {
|
||||
is KotlinSingleTargetExtension -> visitTarget(
|
||||
kotlin.target,
|
||||
project,
|
||||
npmDependencies,
|
||||
gradleComponentsSync,
|
||||
transitiveDependencies
|
||||
)
|
||||
is KotlinMultiplatformExtension -> kotlin.targets.forEach {
|
||||
visitTarget(it, project, npmDependencies, gradleComponentsSync, transitiveDependencies)
|
||||
}
|
||||
}
|
||||
|
||||
npmDependencies.forEach {
|
||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
||||
}
|
||||
|
||||
transitiveDependencies.forEach {
|
||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseVersion(oldVersion: String?, newVersion: String): String =
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.internal.ExecHandleFactory
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProjectLayout
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmResolver
|
||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
@@ -64,7 +64,7 @@ open class KotlinWebpack : DefaultTask() {
|
||||
|
||||
NpmResolver.resolve(project)
|
||||
|
||||
val npmProjectLayout = NpmProject[project]
|
||||
val npmProjectLayout = NpmProjectLayout[project]
|
||||
|
||||
configFile.writeText(buildConfig())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user