Skip to content

Update Yarn -> Npm #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .idea/kotlinx-rpc.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions .puppeteerrc.cjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
/*
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

const {join} = require('path');

const isCI = process.env.TEAMCITY_VERSION || process.env.GITHUB_ACTIONS;
const isTC = process.env.TEAMCITY_VERSION;
const isGA = process.env.GITHUB_ACTIONS;

if (isCI) {
if (isTC !== undefined || isGA !== undefined) {
/**
* @type {import("puppeteer").Configuration}
*/
Expand Down
3 changes: 3 additions & 0 deletions compiler-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ org.gradle.configuration-cache=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true

# https://youtrack.jetbrains.com/issue/KT-78504
kotlin.js.yarn=false

# development mode for kotlinx.rpc gradle plugin. Uses local project paths to apply the compiler plugin
kotlinx.rpc.plugin.internalDevelopment=true

Expand Down
71 changes: 70 additions & 1 deletion docs/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,74 @@ Here is a 'simple' guide for solving problems:
- Try different IDE version (last resort)
- Docker
- `Cannot connect to the Docker daemon` - open `Docker Desktop`
- Kotlin/Js or Kotlin/Wasm
- `kotlinUpgradePackageLock` or `kotlinWasmUpgradePackageLock` (and also `kotlinNpmInstall` or `kotlinWasmNpmInstall`)
have a funny tendency to fail sometimes, and you don't know why.
<br/>
I'll tell you!
<br/>
We use proxy repos, and sometimes dependencies get downloaded from the wrong source.
Make sure ALL urls in `package-lock.json` files start with `https://packages.jetbrains.team/npm/p/krpc/build-deps/`.
<br/>
If something doesn't work, your steps are:
- Delete `package-lock.json` file
- Delete `<REPO_ROOT>/build/js` / `<REPO_ROOT>/build/wasm`
- Run `kotlinUpgradePackageLock` / `kotlinWasmUpgradePackageLock`
- If the problem persists:
- Check that `<REPO_ROOT>/build/<target>/.npmrc` AND `<REPO_ROOT>/build/<target>/.yarnrc` are present
- Check that `.yarnrc` contains one line: `registry: "https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
- Check that `.npmrc` contains the following lines:
- `registry="https://packages.jetbrains.team/npm/p/krpc/build-deps/"`
- `always-auth=true`
- `save-exact=true`
- `//packages.jetbrains.team/npm/p/krpc/build-deps/:_authToken=<your_auth_token>`,
where `<your_auth_token>` is from the [proxy-repositories.md](proxy-repositories.md) guide.
- Check that `<USER_HOME>/.npmrc` / `<USER_HOME>/.yarnrc` don't interfere
command to debug. Replace versions of tools if needed.
- When you get the following error — `puppeteer` failed to run the installation script.
Reasons vary, try updating the version to a newer one,
check the [.puppeteerrc.cjs](../.puppeteerrc.cjs) and [chrome_bin.js](../karma/chrome_bin.js) files if they are valid js.

For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
at ChromeLauncher.resolveExecutablePath (/rpc/build/js/packages/kotlinx-rpc-utils-test/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:295:27)

- When the previous error is gone, you may get the next one.

