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.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
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.targets.js.webpack.KotlinWebpack
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
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) :
|
class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
||||||
KotlinTargetConfigurator<KotlinJsCompilation>(true, true, kotlinPluginVersion) {
|
KotlinTargetConfigurator<KotlinJsCompilation>(true, true, kotlinPluginVersion) {
|
||||||
@@ -25,7 +27,7 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
|||||||
|
|
||||||
platformTarget.compilations.all {
|
platformTarget.compilations.all {
|
||||||
it.compileKotlinTask.kotlinOptions {
|
it.compileKotlinTask.kotlinOptions {
|
||||||
moduleKind = "commonjs"
|
moduleKind = "umd"
|
||||||
sourceMap = true
|
sourceMap = true
|
||||||
sourceMapEmbedSources = null
|
sourceMapEmbedSources = null
|
||||||
}
|
}
|
||||||
@@ -34,7 +36,7 @@ class KotlinJsTargetConfigurator(kotlinPluginVersion: String) :
|
|||||||
|
|
||||||
override fun configureTest(target: KotlinOnlyTarget<KotlinJsCompilation>) {
|
override fun configureTest(target: KotlinOnlyTarget<KotlinJsCompilation>) {
|
||||||
val project = target.project
|
val project = target.project
|
||||||
val npmProject = NpmProject[project]
|
val npmProject = NpmProjectLayout[project]
|
||||||
|
|
||||||
target.compilations.all { compilation ->
|
target.compilations.all { compilation ->
|
||||||
if (isTestCompilation(compilation)) {
|
if (isTestCompilation(compilation)) {
|
||||||
|
|||||||
+63
-5
@@ -5,11 +5,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.js.npm
|
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.api.Project
|
||||||
|
import org.gradle.process.ExecSpec
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin
|
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
|
import java.io.File
|
||||||
|
|
||||||
class NpmProjectLayout(val nodeWorkDir: File) {
|
class NpmProjectLayout(
|
||||||
|
val project: Project,
|
||||||
|
val nodeWorkDir: File,
|
||||||
|
val managed: Boolean
|
||||||
|
) {
|
||||||
val nodeModulesDir
|
val nodeModulesDir
|
||||||
get() = nodeWorkDir.resolve(NODE_MODULES)
|
get() = nodeWorkDir.resolve(NODE_MODULES)
|
||||||
|
|
||||||
@@ -18,18 +28,66 @@ class NpmProjectLayout(val nodeWorkDir: File) {
|
|||||||
return nodeWorkDir.resolve(PACKAGE_JSON)
|
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 {
|
companion object {
|
||||||
const val PACKAGE_JSON = "package.json"
|
const val PACKAGE_JSON = "package.json"
|
||||||
const val NODE_MODULES = "node_modules"
|
const val NODE_MODULES = "node_modules"
|
||||||
|
|
||||||
operator fun get(project: Project): NpmProjectLayout {
|
operator fun get(project: Project): NpmProjectLayout {
|
||||||
val manageNodeModules = NodeJsPlugin[project].manageNodeModules
|
val nodeJsRootExtension = NodeJsPlugin.apply(project)
|
||||||
|
|
||||||
|
val manageNodeModules = nodeJsRootExtension.root.manageNodeModules
|
||||||
|
|
||||||
val nodeWorkDir =
|
val nodeWorkDir =
|
||||||
if (manageNodeModules) project.rootDir
|
if (manageNodeModules) project.projectDir
|
||||||
else project.buildDir
|
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.gradle.api.Project
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
|
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.KotlinPlatformType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
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.NodeJsPlugin
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
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 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
|
val resolved = process?.resolved
|
||||||
|
|
||||||
return if (resolved != null) AlreadyResolved(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()
|
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 packageManager = nodeJs.packageManager
|
||||||
private val hoistGradleNodeModules = packageManager.hoistGradleNodeModules
|
private val hoistGradleNodeModules = npmProject.hoistGradleNodeModules
|
||||||
private val npmPackages = mutableListOf<NpmPackage>()
|
private val npmPackages = mutableListOf<NpmPackage>()
|
||||||
private val gson = GsonBuilder()
|
private val gson = GsonBuilder()
|
||||||
.setPrettyPrinting()
|
.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(
|
class NpmPackage(
|
||||||
val project: Project,
|
val project: Project,
|
||||||
@@ -91,14 +100,14 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
|||||||
private fun resolve(
|
private fun resolve(
|
||||||
project: Project,
|
project: Project,
|
||||||
parentGradleNodeModules: GradleNodeModulesSync?
|
parentGradleNodeModules: GradleNodeModulesSync?
|
||||||
): ResolvedProject? {
|
): Boolean {
|
||||||
val existedProcess = ProjectData[project]
|
val existedProcess = ProjectData[project]
|
||||||
val process = if (existedProcess != null) {
|
if (existedProcess != null) {
|
||||||
if (existedProcess.resolved != null) error("yarn dependencies for $project already resolved")
|
if (existedProcess.resolved != null) error("yarn dependencies for $project already resolved")
|
||||||
else {
|
else {
|
||||||
// called inside resolution of classpath (from visitTarget)
|
// called inside resolution of classpath (from visitTarget)
|
||||||
// we should return as we are already in progress
|
// we should return as we are already in progress
|
||||||
return null
|
return false
|
||||||
}
|
}
|
||||||
} else ProjectData().also {
|
} else ProjectData().also {
|
||||||
ProjectData[project] = it
|
ProjectData[project] = it
|
||||||
@@ -133,10 +142,7 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
|||||||
gradleNodeModules.sync()
|
gradleNodeModules.sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
val npmDependencies = npmPackage?.npmDependencies ?: setOf()
|
return true
|
||||||
return ResolvedProject(npmDependencies).also {
|
|
||||||
process.resolved = it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newGradleNodeModulesSync(project: Project): GradleNodeModulesSync {
|
private fun newGradleNodeModulesSync(project: Project): GradleNodeModulesSync {
|
||||||
@@ -150,40 +156,53 @@ internal class NpmResolver private constructor(val rootProject: Project) {
|
|||||||
gradleComponentsSync: GradleNodeModulesSync
|
gradleComponentsSync: GradleNodeModulesSync
|
||||||
): NpmPackage? {
|
): NpmPackage? {
|
||||||
val packageJson = PackageJson(project.name, project.version.toString())
|
val packageJson = PackageJson(project.name, project.version.toString())
|
||||||
val transitiveDependencies = mutableListOf<GradleNodeModulesSync.TransitiveNpmDependency>()
|
|
||||||
|
|
||||||
val kotlin = project.kotlinExtension
|
|
||||||
val npmDependencies = mutableSetOf<NpmDependency>()
|
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 {
|
visitNpmDependencies(project, npmDependencies, gradleComponentsSync, packageJson)
|
||||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
|
||||||
}
|
|
||||||
|
|
||||||
transitiveDependencies.forEach {
|
project.nodeJs.packageJsonHandlers.forEach {
|
||||||
packageJson.dependencies[it.key] = chooseVersion(packageJson.dependencies[it.key], it.version)
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeJsExtension[project].packageJsonHandlers.forEach {
|
|
||||||
it(packageJson)
|
it(packageJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project == rootProject) {
|
val packageJsonRequired = if (project == rootProject) {
|
||||||
packageManager.hookRootPackage(rootProject, packageJson, npmPackages)
|
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 =
|
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.api.tasks.*
|
||||||
import org.gradle.process.internal.ExecHandleFactory
|
import org.gradle.process.internal.ExecHandleFactory
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
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.NpmResolver
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
|
||||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
@@ -64,7 +64,7 @@ open class KotlinWebpack : DefaultTask() {
|
|||||||
|
|
||||||
NpmResolver.resolve(project)
|
NpmResolver.resolve(project)
|
||||||
|
|
||||||
val npmProjectLayout = NpmProject[project]
|
val npmProjectLayout = NpmProjectLayout[project]
|
||||||
|
|
||||||
configFile.writeText(buildConfig())
|
configFile.writeText(buildConfig())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user