Skip to content
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

Cannot read property 'GoogleAuthProvider' of undefined #38

Closed
socalrunner opened this issue Nov 5, 2019 · 20 comments
Closed

Cannot read property 'GoogleAuthProvider' of undefined #38

socalrunner opened this issue Nov 5, 2019 · 20 comments

Comments

@socalrunner
Copy link
Contributor

socalrunner commented Nov 5, 2019

We are building an Ionic Stencil (no framework) app using Capacitor (hybrid mobile app).

So far, I'm loving this plugin (I only have a working build in Android so far). Great job unifying the login approach for all of the different providers. It initially took me awhile to get things working. I found that the following import in facades.js was causing the above error.

import * as firebase from 'firebase/app';

And this is because firebase.auth in firebase.auth.GoogleAuthProvider().providerId was undefined.

So, I changed it to:

import firebase from '@firebase/app';

And now the reference to the provider is valid. I don't fully understand why this is happening. Can you give me some guidance for how to deal with this properly? Maybe I should be using a different version of com.google.firebase:firebase-auth:17.0.0? I downgraded to this version because the latest version was causing some manifest merge issues related to AndroidX.

Here are the dependencies I'm using:

Root level gradle has: classpath 'com.google.gms:google-services:4.3.2' // Google Services plugin

App level gradle has:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation project(':capacitor-android')
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation project(':capacitor-cordova-android-plugins')
    implementation 'com.google.firebase:firebase-auth:17.0.0'
    implementation 'com.facebook.android:facebook-android-sdk:4.41.0'
}

package.json

  "dependencies": {
    "@capacitor/android": "^1.3.0",
    "@capacitor/core": "1.2.1",
    "@capacitor/ios": "^1.3.0",
    "@ionic/core": "^4.11.3",
    "@stencil/state-tunnel": "^1.0.1",
    "@types/jest": "^24.0.21",
    "animate.css": "^3.7.2",
    "capacitor-firebase-auth": "^0.2.4",
    "firebase": "^6.6.1",
    "moment": "^2.24.0",
    "prettier": "^1.18.2"
  },

Please advise?

@mckelveygreg
Copy link
Contributor

Hey, I've been toying with this library the last few days and I may be able to point you in hopefully a helpful direction?

I found that this plugin already had the gradle implementation set correctly, so I did not need to add it to my app/build.gradle.

However, I did find that forgetting to add the plugin in MainActivity.java did cause a problem similar to what you had. Step 2
Good luck! I'm still working out my own bugs currently...

@socalrunner
Copy link
Contributor Author

socalrunner commented Nov 6, 2019

@mckelveygreg thanks for the feedback. I can confirm that you are correct, I don't need the app level gradle configuration. However, I also verified that I did add the plugin in MainActivity.java. I tried again uninstalling and reinstalling this plugin and I still get this error, Cannot read property 'GoogleAuthProvider' of undefined.

The only way I am able to get the plugin working properly is to change this import import * as firebase from 'firebase/app to import firebase from '@firebase/app'; in this file .../node_modules/capacitor-firebase-auth/dist/esm/facades.js (I believe this is the compiled facades.ts, but this only works if I change the import in the compiled .js file because if I try to change the import in the .ts file and recompile then TS throws errors).

I believe this is the only change I need and then I am able to get the providers I need (google.com, facebook.com) to work properly.

I forked this repo temporarily so that I can experiment with it, but I'd like to use it properly. Any additional advice is more than welcome. Thanks!!

@baumblatt
Copy link
Owner

baumblatt commented Nov 7, 2019

Hello Justin,

The Cannot read property 'GoogleAuthProvider' of undefined is occurring before or after the native call of the plugin?

Please, can you verify the Firebase App initialization in web tier? This is required to the plugin work correctly.

Case the Firebase App are not configured on web, please, follow the instructions of Add Firebase SDKs and initialize Firebase on official docs.

Best regards,
Bernardo Baumblatt.

@socalrunner
Copy link
Contributor Author

Hi Bernardo, I believe it's happening before the native call. It is happening when I hit the Google login button which calls cfaSignIn('google.com') in the facades.js module in this function:

// '/node_modules/capacitor-firebase-auth/dist/esm/facades.js' in the plugin
/**
 * Call the sign in method on native layer and sign in on web layer with retrieved credentials.
 * @param providerId The provider identification.
 * @param data The provider additional information (optional).
 */
export const cfaSignIn = (providerId, data) => {
    const googleProvider = new firebase.auth.GoogleAuthProvider().providerId;
    const facebookProvider = new firebase.auth.FacebookAuthProvider().providerId;
    const twitterProvider = new firebase.auth.TwitterAuthProvider().providerId;
    const phoneProvider = new firebase.auth.PhoneAuthProvider().providerId;
    switch (providerId) {
        case googleProvider:
            return cfaSignInGoogle();
        case twitterProvider:
            return cfaSignInTwitter();
        case facebookProvider:
            return cfaSignInFacebook();
        case phoneProvider:
            return cfaSignInPhone(data.phone, data.verificationCode);
        default:
            return throwError(new Error(`The '${providerId}' provider was not supported`));
    }
};