Errors occurred during launch of browser for testing.
- ChromeHeadless
Please make sure that you have installed browsers.
Or change it via
browser {
testTask {
useKarma {
useFirefox()
useChrome()
useSafari()
}
}
}
This means the `puppeteer` failed to locate Chrome.
Either the cache dir is wrong (check [.puppeteerrc.cjs](../.puppeteerrc.cjs) file) or it really isn't there.
<br/>
Reasons again vary.
When `npm` installs `puppeteer`, it should execute script to install the browser too
(On CI to the `<ROOT_DIR>/.puppeteer/browsers` directory).
This absence may be caused by the `--ignore-scripts` flag.
Check the clean installation (`rm -rf build && ./gradlew clean cleanJsBrowserTest`) with `--debug` flag.
(Something like `./gradlew jsBrowserTest --debug`).
**IMPORTANT: run in docker with `TEAMCITY_VERSION` env var set, if you are chasing a CI fail**.
<br/>
The property is set in [npm.kt](../gradle-conventions/src/main/kotlin/util/tasks/npm.kt), see `ignoreScripts`,
it should be `false`.
<br/>
If this is not the case, check the debug log for other `node`-related issues.
Try installing browsers manually: `~/.gradle/nodejs/node-v22.0.0-linux-x64/bin/node build/js/node_modules/puppeteer/install.mjs`
If this works — problem is somewhere in KGP and probably your configs.
Check that your config (like ones with `ignoreScript`) are actually applied,
as they use on demand execution and may target wrong plugin or extension and never be executed.
<br/>
**Bonus**: it may not be installed, because npm install doesn't do this.
See the long comment in [npm.kt](../gradle-conventions/src/main/kotlin/util/tasks/npm.kt).

Something doesn't work, and you are sure it's not your fault? Report it appropriately! Don't be lazy.

Expand All @@ -377,7 +445,8 @@ all included builds (not subprojects) must reflect the change.
- `checkLegacyAbi` / `updateLegacyAbi` - ABI checks.
See https://kotlinlang.org/docs/whatsnew22.html#binary-compatibility-validation-included-in-kotlin-gradle-plugin.
Former BCV: https://github.com/Kotlin/binary-compatibility-validator
- `kotlinUpgradeYarnLock` - update [kotlin-js-store](../kotlin-js-store) contents, usually after Kotlin version update.
- `kotlinUpgradePackageLock` / `kotlinWasmUpgradePackageLock` - update [kotlin-js-store](../kotlin-js-store) contents,
usually after Kotlin version update.
- `updateDocsChangelog` - put modified [CONTRIBUTING.md](../CONTRIBUTING.md) into [topics](pages/kotlinx-rpc/topics)
- `detekt` - run detekt checks.
- `verifyPlatformTable` / `dumpPlatformTable` - Update [platforms.topic](pages/kotlinx-rpc/topics/platforms.topic)
Expand Down
3 changes: 3 additions & 0 deletions dokka-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ org.gradle.configuration-cache=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true

# https://youtrack.jetbrains.com/issue/KT-78504
kotlin.js.yarn=false

# development mode for kotlinx.rpc gradle plugin. Uses local project paths to apply the compiler plugin
kotlinx.rpc.plugin.internalDevelopment=true

Expand Down
26 changes: 26 additions & 0 deletions gradle-conventions-settings/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,36 @@
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
*/

plugins {
// Keep it in sync with libs.versions.toml
id("com.gradle.develocity") version "3.19.2"
}

rootProject.name = "gradle-conventions-settings"

// Code below is a hack because a chicken-egg problem, I can't use myself as a settings-plugin
apply(from = "src/main/kotlin/conventions-repositories.settings.gradle.kts")
apply(from = "src/main/kotlin/conventions-version-resolution.settings.gradle.kts")

include(":develocity")

// Should be in sync with ktorbuild.develocity.settings.gradle.kts
develocity {
server = "https://ge.jetbrains.com"
}

val isCIRun = providers.environmentVariable("TEAMCITY_VERSION").isPresent ||
providers.environmentVariable("GITHUB_ACTIONS").isPresent

