How to import Firebase SDK modules separately in Kotlin/JS?

Hi,

I’m trying to import the Firebase SDK in a Kotlin/JS project but I can’t find a way to import each module separately so that the whole SDK is not loaded when I only need a couple of modules from it.

I’m importing the library from Gradle like this:

implementation(npm("firebase", "7.13.2"))

and I’m using the Kotlin wrappers for it available in the following project: GitHub - lamba92/firebase-multiplatform which seem to have been generated by Dukat and then improved by @lamba92.

When I run the app I get the following warning:

It looks like you're using the development build of the Firebase JS SDK.
When deploying Firebase apps to production, it is advisable to only import
the individual SDK components you intend to use.

For the module builds, these are available in the following manner
(replace <PACKAGE> with the name of a component - i.e. auth, database, etc):

CommonJS Modules:
const firebase = require('firebase/app');
require('firebase/<PACKAGE>');

ES Modules:
import firebase from 'firebase/app';
import 'firebase/<PACKAGE>';

Typescript:
import * as firebase from 'firebase/app';
import 'firebase/<PACKAGE>';

I have tried to change the Kotlin wrappers to only import each module like this:

@file:JsModule("firebase/app")
@file:JsModule("firebase/analytics")
...

and I can call firebase.initializeApp() which works fine, but when I try to access features like analytics like this:

val firebaseApp = firebase.initializeApp(...)

firebaseApp.analytics().logEvent("test")

then I get the following error in the console at runtime:

Uncaught TypeError: firebaseApp.analytics is not a function

In this case, when I check the app.js file generated in the build folder I can see that the only require() statement is for firebase/app for some reason.

Has anyone come across this kind of issue with Firebase or any other library that has to be imported this way?

1 Like

Happens because I still need to implement the many packages, until then when importing the whole SDK is the only reasonable way. ATM I am very busy with university and I do not have time :confused: Any help on the repo is welcome tho!

Most likely an error in the externals I’ll have a look as soon as possible. Could you open an issue here?

Thanks for the answer @lamba92. I’m actually not using your library, I’m just using the Kotlin wrapper of the Firebase JS library that are inside your repo, the ones created by Dukat (I downloaded them and added them to my project). So the issue is not on your library.

Do you have any idea of how to import certain modules from the Firebase JS SDK even if you haven’t implemented it yet?

1 Like

You need to declare those functions inside a file with the right @JSModule() annotation!

@lamba92 that’s what I tried as I explained on my first post, e.g., @file:JsModule("firebase/analytics") but they don’t seem to work as I get the error Uncaught TypeError: firebaseApp.analytics is not a function.

Have you tried it before and it worked?

Sorry I misread, I will have a look tomorrow morning!

Thanks @lamba92 :slight_smile:

Hi, @franco Did you find any solutions? I am stuck with similar problem.

Hi @gurupadmamadapur, unfortunately, I have not found a way to do this and I’m still loading the full Firebase SDK :confused:. But to be honest I have not spent any more time looking into this as I had more important tasks that needed my attention.

Let me know if you find a way to do it :slight_smile:

1 Like

@franco so I found this.

The thing is firebase injects the required component into the app object based on what you’ve required.

Say if you require - const messaging = require('firebase/messaging/'), the messaging() function will be available in the firebaseApp object.

So require whatever component you need before accessing.

val firebaseApp = firebase.initializeApp(...)
kotlinext.js.require("firebase/messaging") // Required to force firebase to load analytics module
firebaseApp.analytics().logEvent("test")

Sadly you’ll have to do that wherever you need analytics or you could initialize it in a singleton on startup.

@franco Sorry if I did not answer long ago but I never found a solution until @gurupadmamadapur posted his!

Based on the finding of @gurupadmamadapur I moved the Kotlin/JS in a different project and loaded what is needed accordingly. Have a look here!

Any pull request with fixes is very welcome :slight_smile:

2 Likes

Thanks for the info @gurupadmamadapur :slight_smile:

@lamba92 thanks for putting that on its own repo, I have created a PR now with a fix for the return type of DocumentSnapshot.data()

@gurupadmamadapur I just tried doing what you mentioned but the full SDK is still imported as I still get the following warning on the browser console:

It looks like you're using the development build of the Firebase JS SDK.
When deploying Firebase apps to production, it is advisable to only import
the individual SDK components you intend to use.

For the module builds, these are available in the following manner
(replace <PACKAGE> with the name of a component - i.e. auth, database, etc):

CommonJS Modules:
const firebase = require('firebase/app');
require('firebase/<PACKAGE>');

ES Modules:
import firebase from 'firebase/app';
import 'firebase/<PACKAGE>';

Typescript:
import * as firebase from 'firebase/app';
import 'firebase/<PACKAGE>';

Did you try it and not get this warning somehow?

Yep, it doesn’t show up now. Make sure you don’t have @file:JsModule("firebase") anywhere in you external declarations (It’ll load all the components (Meaning don’t skip this step that you did - I have tried to change the Kotlin wrappers to only import each module like this:)

To not get this error - Uncaught TypeError: firebaseApp.analytics is not a function, you’ll have to call require function for the necessary module after call to initializeApp

2 Likes

I need to use the @firebase/<PACKAGE> npm import then. I’ll fix it as soon as possible.

EDIT: I published the fixes using @JsModule("firebase/<package>"). Please try them and let me know.

1 Like

@lamba92 the CD automation might not be working properly as the core library is not available for 0.3.0.

@gurupadmamadapur can you share a project where this is working?

I did what you mentioned but I’m still getting errors at runtime when using this in a real app that uses Firebase Auth, Firestore and Analytics.

This is the error I’m getting now:

Uncaught TypeError: Cannot read property 'GoogleAuthProvider' of undefined

This is how I’m importing it:

kotlinext.js.require("firebase/app")
kotlinext.js.require("firebase/auth")
kotlinext.js.require("firebase/analytics")
kotlinext.js.require("firebase/firestore")

firebase.initializeApp(...)

@lamba92 I couldn’t include that repo as a dependency in my project. Received 401 from jitpack. Anyways I copy-pasted the declarations and ran into the same issue.

I see a @file:JsModule(“firebase”) used in this file kotlinjs-firebase-declarations/index.firebase.module_firebase.kt at master · lamba92/kotlinjs-firebase-declarations · GitHub where initializeApp is called. This loads all the components by default. If @file:JsModule(“firebase/app”) is used in this file you’ll get the app object however it won’t have any components. Hence calling app.<required_component>() will break.

But I can’t really explain with concrete evidence why that isn’t working (although it looks correct) as I’ve no idea how js module stuff works.

Having said that I just checked out the firebase sdk from latest version 8.0.0 looks like there are some new changes and initializeApp can’t be declared as a file function anymore, it has to be inside a companion object (probably App). Maybe this will generate better externals using dukat.

Also, maybe when kotlin IR backend improves and they’ve much more control on dce, maybe this won’t be relevant then since unused modules can be dce’d. Again, I’m just speculating, no idea.

Maybe try requiring after call to initalizeApp(…).

@franco Here is a sample repo (with messaging and analytics module) - The external declarations are minimal (Copied from @lamba92’s repo)

Changed the name to app, sorry