I can confirm that I am initializing firebase in the web tier, but I fear I'm not initializing it correctly.

Here's what I'm doing:

import { firebase } from "@firebase/app";

var creds = {
  name: ["<name>"],
  apiKey: "<apiKey>",
  authDomain: "<authDomain>",
  databaseURL: "<dbURL>",
  projectId: "<projectId>",
  storageBucket: "<storageBucket>",
  messagingSenderId: "<messagingSenderId>"
};
firebase.initializeApp(creds);

Then I am injecting firebase into components where they are needed.

@baumblatt
Copy link
Owner

Hi Justin,

I’m not sure about, but please, can you remove the line name: ["<name>"], from the creds and try again.

Just in case, on my web project I'm using "firebase": "^7.2.1", can you make a try too?

In time, second though: We have two Firebase libraries on node_modules!

In your code, you are initializing the Firebase App from @firebase/app, but the plugin is using the
firebase/app, maybe this justify why changing the import from facade.js solve the issue.

Just to be sure that is correct, please can you try changing your import to import * as firebase from 'firebase/app'; and make a try?

The big question is, what is the correct way to import Firebase? This comment of Michel on firebase-js-sdk issue 1008 may help us!

Best regards,
Bernardo Baumblatt.

@socalrunner
Copy link
Contributor Author

@baumblatt thank you for the additional notes. Sorry for the delay, I was focusing on a different issue for a few days. I'll run some more tests today and let you know what I find.

@socalrunner
Copy link
Contributor Author

@baumblatt, ok, I've tested this again today. I tried your suggestions but to no avail. After testing here's what I did find. When I import now I've changed all of my imports to import firebase from 'firebase/app'. I removed the name property from the creds object as it is not needed, like you suggested. I also updated firebase to "firebase": "^7.2.1". I tested all of this with capacitor-firebase-auth v0.2.4 and still I get the same error.

So, then in the forked version of your plugin, in facades.ts I changed import * as firebase from 'firebase/app'; to import firebase from 'firebase/app';. Now anywhere in my app where I import firebase I'm using this same import plus import 'firebase/auth'; (based on google docs). Now I update the plugin to my forked version and it's working correctly.

The problem appears to me to be related to the way stencil bundles the dependencies. Maybe related to Rollup and/or the way our app is configured. Here is my stencil.config.ts:

import { Config } from "@stencil/core";
import { env } from '@alepop/stencil-env';
import { sass } from "@stencil/sass";
import * as path from "path"

// https://stenciljs.com/docs/config
export const config: Config = {
  hashFileNames: false,
  minifyJs: false,
  minifyCss: true,
  outputTargets: [
    {
      type: "www",
      serviceWorker: null
    }
  ],
  globalScript: "src/global/app.ts",
  globalStyle: "src/global/app.scss",
  plugins: [env({ path: path.resolve(__dirname, `.env.${process.env.ENVIRONMENT}`)}), sass()],
  commonjs: {
    namedExports: {
      "./node_modules/idb/build/idb.js": ["openDb"],
      "./node_modules/firebase/dist/index.cjs.js": [
        "initializeApp",
        "firestore"
      ],
      "./node_modules/firebase/app/dist/index.cjs.js": ["auth", "app"]
    }
  }
};

capacitor.config.json

{
  "appId": <appId>
  "appName": <appName>,
  "bundledWebRuntime": false,
  "npmClient": "npm",
  "webDir": "www",
  "cordova": {
    "preferences": {
      "AllowInlineMediaPlayback": "true",
      "orientation": "portrait"
    }
  },
  "plugins": {
    "CapacitorFirebaseAuth": {
      "providers": ["google.com", "facebook.com"],
      "languageCode": "en",
      "nativeAuth": false,
      "permissions": {
        "google": ["profile"]
      }
    }
  }
}

tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "allowUnreachableCode": false,
    "declaration": false,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2017"
    ],
    "moduleResolution": "node",
    "module": "esnext",
    "target": "es2017",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "jsx": "react",
    "jsxFactory": "h"
  },
  "include": [
    "src"
  ],
  "exclude": [
    "node_modules"
  ]
}

I will continue to research and test, but I don't know what to do except to change that import. Please let me know if I can give you more information that would help. Thank you!! Still loving this plugin, wish I could figure out what I'm missing.

@baumblatt
Copy link
Owner

Hi Justin,

Let's try this, I will implement the import like it works on your stencil project and try it on my Angular CLI project.

If everything works for me, I will bump the version on npm.

As soon I have a results, I will let you know.

Best regards,
Bernardo Baumblatt

@christopherShelleySocotree

Sorry to hijack this thread with a slightly off question. Has anyone had any luck setting up this plugin in an ionic react project? Unfortunately android and android studio are not environments im familiar with, so i ended chasing my tail for some days trying to install this plugin and dealing with bugs.

