Search code examples
typescriptfirebasekotlinkotlin-jskotlin-js-interop

Uncaught ReferenceError: firebase is not defined in Kotlin/JS project with Dukat generated declarations


In a basic kotlin js project, I imported the firebase dependency. I used Dukat to get access to the type references and got them to compile. My kotlin compiles like a charm, however it seems to me like the bundle created by webpack does not contain the firebase library in the end.

What I did :

  • Download firebase (npm install firebase)
  • Run Dukat on it to generate the declarations (dukat firebase/app/dist/app/index.d.ts).
  • Copy the generated files to my Kotlin JS project.

enter image description here

After a few changes, my Kotlin compiles fine. When running it however, I am facing a Uncaught ReferenceError: firebase is not defined error in the frontend. This error happens before the code using firebase gets invoked, so I think that the problem comes from the bundling somehow.

Here is my stacktrace:

sample-firebase.js:391 Uncaught Error: Cannot find module 'firebase'
    at webpackMissingModule (sample-firebase.js:3)
    at eval (sample-firebase.js:3)
    at eval (sample-firebase.js:8)
    at Object../kotlin-dce-dev/sample-firebase.js (sample-firebase.js:359)
    at __webpack_require__ (sample-firebase.js:388)
    at sample-firebase.js:1447
    at sample-firebase.js:1450
    at webpackUniversalModuleDefinition (sample-firebase.js:17)
    at sample-firebase.js:18
[webpack-dev-server] Module not found: Error: Package path . is not exported from package /Users/julien/Developer/kotlin-samples/sample-firebase/build/js/node_modules/firebase (see exports field in /Users/julien/Developer/kotlin-samples/sample-firebase/build/js/node_modules/firebase/package.json)

Here is my Client code (the only actually interesting line is the one containing initializeApp.

fun main() {
    val firebaseConfig: Json = json(...)

    val fire = initializeApp(firebaseConfig)
    console.log(fire)
    window.onload = {
        console.log(sorted(arrayOf(1, 2, 3)))
        startFirebase();
        document.body?.sayHello() } }

Commenting out the firebase related code completely removes the error (but obviously also doesn't add firebase functionalities).

My client is available here. You can reproduce by running ./gradlew run in the sample-firebase module.

I have tried quite a few things:

  • By default, Dukat was generating package names for the Kotlin declarations. I tried to removed them but that seems to have no effect on the error.
  • I tried to directly import firebase from my Client (`require("firebase")), in order to ensure it was bundled, but that did not succeed either.
  • finally, I also tried to declare an implementation dependency to another npm package, and import this one using homemade declarations as described in the documentation. This one works like a charm.
  • The error also happens before the javascript is ran so it looks like an import issue of the bundle at runtime.

What are ways to find the discrepancy between my Kotlin declarations that compile, and don't throw errors, and my frontend which just fails to import firebase?


Solution

  • Dukat is still experimental. Use handmade wrapper. Something like that:

    external interface FirebaseOptions{
    }
    
    external interface FirebaseAppSettings{
        var setting: String  // needed settings
    }
    
    external interface FirebaseApp{
    }
    
    @JsModule("firebase/app")
    @JsNonModule
    external val firebaseModule: dynamic
    
    val initializeApp: (options: FirebaseOptions, config: FirebaseAppSettings) -> FirebaseApp = firebaseModule.initializeApp
    

    add to build.gradle:

    implementation(npm("firebase", "9.1.3"))
    

    and use it:

    fun main() {
        val options: dynamic = object {}
        val config: dynamic = object {}
        config["setting"] = "xxx"
        val firebaseApp = initializeApp(
            options.unsafeCast<FirebaseOptions>(),
            config.unsafeCast<FirebaseAppSettings>()
        )
        console.log(firebaseApp)
    }