buildCache {
if (isCIRun) {
local {
isEnabled = false
}
}

remote(develocity.buildCache) {
isPush = isCIRun
isEnabled = true
}
}
2 changes: 1 addition & 1 deletion gradle-conventions/src/main/kotlin/util/targets/js.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fun KmpConfig.configureJs() {
nodejs {
testTask {
useMocha {
timeout = "100s"
timeout = "300s"
}
}
}
Expand Down
151 changes: 121 additions & 30 deletions gradle-conventions/src/main/kotlin/util/tasks/npm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,50 @@ package util.tasks

import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.*
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsEnvSpec
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootEnvSpec
import org.jetbrains.kotlin.gradle.targets.js.npm.BaseNpmExtension
import org.jetbrains.kotlin.gradle.targets.js.npm.LockFileMismatchReport
import org.jetbrains.kotlin.gradle.targets.js.npm.NpmExtension
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsEnvSpec
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.wasm.nodejs.WasmNodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.wasm.npm.WasmNpmExtension
import org.jetbrains.kotlin.gradle.targets.web.nodejs.BaseNodeJsEnvSpec
import org.jetbrains.kotlin.gradle.targets.web.nodejs.BaseNodeJsRootExtension
import org.jetbrains.kotlin.gradle.targets.web.nodejs.CommonNodeJsRootPlugin
import util.other.optionalProperty
import util.other.spacePassword
import util.other.useProxyRepositories
import java.io.File

fun Project.configureNpm() {
val kotlinMasterBuild by optionalProperty()

val executeNpmLogin by tasks.registering {
const val PUPPETEER_BROWSERS_DIR = ".puppeteer"

private inline fun <
reified Plugin : CommonNodeJsRootPlugin,
reified Spec : BaseNodeJsEnvSpec,
reified RootExtension : BaseNodeJsRootExtension,
> Project.registerCustomNpmTasks(
target: String,
useProxy: Boolean,
) {
val capitalizedTarget = target.replaceFirstChar { it.titlecase() }
val login = tasks.register("execute${capitalizedTarget}NpmLogin") {
if (!useProxyRepositories) {
return@registering
return@register
}

val registryUrl = "https://packages.jetbrains.team/npm/p/krpc/build-deps/"

// To prevent leaking of credentials in VCS on dev machine use the build directory config file
val buildYarnConfigFile = File(project.rootDir, "build/js/.yarnrc")
val buildNpmConfigFile = File(project.rootDir, "build/js/.npmrc")
val buildYarnConfigFile = File(project.rootDir, "build/$target/.yarnrc")
val buildNpmConfigFile = File(project.rootDir, "build/$target/.npmrc")

val spacePassword: String? = spacePassword

Expand Down Expand Up @@ -64,36 +84,107 @@ fun Project.configureNpm() {
outputs.file(buildNpmConfigFile).withPropertyName("buildOutputNpmFile")
}

val useProxy = useProxyRepositories

plugins.withType(NodeJsRootPlugin::class.java).configureEach {
rootProject.extensions.configure<NodeJsEnvSpec> {
plugins.withType<Plugin>().configureEach {
extensions.configure<Spec> {
download = true

if (useProxy) {
downloadBaseUrl = "https://packages.jetbrains.team/files/p/krpc/build-deps/"
}
}

tasks.named("kotlinNpmInstall").configure {
dependsOn(executeNpmLogin)
val nodeExecutable = executable

extensions.configure<RootExtension> {
/**
* Long story short:
* We can use Yarn because of this: https://youtrack.jetbrains.com/issue/KT-78504
* So: `kotlin.js.yarn=false`
*
* When we use `npm` instead, it runs `npm install` task.
* That should install `puppeteer` package, which should run its script `install.mjs`.
* That script installs browsers for tests.
*
* If we pass `--ignore-scripts` to npm, the script won't be executed.
* KGP does it by default.
* So we set `ignoreScripts = false`.
* We set it for `NpmExtension` and `WasmNpmExtension` in `NodeJsRootPlugin` and `WasmNodeJsRootPlugin`
* respectively (and not their common supertype because it will not work)
*
* And this approach worked for Yarn.
* Script was executed, browsers were installed.
*
* For some reason, for `npm` it didn't work.
* Even with a proper flag (which I checked with a --debug flag).
*
* So we need to run the script manually AFTER `kotlinNpmInstall` (or `kotlinWasmNpmInstall`).
* But also, BEFORE every other action that comes after `kotlinNpmInstall` (or `kotlinWasmNpmInstall`),
* as otherwise there will be race in parallel tasks execution.
*
* Hence, all shenanigans.
*/
val puppeteerInstall = tasks.register<Exec>("puppeteerInstall$capitalizedTarget") {
commandLine(nodeExecutable.get(), "build/$target/node_modules/puppeteer/install.mjs")
workingDir = rootProject.projectDir

// keep in sync with <ROOT>/.puppeteer.cjs
outputs.dir(rootProject.projectDir.resolve(PUPPETEER_BROWSERS_DIR).resolve("browsers"))
}

npmInstallTaskProvider.configure {
dependsOn(login)
finalizedBy(puppeteerInstall)
}

tasks.matching { task ->
task.dependsOn.any { dependency ->
when (dependency) {
is Task -> dependency == npmInstallTaskProvider.get()
is TaskProvider<*> -> dependency == npmInstallTaskProvider
is String -> dependency == npmInstallTaskProvider.name
else -> false
}
}
}.configureEach {
dependsOn(puppeteerInstall)
}
}
}
}
}

// necessary for CI js tests
rootProject.plugins.withType<YarnPlugin> {
rootProject.extensions.configure<YarnRootEnvSpec> {
ignoreScripts = false
download = true
@Suppress("UnusedReceiverParameter")
fun BaseNpmExtension.configureNpmExtension(useProxy: Boolean, kotlinMasterBuild: Boolean) {
// todo it still doesn't work for an unknown reason, see 'puppeteerInstall*' tasks above
ignoreScripts = false // if true - puppeteer won't install browsers

yarnLockMismatchReport = if (useProxy && !kotlinMasterBuild) {
YarnLockMismatchReport.FAIL
} else {
YarnLockMismatchReport.WARNING
}
packageLockMismatchReport = if (useProxy && !kotlinMasterBuild) {
LockFileMismatchReport.FAIL
} else {
LockFileMismatchReport.WARNING
}
}

if (useProxy) {
downloadBaseUrl = "https://packages.jetbrains.team/files/p/krpc/build-deps/"
}
fun Project.configureNpm() {
val kotlinMasterBuild by optionalProperty()
val useProxy = useProxyRepositories

registerCustomNpmTasks<NodeJsRootPlugin, NodeJsEnvSpec, NodeJsRootExtension>("js", useProxy)
registerCustomNpmTasks<WasmNodeJsRootPlugin, WasmNodeJsEnvSpec, WasmNodeJsRootExtension>("wasm", useProxy)

// necessary for CI js tests
rootProject.plugins.withType<NodeJsRootPlugin> {
rootProject.extensions.configure<NpmExtension> {
configureNpmExtension(useProxy, kotlinMasterBuild)
}
}

rootProject.plugins.withType<WasmNodeJsRootPlugin> {
rootProject.extensions.configure<WasmNpmExtension> {
configureNpmExtension(useProxy, kotlinMasterBuild)
}
}

tasks.named<Delete>("clean") {
delete(project.layout.projectDirectory.dir(PUPPETEER_BROWSERS_DIR))
}
}
3 changes: 3 additions & 0 deletions gradle-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ org.gradle.configuration-cache=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true

# https://youtrack.jetbrains.com/issue/KT-78504
kotlin.js.yarn=false

# development mode for kotlinx.rpc gradle plugin. Uses local project paths to apply the compiler plugin
kotlinx.rpc.plugin.internalDevelopment=true

Expand Down
3 changes: 3 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ org.gradle.configuration-cache=true
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true

# https://youtrack.jetbrains.com/issue/KT-78504
kotlin.js.yarn=false

# development mode for kotlinx.rpc gradle plugin. Uses local project paths to apply the compiler plugin
kotlinx.rpc.plugin.internalDevelopment=true

Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading
Loading