Also you seem like the right people to ask, is it possible to setup firebase/facebook login inside the app webview, without jumping out to the device's browser? I would much prefer that if possible instead of jumping out then back into the app.
Thanks for any clarity you can provide.

@christopherShelleySocotree

regarding my previous message, i had success in an ionic-react project, after managing some minor config merge bugs. Thanks for the library.

@hawekotte
Copy link

@christopherShelleySocotree, any chance you can provide a snippet of your react code for how you implemented it?

I am attempting to implement it in iOS and cannot seem to get Capacitor to recognize the plugin (i.e. provide it within Plugins from @capacitor/core). Any import attempts always throw

Either an instance of firebase.auth.Auth must be passed as an argument to the
firebase.auth.PhoneAuthProvider constructor, or the default firebase App instance
must be initialized via firebase.initializeApp()

I plan on checking it in Android but I need to fix a gradle merge issue first.

@socalrunner
Copy link
Contributor Author

Hi Justin,

Let's try this, I will implement the import like it works on your stencil project and try it on my Angular CLI project.

If everything works for me, I will bump the version on npm.

As soon I have a results, I will let you know.

Best regards,
Bernardo Baumblatt

Hi @baumblatt !! Just checking in to see if you had a chance to test the above? If you'd like, I would be happy to push a PR showing what I did. If it would make things easier? Just let me know how you'd like to proceed.

@baumblatt
Copy link
Owner

Hi Justin,

Really sorry about the delay, honestly I just forgot.

About the case, we fall in a dilemma, changing the import will break the Angular's builds, with the message below::

../node_modules/capacitor-firebase-auth/node_modules/firebase/index.d.ts:8601:1
    8601 export = firebase;
    ~~~~~~~~~~~~~~~~~~
    This module is declared with using 'export =', and can only be used with a default import when using the 'allowSyntheticDefaultImports' flag.

The Angular's build go back to work after the suggested flag, but I don’t know the effects of this changes on large projects.

Is there another way out?

Best regards,
Bernardo Baumblatt.

@socalrunner
Copy link
Contributor Author

socalrunner commented Dec 17, 2019

Hi @baumblatt, I did a little more research today and it looks like a more durable solution for the above error could be to use "esModuleInterop": true in the angular app instead of allowSyntheticDefaultImports. Can you try to adding that to your tsconfig.json and see if it can overcome the different import method? If you have an example angular app that you can share, I can do more testing and research to see what I can find (if that helps).

Just as a note, all of the stencil/firebase examples I find are importing as import firebase from 'firebase/app';. I think our issue is related to the way rollup bundles the app, but I still don't fully understand the problem. I'm wondering if you use a different bundler for the Angular app like Webpack or something?

Still researching on my end, I'll let you know if I find anything useful.

Update: This is a pretty good explanation of the esModuleInterop flag: https://stackoverflow.com/questions/56238356/understanding-esmoduleinterop-in-tsconfig-file

@socalrunner
Copy link
Contributor Author

Ok, @baumblatt, I went ahead and tested my fork using only "esModuleInterop": true; (I left allowSyntheticDefaultImports out of the tsconfig this time). The facades.ts file is importing the firebase app like so: import firebase from 'firebase/app'. This all works well within my app. So, can you test this in the Angular app you are using for testing?

After more research tonight, I found out that TypeScript has recommended setting esModuleInterop to true since v2.7 (here is the excerpt: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-from-commonjs-modules-with---esmoduleinterop). It looks to me like this is the accepted way to make typescript generated output from commonjs modules look more like babel outputs. I'd like to hear what you think and let me know what else I can do to assist.

@baumblatt
Copy link
Owner

Hi Justin,

The esModuleInterop works on my Angular application test.

The only issue is that will brake existing Angular applications. But as exposed here, this is required to support stencil.

Please, just make sure that this is the only way out.

Best regards,
Bernardo Baumblatt.

@socalrunner
Copy link
Contributor Author

@baumblatt I suppose another alternative would be to fork the plugin, one for Angular (other) and one for Stencil, but it seems like overkill to do that for a small change like this. Our app is a Stencil + Capacitor only mobile app (no other ui framework).

Bernardo, your app is an Angular app and it is in production, is that right? Maybe we can take our time and you can test it out on your side for awhile so that you can feel comfortable before you put it into production.

We're not ready for production use yet, so we have some more time on our side. Our intention is to use this in production, but we are at least a couple of months out.

Anyway, I'm still looking for another way to solve this and I'll keep you posted if I learn anything.

@baumblatt
Copy link
Owner

Hi,

I don’t think fork is a good idea, it's better to go forward with this change.

I will document the change and create the version.

Best regards,
Bernardo Baumblatt.

@baumblatt
Copy link
Owner

Hello Justin,

Please take a look at v0.3.0 and see with everything is working on Stencil now.

I'm Looking forward to hearing from you.

Best regards,
Bernardo Baumblatt.

@socalrunner
Copy link
Contributor Author

Hello Bernardo, I have tested v0.3.0 and all is well on the Stencil front. Thank you for the quick assist on this, we're very pleased with this plugin.

Closing this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants