I'm attempting to combine implicit initialization for Firebase and a React app (created using CRA) as it seems like a good way to ensure I don't need to worry too much about configuring for different environments.
However, when running the app, if I make any attempt to use the firebase object I get the error Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
My index file has the Firebase files included before the app files and if I put a breakpoint in the Firebase-provided init then I can see that it is initializing the firebase object.
The App component is the one that comes with the CRA boilerplate:
mport React from 'react';
import firebase from 'firebase/app'
import 'firebase/functions'
import logo from './logo.svg';
import './App.css';
const App: React.FC = () => {
const helloWorld = firebase.functions().httpsCallable('helloWorld')
helloWorld().then(result => console.log({ result }))
return (
...
Any pointers?
I was doing it wrong. The init script was being called correctly and creating a global firebase object, which I was then overriding with my imports.
I removed the two imports in my component and changed the helloWorld declaration:
const helloWorld = window.firebase.functions().httpsCallable('helloWorld')
The typescript linter then complains that firebase doesn't exist on Window, so I've added a global.d.ts file containing this:
interface Window {
firebase: any
}
At some point, I'll work out the correct type for it, but it's got me past the problem.
Related
I am building a react app (this part might be inconsequential) and have a server cloud function built:
exports.myFunction = functions.https.onCall(async (data, context) => {
...
}
I know that calling this in my client would normally consist of calling
firebase.functions().httpsCallable('myFunction');
And I have tried this in a separate project, and it works. However, that was using a script tag to import the functions module in my index.html:
<script src="/__/firebase/7.7.9/firebase-functions.js"></script>
but in my current project, my modules are imported in my firebase.js source:
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: ...
...
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
I wasn't able to find any example code for importing functions this way, and everything I have tried has failed.
How can I import functions so that I can invoke the above method? Even better, how could I figure this out on my own? (I have been relying on example code so far). I assume that these are referencing the NPM packages I have npm install'ed (or in my case, yarn add'ed), but I don't immediately see where the code is actually being referenced so I can work this out on my own.
As far what I have understood from you question it is regarding how can firebase cloud function module be imported while using a react app which is calling a HTTPS callable function at the client side.You can use any library or built-in command of your environment to call a HTTPS function.
I would recommend you to try the following to your imports and see if that works.
import { getFunctions, httpsCallable } from "firebase/functions";
OR
import * as functions from 'firebase-functions'; import React from 'react'; import { renderToString } from 'react-dom/server'; import App from './src/App';
Check the below for similar implementation examples to better understand this and implement according to your requirements.
How to call Firebase function from within react component
Call Firebase HTTPS callable function in react
Implement callable function in react app
Firebase callable function CORS
I noticed some weird behaviour in my react app, which I do not understand:
I created a firebase app object which I export:
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export default app;
When I dont import it in my other component, where I use getAuth etc., I still get the same error. When I import it in the "correct" component, everything works.
import app from "../firebase";
I don´t understand why, since the app object is not used in the component. Why do I need to import the object when I don´t even use it? I guess it is used... but I don´t understand how.
I had a working ReactJS app that was using Firebase.
I am following Robin Wieruch's React/Redux/Firebase Tutorial.
I then added Firebase functions, and now my app fails to start. The error I get is, for example, app.database() is not a function when instantiating the Firebase Class.
Here is a brief snippet:
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/database';
import 'firebase/storage'
import config from './config'
class Firebase {
constructor() {
app.initializeApp(config);
/* Helper */
this.serverValue = app.database.ServerValue;
this.emailAuthProvider = app.auth.EmailAuthProvider;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.database();
}
I have the app working in the old repository without functions, so the only thing I can figure is that adding Firebase functions has introduced some conflict.
The directory structure is:
src/
node_modules/
functions/
functions/node_modules/
Any thoughts?
Thanks!
Only a guess... Is it possible that you need to import functions, and this.functions = app.functions() as you have with db and auth?
I'm working on a React and Firebase project and I'm having trouble setting up the autocompletion on my code (I'm using VScode).
Here's what I've got so far:
HOW I'M PROVIDING FIREBASE TO MY APP COMPONENTS (VIA CONTEXT)
FirebaseContext.js
import React from 'react';
const FirebaseContext = React.createContext(null);
export default FirebaseContext;
firebase.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import 'firebase/functions';
// .env file in root folder
const config = {
apiKey: process.env.FIREBASE_APP_API_KEY,
authDomain: process.env.FIREBASE_APP_AUTH_DOMAIN,
databaseURL: process.env.FIREBASE_APP_DATABASE_URL,
projectId: process.env.FIREBASE_APP_PROJECT_ID,
storageBucket: process.env.FIREBASE_APP_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_APP_MESSAGING_SENDER_ID
};
firebase.initializeApp(config);
firebase.functions().useFunctionsEmulator('http://localhost:5000');
export default firebase;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import firebase from './helpers/firebase/firebase';
import FirebaseContext from './helpers/firebase/FirebaseContext';
import { BrowserRouter as Router} from "react-router-dom";
...
ReactDOM.render(
// HERE'S HOW I'M PROVIDING FIREBASE FOR MY APP
<FirebaseContext.Provider value={firebase}>
<Router>
<App/>
</Router>
</FirebaseContext.Provider>
,document.getElementById('root')
);
HOW I'M CONSUMING FIREBASE IN MY COMPONENTS
AddProductContainer.js
import React, { useEffect, useState, useCallback, useContext } from 'react';
import FirebaseContext from '../../../helpers/firebase/FirebaseContext';
function AddProductContainer() {
const firebase = useContext(FirebaseContext);
function saveToFirestore() {
// I DON'T HAVE ANY AUTOCOMPLETION FROM 'FIREBASE...'
firebase.firestore().collection('products').add({
title: productDetails.title.newTitle,
description: productDetails.description,
categories: productDetails.categories
});
}
}
QUESTION
How can I get autocompletion from Firebase inside a JavaScript project?
Note: All of my component files are .js. I'm not using Typescript.
Is there a way to use JSDoc annotations to get access to autocompletion in this case?
Something like:
/** #type {firebase} */
const firebase = useContext(FirebaseContext);
It would definitely be pretty tricky to do it the way you're doing it without Typescript or something, but can I suggest another option?
I don't think it's necessary to put the firebase object itself in context. Putting app in context might make sense (the object returned from firebase.initializeApp) if you were going to use more than one app or just wanted to be explicit, but it seems like firebase itself would make more sense being a direct import (import firebase from 'firebase/app') in any file that's using it. It won't create a second instance of firebase or anything if that's what you're concerned about, it's just a handle for the firebase library. It'll pick up the default app you initialized with firebase.initializeApp() as long as initializeApp() ran first. initializeApp() creates a global default firebase app that any invocation of Firebase methods will pick up.
If you're uncomfortable with globals, you can be explicit about the specific app you're working with by assigning const app = firebase.initializeApp(...), then passing app down through props or context, then always calling firebase packages with app as an argument, such as firebase.firestore(app).collection('products').etc... .
But there should be no cost to importing the firebase package directly at the top of any file you're using it in (and want autocomplete in).
I'm having issues adding authentication to an app I have been working on.
Everything works fine with firebase as-is without the auth, until I start adding these new lines, which are basically just:
export const provider = new firebase.auth.GoogleAuthProvider();
export const auth = firebase.auth();
import firebase, { auth, provider } from './firebase.js';
I have a file for my config (config.js), which just contains an export for DB_CONFIG (with all my correct info). Here's where I'm running into issues. The tutorial I'm following has firebase imported and initialized in the config file, while I am doing so in my App.js file. I've been trying different things for a couple hours and nothing is working for me. If I import firebase into my config and initializeApp there, it breaks my App.js. Here's a gist of my code vs. what I'm trying to follow.
Is there an easy way to get the auth and provider set up and imported into my App.js file without changing too much?
After looking at your code I made some changes to it, maybe this approach help?
import * as firebase from 'firebase'
import { DB_CONFIG } from './Config/config';
// Configure firebase and it will be available globally.
firebase.initializeApp(DB_CONFIG)
// Once initialized you just need to create the provider and auth
const provider = new firebase.auth.GoogleAuthProvider();
const auth = firebase.auth();
class App extends Component {
constructor(props){
super(props);
// And just call firebase.database() to access database functionality.
// You don't even need to assign it to a local variable as you can access
// it anywhere in your code just by importing firebase
// and calling firebase.database() and also firebase.auth()
this.databaseRef = firebase.database().ref().child('players');
}
}
PS: I would delete your gist because, even though you changed the config file, your configuration info is still available in the gist revisions...