Gradle: webpack

#KT-31013 Fixed
	#KT-31014 Fixed
This commit is contained in:
Sergey Rostov
2019-04-11 15:46:52 +03:00
parent 5372fcef69
commit 39ce257e64
4 changed files with 128 additions and 49 deletions
@@ -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)) {
@@ -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]
@@ -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 =
@@ -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())