Hi! I see that a bunch of methods in the Kotlin Gr...
# javascript
c
Hi! I see that a bunch of methods in the Kotlin Gradle Plugin have been deprecated relating to Node. In particular I have this code:
Copy code
val kotlinEnvironment = project.rootProject.kotlinNodeJsExtension    // ⚠ deprecated
	nodePath.set(
		kotlinEnvironment
			.requireConfigured()                                         // ⚠ deprecated
			.let { RegularFile { File(it.nodeExecutable) } }             // ⚠ deprecated
	)
I'd like to migrate this code to the new way. Basically all it does is find out where the Kotlin plugin installed NodeJS (because we have some other tools that need NodeJS with the exact same version as the Kotlin plugin is using). From what I can gather: •
project.rootProject.kotlinNodeJsExtension
should be not use
rootProject
anymore and should use an extension related to
NodeJsPlugin
, but I can't find which exactly •
requireConfigured()
should be needed anymore because the new extension takes care of that itself (?) •
nodeExecutable
has been replaced by just
executable
? What am I missing?
I'm guessing something like this?
Copy code
val nodeJsEnvironment = project.extensions.getByType(NodeJsEnvSpec::class.java)
	nodePath.set {
		nodeJsEnvironment
			.installationDirectory
			.asFile.get()
	}
but I'm getting
Copy code
Unable to load class 'org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnvSpec'.

This is an unexpected error. Please file a bug containing the idea.log file.
r
c
In my case I can't just ignore the error, it crashes on Kotlin 2.1.0
@Ilya Goncharov [JB] you mentioned in the previous thread that something was going to be added?
i
The actual usage will be something like
Copy code
plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin> {
    the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnvSpec>().executable // Provider<String>
}
c
@Ilya Goncharov [JB] when you say "will be", this isn't yet published, right? I don't see the
.executable
field in 2.1.0
i
c
Are you aware of a workaround until the next version lands? (even if it's not pretty, since a proper fix will come soon)—my plugin fails on all 2.1.0 projects 😅
i
Could you suppress deprecations with
@Suppress("DEPRECATION"
?
c
@Ilya Goncharov [JB] I could in KGP 2.0.20, but I think the fields are completely gone in KGP 2.1.0? At least IntelliJ can't find where they moved to
s
Was this addressed with 2.1.10?
c
NodeJsEnvSpec.executable
does not seem to exist in 2.1.10. If I understand the GitHub correctly, it is in 2.1.20-Beta2?
👍 1
@Ilya Goncharov [JB] I'm trying the solution you mentioned in https://kotlinlang.slack.com/archives/C0B8L3U69/p1736419886059929?thread_ts=1736281644.920429&amp;cid=C0B8L3U69, now that Kotlin 2.1.20 is out, and I'm getting
Copy code
org.gradle.api.UnknownDomainObjectException: Extension of type 'NodeJsEnvSpec' does not exist. Currently registered extension types: [ExtraPropertiesExtension]
This seems to work, but it's a bit disappointing how convoluted it is.
Ah, it doesn't really work.
Copy code
- Gradle detected a problem with the following location: '/home/ivan/.gradle/nodejs/node-v22.0.0-linux-x64/bin/node'.
    
    Reason: Task ':app:viteBuild' uses this output of task ':core:kotlinNodeJsSetup' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed.
I'm confused why
:core
would have a
:kotlinNodeJsSetup
, I thought only the root module had that task?
👀 1
s
@Ilya Goncharov [JB] ☝️ Could you please help with this?
i
Hi, yes, now Node.js can be configured per project, and it helps to set independent versions of Node.js for different subprojects, if it is necessary https://youtrack.jetbrains.com/issue/KT-69628/K-Wasm-Node.js-version-per-project
thank you color 1
c
@Ilya Goncharov [JB] There seems to be something configured incorrectly with this feature then. As you can see in the error message I shared, Gradle detects that
:app:viteBuild
uses a file generated by
:core:kotlinNodeJsSetup
, so evidently they don't use separated installations.
Unless I missed something, it seems the only way for this feature to work is if the
:app:viteBuild
task declares a
mustRunAfter
on each
:xxx:kotlinNodeJsSetup
where
:xxx
is each project that appears in the dependencies of
:app
s
Any updates on this ☝️ @Ilya Goncharov [JB]?
Any updates here, please?
i
Hi, as I understand you have to declare dependency only on specific project's kotlinNodeJsSetup, not all of them But additionally you may need dependency on kotlinNomInstall task
c
@Ilya Goncharov [JB] this is not what the Gradle error message says. Because all modules'
kotlinNodeJsSetup
tasks output to
~/.gradle/nodejs/node-v22.0.0-linux-x64/bin/node
, and I need to declare it as an input, Gradle considers that there should be an explicit dependency from my task to all modules'
kotlinNodeJsSetup
tasks.
Here you can see the
:app:viteBuild
task which is declared to depend on
:app:kotlinNodeJsSetup
. Gradle requests that it should also be declared to depend on
:core:kotlinNodeJsSetup
With this change, the project builds, but it's probably going to break down quite badly as soon as there is a project that doesn't use the
kotlin("multiplatform")
plugin
r
Just FYI, I'm on 2.2.0-RC now and I'm using this function to get nodejs executable:
Copy code
private fun Project.nodeJsBinaryProvider(): Provider<String> {
        val nodeJsEnvSpec = providers.provider {
            extensions.getByType(NodeJsEnvSpec::class)
        }
        return nodeJsEnvSpec.flatMap { it.executable }
    }
It's definitely simpler than the code, I was using earlier.
👍 1
c
I tried rewriting the plugin to use
@RequiresNpmDependencies
, but the problem remains the same, if there are multiple KotlinJS projects in the build, the build fails because multiple of them create the same Node installation.
👍 1