https://kotlinlang.org logo
Title
a

Ahmed Elzeiny

04/05/2023, 7:00 PM
Hello everyone, I have a Kotlin Multiplatform Mobile (KMM) library that I want to use in my Next.js server-side rendering frontend project. I have created the APIs and everything is working fine. I have published the library as an npm package, and it is working fine on the client-side. However, when I try to use it on the server-side, I am getting an error message that says “Error: Cannot find module ‘abort-controller’.” I have already added the following dependencies to my project:
runtimeOnly(npm("abort-controller", "3.0.0")) 
runtimeOnly(npm("node-fetch", "2.6.1"))
I have verified that these dependencies exist and are installed, but I am still getting the same error. Here are my versions:
private const val ktorVersion = "2.2.3"
I am using Kotlin version 1.8.0. any insights or workarounds to fix it ?
b

Big Chungus

04/05/2023, 10:35 PM
Use nodejs() flavour over browser()
a

Ahmed Elzeiny

04/06/2023, 5:48 PM
@Big Chungus tried it and got the same error Here is my gradle
kotlin {
    android()

    val xcf = XCFramework(libName)
    iosArm64 {
        binaries.framework {
            baseName = libName
            xcf.add(this)
        }
    }
    val iosSims = listOf(iosX64(), iosSimulatorArm64())
    configure(iosSims) {
        binaries.framework {
            baseName = libName
            xcf.add(this)
        }
    }

    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
        kotlinOptions {
            jvmTarget = "11"
        }
    }

    js(IR) {
        nodejs()
        binaries.library()
    }

    android {
        publishLibraryVariants("release", "debug")
    }

    multiplatformSwiftPackage {
        packageName(libName)
        swiftToolsVersion("5.5")
        targetPlatforms {
            iOS { v("11") }
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(Dependency.Kotlin.DATE_TIME)
                implementation(Dependency.Kotlin.COROUTINES)
                implementation(Dependency.Kotlin.ATOMICS)
            }
        }
        val androidMain by getting {
            dependencies {
                dependsOn(commonMain)
                implementation("androidx.security:security-crypto:1.0.0")
            }
        }

        val iosX64Main by getting
        val iosArm64Main by getting
        val iosSimulatorArm64Main by getting

        val iosMain by creating {
            dependsOn(commonMain)
            iosX64Main.dependsOn(this)
            iosArm64Main.dependsOn(this)
            iosSimulatorArm64Main.dependsOn(this)
            dependencies {}
        }

        val jsMain by getting {
            dependsOn(commonMain)
            dependencies {
                runtimeOnly(npm("text-encoding", "0.7.0"))
                runtimeOnly(npm("abort-controller", "3.0.0"))
                runtimeOnly(npm("node-fetch", "2.6.1"))
            }
        }
    }
}
b

Big Chungus

04/06/2023, 7:40 PM
Ah,I know what's up. Kjs plugin does not move transitive npm deps into generated package.json
You could try petuska.dev/npm-publish instead to assemble your js package
a

Ahmed Elzeiny

04/06/2023, 7:45 PM
npmPublish {
    organization.set(gradleLocalProperties(rootDir).getProperty("PUBLISH_GITHUB_ORGANIZATION"))
    packages {
        named("js") {
            packageJson {
                author {
                    name.set("org")
                }
                repository {
                    type.set("git")
                    url.set("<https://github.com/org/org-kmm.git>")
                }
            }
        }
    }
    registries {
        github {
            access.set(dev.petuska.npm.publish.extension.domain.NpmAccess.RESTRICTED)
            authToken.set(gradleLocalProperties(rootDir).getProperty("PUBLISH_GITHUB_AUTH_TOKEN"))
        }
    }
}
id("dev.petuska.npm.publish") version "3.2.1"
@Big Chungus I’m already using it, and i’m publishing my version using publishJsPackageToGithubRegistry do I need to change anything on it ?
b

Big Chungus

04/06/2023, 7:46 PM
Hmm, i think runtimeOnly could be causing issues. It's not very polished on js. Try changing that to api or implementation?
npmPublish block while suboptimal, looks correct
a

Ahmed Elzeiny

04/06/2023, 7:48 PM
I tried api and implementation before using nodeJs over browser, let me try again now
b

Big Chungus

04/06/2023, 7:50 PM
Also inspect generated package.json to verify the dependencies
a

Ahmed Elzeiny

04/06/2023, 7:59 PM
yeah tried it now and also checked the package.json and it contains the dependancies
"dependencies": {
        "abort-controller": "3.0.0",
        "node-fetch": "2.6.1",
        "text-encoding": "0.7.0",
        "ws": "8.5.0",
        "@js-joda/core": "3.2.0"
    }
got the same error as well
b

Big Chungus

04/06/2023, 8:01 PM
Why do you have dependsOn(commonMain) in jsMain?
Do you use abort-controller directly in your code?
Can you share any stack traces?
a

Ahmed Elzeiny

04/06/2023, 8:02 PM
just to get the same dependencies as common main, and no I don’t use it in anyplace
b

Big Chungus

04/06/2023, 8:03 PM
Remove dependsOn line. All sourceSets extend from commonMain implicitly
It might be causing some weird side effects
a

Ahmed Elzeiny

04/06/2023, 8:04 PM
3fQ.6wmu1ePjaTDj-J_TtLnneW_yxbPKC8K_wDSPesjOKJk
getCards: starting fetching getCards
TRACE: Applied DefaultRequest to <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>. New url: <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Adding Accept=application header for <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Body type class EmptyContent is in ignored types. Skipping ContentNegotiation for <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>.
TRACE: Adding Accept-Charset=UTF-8 to <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Processing exception Error: Cannot find module 'abort-controller'
Require stack:
- /var/task/.next/server/chunks/768.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/pages/_document.js
- /var/task/node_modules/next/dist/server/require.js
- /var/task/node_modules/next/dist/server/next-server.js
- /var/task/___next_launcher.cjs for request <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
Error: Cannot find module 'abort-controller'
Require stack:
- /var/task/.next/server/chunks/768.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/pages/_document.js
- /var/task/node_modules/next/dist/server/require.js
- /var/task/node_modules/next/dist/server/next-server.js
- /var/task/___next_launcher.cjs
    at Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
    at mod._resolveFilename (/var/task/node_modules/next/dist/build/webpack/require-hook.js:23:32)
    at Module._load (node:internal/modules/cjs/loader:885:27)
    at Module.require (node:internal/modules/cjs/loader:1105:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at AbortController_0 (/var/task/.next/server/chunks/768.js:41498:45)
    at commonFetch (/var/task/.next/server/chunks/768.js:41469:26)
    at $executeCOROUTINE$16.zf (/var/task/.next/server/chunks/768.js:40872:37)
    at JsClientEngine.f28 (/var/task/.next/server/chunks/768.js:40988:20)
    at HttpClientEngine$executeWithinCallContext$slambda.zf (/var/task/.next/server/chunks/768.js:36485:48) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/var/task/.next/server/chunks/768.js',
    '/var/task/.next/server/webpack-runtime.js',
    '/var/task/.next/server/pages/_document.js',
    '/var/task/node_modules/next/dist/server/require.js',
    '/var/task/node_modules/next/dist/server/next-server.js',
    '/var/task/___next_launcher.cjs'
  ]
}
[Error: An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.] {
  digest: '2805196926'
}
b

Big Chungus

04/06/2023, 8:05 PM
Why do you declare abort-controller dependency if you don't use it directly?
Seems the easiest fix is to simply remove the dependency
a

Ahmed Elzeiny

04/06/2023, 8:06 PM
Ok let me try it also
removed the npm deps and the depends on and still getting the same error as well FYI i’m using “next”: “13.1.6", react server components
RequestId: 42fe86f7-6a5a-462a-841e-7fd936d6b40d Version: $LATEST
attempting to fetch cards using kmm
getCards: try to getCards with token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTAsImlhdCI6MTY4MDc5NDA2NywiZXhwIjoxNzEyMzMwMDY3fQ.6wmu1ePjaTDj-J_TtLnneW_yxbPKC8K_wDSPesjOKJk
getCards: starting fetching getCards
TRACE: Applied DefaultRequest to <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>. New url: <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Adding Accept=application header for <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Body type class EmptyContent is in ignored types. Skipping ContentNegotiation for <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>.
TRACE: Adding Accept-Charset=UTF-8 to <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
TRACE: Processing exception Error: Cannot find module 'abort-controller'
Require stack:
- /var/task/.next/server/chunks/768.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/pages/_document.js
- /var/task/node_modules/next/dist/server/require.js
- /var/task/node_modules/next/dist/server/next-server.js
- /var/task/___next_launcher.cjs for request <https://dev-api.mywebsite.com/api/cards?pagination%5Bpage%5D=1&pagination%5BpageSize%5D=10&pagination%5BwithCount%5D=true>
Error: Cannot find module 'abort-controller'
Require stack:
- /var/task/.next/server/chunks/768.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/pages/_document.js
- /var/task/node_modules/next/dist/server/require.js
- /var/task/node_modules/next/dist/server/next-server.js
- /var/task/___next_launcher.cjs
  at Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
  at mod._resolveFilename (/var/task/node_modules/next/dist/build/webpack/require-hook.js:23:32)
  at Module._load (node:internal/modules/cjs/loader:885:27)
  at Module.require (node:internal/modules/cjs/loader:1105:19)
  at require (node:internal/modules/cjs/helpers:103:18)
  at AbortController_0 (/var/task/.next/server/chunks/768.js:41498:45)
  at commonFetch (/var/task/.next/server/chunks/768.js:41469:26)
  at $executeCOROUTINE$16.zf (/var/task/.next/server/chunks/768.js:40872:37)
  at JsClientEngine.f28 (/var/task/.next/server/chunks/768.js:40988:20)
  at HttpClientEngine$executeWithinCallContext$slambda.zf (/var/task/.next/server/chunks/768.js:36485:48) {
 code: 'MODULE_NOT_FOUND',
 requireStack: [
  '/var/task/.next/server/chunks/768.js',
  '/var/task/.next/server/webpack-runtime.js',
  '/var/task/.next/server/pages/_document.js',
  '/var/task/node_modules/next/dist/server/require.js',
  '/var/task/node_modules/next/dist/server/next-server.js',
  '/var/task/___next_launcher.cjs'
 ]
}
b

Big Chungus

04/06/2023, 8:21 PM
Hmm, what if you add abort-controller to your next package.json?
a

Ahmed Elzeiny

04/06/2023, 8:22 PM
I did and same issue as well
b

Big Chungus

04/06/2023, 8:22 PM
Tbh, it might be an issue with next.js itself and its mixing of server and client code
No clue how it handles dependencies between the two
a

Ahmed Elzeiny

04/06/2023, 8:23 PM
I saw some comments saying that abort controller will work on the client side only, so I’m afraid that KTOR and KMM doesn’t support server-side rendering till now
b

Big Chungus

04/06/2023, 8:23 PM
Does next.js require es6? Kotlin doesn't support that so it might be the cause
a

Ahmed Elzeiny

04/06/2023, 8:25 PM
unfortunately yes!