Using local emulator for firebase with expo - firebase

I am trying to firebase to emulate locally for testing a react native app I am working on with expo. To that end I am trying to set the host of the functions and firestore to the proper port on local host.
After many iterations I finally found a weird combination of imports and calls that did not error. However, when I tried to run it with expo my App came up as a blank screen with no errors.
I am pretty lost at this point and the firebase documentation is confusing.
This is my current index.js:
import firebase from "firebase"
import 'firebase/firestore';
import 'firebase/functions';
import 'firebase/app';
const config = {
//config info
};
const fb = firebase.initializeApp(config);
const firestore = firebase.firestore();
const functions = firebase.functions();
if(__DEV__){
firestore.settings({
host : "localhost:9000",
ssl : false
});
functions.useFunctionsEmulator("http://localhost:5001");
}
const auth = fb.auth();
export { auth, functions, firestore }
The imports are very weird and I don't understand them but I got them from another stack overflow thread and it was the only thing that made it even get to the end of the file. Is there something very obvious I am missing about setting up the local emulator?

the issue you may be having with using the Local Emulator Suite and Expo together is that that "localhost" refers to the device you're using. If you're testing on a physical device, you need to point Firebase to the running instance on your computer. I wrote up a short explainer on it here:
https://dev.to/haydenbleasel/using-the-firebase-local-emulator-with-expo-s-managed-workflow-5g5k

I was able to get this to work on my machine via:
import * as firebase from 'firebase';
import '#firebase/firestore';
import '#firebase/functions';
const firebaseConfig = { /* config data */ }
firebase.initializeApp(firebaseConfig);
firebase.firestore().settings({ host: "localhost:8080", ssl: false });
firebase.functions().useFunctionsEmulator('http://localhost:5001');
In your attempt, I think your problem might be the the way you declared:
const fb = firebase.initializeApp(config);
and then forgot to use the initialized fb -- and instead you used firebase again.
try changing these lines:
const firestore = firebase.firestore();
const functions = firebase.functions();
to this:
const firestore = fb.firestore();
const functions = fb.functions();
or just use the firebase class directly instead of setting to a variable.
Edit:
I noticed that I actually had my firestore store host value set incorrectly so I edited it above - I had added http:// to the beginning but that's not what you want for that parameter.
Note - If you want to see exactly what your dev env is doing when trying to connect to your local firestore, add this line:
firebase.firestore.setLogLevel('debug');

I'm not exactly sure it's your only problem. But for firebase functions to work in an emulator using your android or iphone you need to change
functions.useFunctionsEmulator("http://localhost:5001") to
firebase.functions().useFunctionsEmulator("http://10.0.2.2:5001");
it's for an android emulator only. It's the IP adress of the device you need to reach.

This article does a good job of showing you how to get the right debugger host IP dynamically (if you're running Expo Go on a mobile phone).
basically, it all comes down to:
const origin = Constants.manifest.debuggerHost?.split(":").shift() || "localhost";
firebase.auth().useEmulator(`http://${origin}:9099/`);
firebase.firestore().useEmulator(origin, 8080);
firebase.functions().useEmulator(origin, 5001);

Related

Firebase dynamic links Expo dev

Im trying to implement Firebase dynamic links into my react native app. I'm using expo dev since it clearly states here that Expo Go does not support firebase.
However when running const link = await dynamicLinks().getInitialLink() I keep getting Error: No Firebase App '[DEFAULT]' has been created - call firebase.initializeApp()
Where am I supposed to initialize it? It's a bit hard to find documentation or any mention of initializing firebase for a react native app, all I can find is for a web and I'm missing a lot of the config params.
I did setup my app.json according to the these docs
Any help is highly appreciated.
It turns out my firebase config was missing non optional items, once I filled them out I initialized my app like so
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
} else {
firebase.app(); // if already initialized, use that one
}
and the config min required is
export const firebaseConfig = {
apiKey: "my key",
projectId: "my project id",
appId:"my app id",
databaseURL:"my db url",
messagingSenderId:"my id",
storageBucket:"bucket"
};

Using Webpack with Firebase Messaging service worker

I'm using Firebase Messaging to send notifications to an Angular web app. Everything is working, using code like this in my firebase-messaging-sw.js file:
importScripts('https://www.gstatic.com/firebasejs/9.15.0/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/9.15.0/firebase-messaging-compat.js');
let firebaseConfig = { /* config here */ };
let app = firebase.initializeApp(firebaseConfig);
let messaging = firebase.messaging();
I would much prefer not to load the Firebase libraries from the CDN, so I don't have to make sure the library versions match what I'm importing in the web app (via the usual import statements from node_modules).
What seemed to be the right solution is to use Webpack to combine my service worker code above with its Firebase library dependencies, but I can't seem to get it to work.
As an initial test, I used webpack with this code:
import { initializeApp } from 'firebase/app';
import { getMessaging } from "firebase/messaging";
import { onBackgroundMessage } from "firebase/messaging/sw";
let firebaseConfig = { /* config here */ };
let app = initializeApp(firebaseConfig);
let messaging = getMessaging(app);
I replaced my existing firebase-messaging-sw.js with the webpacked output file, but the browser output shows this error:
Uncaught (in promise) FirebaseError: Messaging: This browser doesn't support the API's required to use the Firebase SDK. (messaging/unsupported-browser).
This suggests to me that webpack is including the parts of the Firebase library intended for the browser instead of the service worker. (I am setting target to webworker in my webpack.config.js, but it doesn't seem to make a difference.)
How can I accomplish this? Is it possible with webpack?
That's due to the fact that you're importing getMessaging from firebase/messaging:
import { getMessaging } from "firebase/messaging";
To use Firebase in a service worker you should import it from firebase/messaging/sw instead:
import { getMessaging } from "firebase/messaging/sw";

Firebase Nuxt Does Not Recognize 'location' Object When Trying to Run The Whole App With Firebase Emulator

My firebase Nuxt app was recently converted to SSR from SPA mode. It was all working fine in SPA mode but when I tried to convert it, it generated a lot of errors. I tried to solve them one by one and I'm stuck with the error ReferenceError 'location' was not defined. I want to run my emulator because I want to test my other functions if it is running completely in SSR mode.
import firebaseTmp from "firebase/app";
import firebaseErrorsJa from "~/plugins/firebaseErrorsJa";
import "firebase/storage";
import "firebase/firestore";
import 'firebase/auth';
import 'firebase/functions';
const config = process.env.firebaseConfig;
if (!firebaseTmp.apps.length) {
firebaseTmp.initializeApp(config);
}
const db = firebaseTmp.firestore();
const functions = firebaseTmp.functions();
const firebase = firebaseTmp;
const firestore = firebaseTmp.firestore();
const storage = firebaseTmp.storage();
const auth = firebaseTmp.auth();
const firestoreTimestamp = firebaseTmp.firestore.Timestamp;
const serverTimestamp = firebaseTmp.firestore.FieldValue.serverTimestamp();
const firebaseErrors = firebaseErrorsJa;
if (location.hostname === "localhost") {
db.settings({
host: "localhost:8000",
ssl: false
});
functions.useEmulator("localhost", 5001);
auth.useEmulator('http://localhost:9099/');
}
export { db, firebase, firestore, auth, storage, firestoreTimestamp, serverTimestamp, functions, firebaseErrors }
I imported almost all libraries but still it does not work.
TAKE NOTE: This only happens when it is in SSR mode. Does this mean that location does not work in SSR mode?
I tried to take away the chunk of code that has 'location' in it. It works perfectly well locally but when I try to run my other functions, it generates CORS error. It accesses the link being used when we deploy our functions.
https://us-central1-talkfor-dev.cloudfunctions.net/v1-auth-updateUser
This is the link that was shown in the console
What I expected is that us-central1-talkfor-dev.cloudfunctions.net will be localhost:5000 since we are using the local development.
Do you have any Idea why is it like this?
Alex you understand that SSR mode is trying to render the website on the server. This can be your local running server instance, that means there is no window object for it to access location variable. Location is only accessible inside the browser. The SSR context is not in the browser, hence makes total sense.
Window.location here states.
Server vs Browser environments here states that
Because you are in a Node.js environment... You do not have access to the window or document objects... You can however use window or document by using the beforeMount or mounted hooks.
.
Why don't you try either of these,
use these beforeMount and mounted hooks like this.
beforeMount () {
window.alert('hello');
}
mounted () {
window.alert('hello');
}
using the process.client environment variable
if (process.client) {
// Do your stuff here
// I think this is what you are looking for.
}

firebase functions emulator useFunctionsEmulator() method not working

I am currently working on the way to test my cloud functions locally.
I found several ways but using firebase emulator and useFunctionsEmulator() method seemed great. At https://firebase.google.com/docs/functions/local-emulator, they didn't say about the method, but I found it on this url How to test `functions.https.onCall` firebase cloud functions locally?.
However, when I run firebase emulator:start and console.log(firebase.functions().useFunctionsEmulator('http://localhost:5001'), it just showed undefined.
I tried several inputs on the origin but nothing changed. There's so little information on the internet about this, I think that's because this is alpha, so Please help me on this.
I got the emulators working and handling local requests by calling the useFunctionsEmulator() method just after initializing the firebase app in the client. Calling it prior caused errors.
firebase.initializeApp(config);
firebase.functions().useFunctionsEmulator("http://localhost:5001");
useFunctionsEmulator() doesn't return anything, it's just a setter.
Use it in the following way:
firebase.initializeApp(config);
const functions = firebase.functions();
functions.useFunctionsEmulator("http://localhost:5001");
I haven't been able to get useFunctionsEmulator() either but I have a workaround:
I switch my onCall function to an onRequest function like so:
// FROM THIS
exports.exampleFunction = functions.https.onCall((data, context) => {
// CODE FOR CLOUD FUNCTION
});
// TO THIS
exports.exampleFunction = functions.https.onRequest((request, response) => {
// CODE FOR CLOUD FUNCTION
});
Then I can serve my function locally with this command firebase serve --only functions which will display a url that I can send requests to via curl, postman or my browser. When I'm done editing the function I switch it back to an onCall function. I hope this helps!
As #app_ wrote, but also this may be worth to someone:
If you use regions, they should only be set for the online call, not the emulated one. This works for me (JavaScript client):
const fns = LOCAL ? firebase.app().functions() :
firebase.app().functions(functionsRegion);
const log = fns.httpsCallable('logs_v200719');
The LOCAL is set earlier to true if we know we are run against emulated back-end. Please let me know if there's a standard way to sniff that, from the Firebase client.
For developer experience, it would be best if regions are handled the same way locally, meaning one doesn't need the above ternary operator.
firebase-tools 8.6.0, JavaScript client 7.16.1
For having troubles calling
firebase.functions().useFunctionsEmulator("http://localhost:5001");
You can test your onCall method in your app by adding this lines.
FirebaseFunctions functions = FirebaseFunctions.getInstance();
functions.useEmulator("10.0.2.2", 5001);
or
functions.UseFunctionsEmulator("http://localhost:5004");
Here is my source : https://firebase.google.com/docs/functions/local-emulator
EDIT: Also in node.js you can use
const admin = require('firebase-admin');
admin.initializeApp();
admin.database().useEmulator('127.0.0.1', 5001);
For Firebase 9 (modular), use connectFunctionsEmulator instead:
import { getApp } from "firebase/app";
import { getFunctions, connectFunctionsEmulator } from "firebase/functions";
const functions = getFunctions(getApp());
connectFunctionsEmulator(functions, "localhost", 5001);
If you have problem using Firebase 9, follow this guide.

Firebase cloud functions -#google-cloud/storage initialization

First question here.
I am trying to write a firebase cloud function to compress a file. I went through a lot of examples on the web but my code keeps getting stuck at two points.
1.const {gcs} =require('#google-cloud/storage')();
When I use this construct in require , I get the following error
TypeError: require(...) is not a function
If I change this to
const {gcs} =require('#google-cloud/storage'); the error goes away but apparently the object isn't initialized because I get this error when I try to access it like so
TypeError: Cannot read property 'bucket' of undefined
at exports.onfilechangecompressor.functions.storage.object.onFinalize.object
(/user_code/index.js:21:27)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:733:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
This is the line where I use gcs like so
const destBucket = gcs.bucket(bucket); where bucket is the object.bucket returned ( object is returned by onFinalize ).
Can someone please tell me how to initialize the storage so it works and returns a valid object.
My node.js version is 8.12.0
firebase version is 5.1.1
The documentation for 2.x shows this:
const {Storage} = require('#google-cloud/storage');
You're adding () after the require, which you're discovered is not correct.
You then go on to initialize it like this:
// Your Google Cloud Platform project ID
const projectId = 'YOUR_PROJECT_ID';
// Creates a client
const storage = new Storage({
projectId: projectId,
});
You may not need to specify the project id if you're running in Cloud Functions or other Google environments.
After that, you can get a reference to your default bucket:
storage.bucket()
You can also use the Admin SDK to invoke the same cloud storage APIs:
const admin = require('firebase-admin');
admin.initializeApp();
const storage = admin.storage();
storage.bucket();

Resources