I am new to react native and firebase and am trying to create an app that uses firebase to send background notifications within iOS.
When I run my app I seem to get the following error message and my app won't run.
TypeError: (0, _app2.messaging) is not a function. (In '(0, _app2.messaging)()', '(0, _app2.messaging)' is undefined)
Here is my firebase code.
import {name as appName} from './app.json';
import {AppRegistry} from 'react-native';
import {messaging} from '#react-native-firebase/app';
requestUserPermission = async () => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
};
// Register background handler
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
console.log('Messaage handled in the background!', remoteMessage);
});
HeadlessCheck = ({ isHeadless }) => {
if (isHeadless) {
// App has beeen launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
I might be writing my firebase code wrong as I am new to firebase and I'm still unsure what I am doing and am simply trying to follow a few online tutorials.
I did google this problem but not one seems to be having it. I tried to delete my node_modules folder and ran yarn again but this didn't fix the problem.
Seems that messaging does not exist, I noticed you are importing messaging from #react-native-firebase/app. Following the docs (https://rnfirebase.io/messaging/usage) looks like you need a different module.
Installing the messaging module:
# Install the messaging module
yarn add #react-native-firebase/messaging
# If you're developing your app using iOS, run this command
cd ios/ && pod install
Importing messaging for usage
import messaging from '#react-native-firebase/messaging';
I am getting the following error when uploading an image to Firebase:
Error: No Firebase App '[DEFAULT]' has been created - call firebase.initializeApp()
Here is my code:
App.js
import * as Firebase from 'firebase';
componentDidMount() {
Firebase.initializeApp(firebaseConfig);
}
Profile.js
import * as Firebase from 'firebase';
import rnFb from '#react-native-firebase/storage';
uploadImage = localUri =>
new Promise((resolve, reject) => {
const localUri2 = Platform.OS === 'ios' ? localUri.replace('file://', '') : localUri;
const fbUri = Firebase.storage().ref();
rnFb().ref(localUri2).putFile(fbUri)
.then(
() => { resolve(); }
)
.catch(
(e) => { reject(e); }
);
});
It's failing at the .putFile line.
I don't understand what the problem is because I am calling .initializeApp() in App.js
UPDATE 12/21
I added console.log(Firebase.apps.length); right before rnFb().ref(localUri2).putFile(fbUri) and the output is 1...very strange indeed.
...and if I do exactly as the error asks and call firebase.initializeApp() right before rnFb().ref(localUri2).putFile(fbUri) I get the error Error:
Firebase: Firebase App named '[DEFAULT]' already exists
Help!!
My understanding is that the Firebase SDK used internally inside #react-native-firebase is independent of the ordinary Firebase SDK from firebase.
It can be exposed using:
import firebase from '#react-native-firebase/app';
// OR
import { firebase } from '#react-native-firebase/storage';
Applying these changes (and simplifying your code), leaves you with the following:
import storage, { firebase } from '#react-native-firebase/storage';
// can possibly be somewhere else
firebase.initializeApp(firebaseConfig);
uploadImage = localUri => {
const localUri2 = Platform.OS === 'ios' ? localUri.replace('file://', '') : localUri;
return storage().ref('/path/to/upload/to').putFile(localUri2)
}
Rather than use "client initialization" using firebase.initializeApp(), you can also use "native initialization"
for Android and iOS.
Have you followed the API documentation? I can't seem to find anywhere in the docs that you need to manually call initializeApp()
I think your fbUri is wrong. The param has to be a string.
For ex:
firebase
.storage()
.ref('remote_path') // remote path where you want to store
.putFile(
'local/ok.jpeg' // local file
)
.then(successCb)
.catch(failureCb);
I'm importing Firebase into my Sapper application, I do not want the imports to be evaluated on the server. How do I make sure imports are only on the client-side?
I am using Sapper to run sapper export which generates the static files. I have tried:
Creating the firebase instance in it's own file and exported the firebase.auth() and firebase.firestore() modules.
Trying to adjust the rollup.config.js to resolve the dependencies differently, as suggested from the error message below. This brings more headaches.
Creating the Firebase instance in client.js. Unsuccessful.
Creating the instance in stores.js. Unsuccessful.
Declaring the variable and assigning it in onMount(). This causes me to have to work in different block scopes. And feels a bit hacky.
The initialization of the app, works fine:
import firebase from 'firebase/app'
const config = {...}
firebase.initializeApp(config);
I have also discovered that if I change the import to just import firebase from 'firebase' I do not get this server error:
#firebase/app:
Warning: This is a browser-targeted Firebase bundle but it appears it is being run in a Node environment. If running in a Node environment, make sure you are using the bundle specified by the "main" field in package.json.
If you are using Webpack, you can specify "main" as the first item in
"resolve.mainFields": https://webpack.js.org/configuration/resolve/#resolvemainfields
If using Rollup, use the rollup-plugin-node-resolve plugin and set "module" to false and "main" to true: https://github.com/rollup/rollup-plugin-node-resolve
I expected to just export these firebase functionalities from a file and import them into my components like:
<script>
import { auth } from "../firebase";
</script>
But as soon as that import is include, the dev server crashes. I don't want to use it on the server, since I'm just generating the static files.
Does anyone have some ideas on how to achieve importing only on client side?
So I have spent too much time on this. There isn't really a more elegant solution than onMOunt.
However, I did realize that sapper really should be used for it's SSR capabilities. And I wrote an article about how to get set up on Firebase with Sapper SSR and Cloud Functions:
https://dev.to/eckhardtd/how-to-host-a-sapper-js-ssr-app-on-firebase-hmb
Another solution to original question is to put the Firebase CDN's in the global scope via the src/template.html file.
<body>
<!-- The application will be rendered inside this element,
because `app/client.js` references it -->
<div id='sapper'>%sapper.html%</div>
<!-- Sapper creates a <script> tag containing `app/client.js`
and anything else it needs to hydrate the app and
initialise the router -->
%sapper.scripts%
<!-- Insert these scripts at the bottom of the HTML, but before you use any Firebase services -->
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-app.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.0.4/firebase-firestore.js"></script>
</body>
</html>
and in the component:
<script>
import { onMount } from 'svelte';
let database, authentication;
onMount(() => {
database = firebase.firestore();
authentication = firebase.auth();
});
const authHandler = () => {
if (process.browser) {
authentication
.createUserWithEmailAndPassword()
.catch(e => console.error(e));
}
}
</script>
<button on:click={authHandler}>Sign up</button>
I was able to import firebase using ES6. If you are using rollup you need to consfigure namedExports in commonjs plugin:
//--- rollup.config.js ---
...
commonjs({
namedExports: {
// left-hand side can be an absolute path, a path
// relative to the current directory, or the name
// of a module in node_modules
'node_modules/idb/build/idb.js': ['openDb'],
'node_modules/firebase/dist/index.cjs.js': ['initializeApp', 'firestore'],
},
}),
The you can use it like this:
//--- db.js ---
import * as firebase from 'firebase';
import 'firebase/database';
import { firebaseConfig } from '../config'; //<-- Firebase initialization config json
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
export { firebase };
// Initialize db
export const db = firebase.firestore();
and maybe use it in a service like such:
// --- userService.js ----
import { db } from './common';
const usersCol = db.collection('users');
export default {
async login(username, password) {
const userDoc = await usersCol.doc(username).get();
const user = userDoc.data();
if (user && user.password === password) {
return user;
}
return null;
},
};
EDITED
Full rollup config
/* eslint-disable global-require */
import resolve from 'rollup-plugin-node-resolve';
import replace from 'rollup-plugin-replace';
import commonjs from 'rollup-plugin-commonjs';
import svelte from 'rollup-plugin-svelte';
import babel from 'rollup-plugin-babel';
import { terser } from 'rollup-plugin-terser';
import config from 'sapper/config/rollup';
import { sass } from 'svelte-preprocess-sass';
import pkg from './package.json';
const mode = process.env.NODE_ENV;
const dev = mode === 'development';
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
// eslint-disable-next-line no-shadow
const onwarn = (warning, onwarn) =>
(warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes('/#sapper/')) || onwarn(warning);
export default {
client: {
input: config.client.input(),
output: config.client.output(),
plugins: [
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
svelte({
dev,
hydratable: true,
emitCss: true,
preprocess: {
style: sass(),
},
}),
resolve({
browser: true,
}),
commonjs({
namedExports: {
// left-hand side can be an absolute path, a path
// relative to the current directory, or the name
// of a module in node_modules
'node_modules/idb/build/idb.js': ['openDb'],
'node_modules/firebase/dist/index.cjs.js': ['initializeApp', 'firestore'],
},
}),
legacy &&
babel({
extensions: ['.js', '.mjs', '.html', '.svelte'],
runtimeHelpers: true,
exclude: ['node_modules/#babel/**'],
presets: [
[
'#babel/preset-env',
{
targets: '> 0.25%, not dead',
},
],
],
plugins: [
'#babel/plugin-syntax-dynamic-import',
[
'#babel/plugin-transform-runtime',
{
useESModules: true,
},
],
],
}),
!dev &&
terser({
module: true,
}),
],
onwarn,
},
server: {
input: config.server.input(),
output: config.server.output(),
plugins: [
replace({
'process.browser': false,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
svelte({
generate: 'ssr',
dev,
}),
resolve(),
commonjs(),
],
external: Object.keys(pkg.dependencies).concat(require('module').builtinModules || Object.keys(process.binding('natives'))),
onwarn,
},
serviceworker: {
input: config.serviceworker.input(),
output: config.serviceworker.output(),
plugins: [
resolve(),
replace({
'process.browser': true,
'process.env.NODE_ENV': JSON.stringify(mode),
}),
commonjs(),
!dev && terser(),
],
onwarn,
},
};
The clean way is to use the Dynamic Import as the documentation said: Making a component SSR compatible
The way to get around this is to use a dynamic import for your component, from within the onMount function (which is only called on the client), so that your import code is never called on the server.
So here for example we want to import the core of firebase and the authentication package too.
<script>
let firebase;
onMount(async () => {
const module = await import("firebase/app");
await import("firebase/auth");
firebase = module.default;
firebase.initializeApp(firebaseConfig);
});
<script>
And now you can use firebase object as you can, for example we want to login with email and password:
let email;
let password;
async function login() {
try {
let result = await firebase.auth().signInWithEmailAndPassword(
email,
password
);
console.log(result.user);
} catch (error) {
console.log(error.code, error.message);
}
}
In order to use Firebase with Sapper, you have to import firebase not firebase/app. You do want firebase to be able to load correctly with SSR on the backend, not just the frontend. If you have some metatags, for example, that would be stored in the database, you want them to load on the backend (UNTESTED).
You could just use firebase, but then you get the annoying console warning. Remember also firebase loads ALL firebase dependencies while firebase/app does not, that is why you don't want to use it on the frontend. There is probably a way with admin-firebase, but we want to have less dependencies.
Do not use rxfire at all. You don't need it. It causes errors with Sapper. Just plain Firebase.
firebase.ts
import firebase from 'firebase/app';
import "firebase/auth";
import "firebase/firestore";
import * as config from "./config.json";
const fb = (process as any).browser ? firebase : require('firebase');
fb.initializeApp(config);
export const auth = fb.auth();
export const googleProvider = new fb.auth.GoogleAuthProvider();
export const db = fb.firestore();
Firebase functions require an extra step and you must enable dynamic imports. (UNTESTED)
export const functions = (process as any).browser ? async () => {
await import("firebase/functions");
return fb.functions()
} : fb.functions();
While this compiles, I have not tried to run httpsCallable or confirmed it will load from the database on the backend for seo ssr from the db. Let me know if it works.
I suspect all of this will work with the new SvelteKit now that Sapper is dead.
I'm writing my own nuxt plugin for firebase/firestore. I'm loading it in the config with:
plugins: [
'~/plugins/firestore.js',
{ src: '~/plugins/vuex-persist', ssr: false }
],
The file itself looks like this
import Vue from 'vue'
import * as firebase from 'firebase/app';
import 'firebase/firestore';
const config = {
...
}
firebase.initializeApp(config)
const settings = {
timestampsInSnapshots: true
}
const store = firebase.firestore()
store.settings(settings)
class Firestore {
...
}
const firestore = new Firestore()
export default ({ app }, inject) => {
inject('firestore', firestore)
}
When I'm running npm run dev it tries to create a firebase instance on each automatic reload. How can I have it only create this instance once?
Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).
You can check firebase.apps to see if its loaded. If your only loading it once, then you can just check the length. If you have multiple then you could check each apps name. Once it helped for me
if (!firebase.apps.length) {
firebase.initializeApp({});
}
Currently found this question (which also puzzled me), but I'm currently using "firebase" to authenticate, and "Firebase" from Ionic Native to get analytics data on the Firebase console. I think that one of these is redundant (since I have the Firebase initialization data once as an object in code, and another one in google-services.json).
So what is the difference, are these two packages substitutes for each other, or is there something else.
u talk about node-modules in ionic. im using if i understand to using it. and my experience tell me its not substitutes for each other. Lets talk about the modules.
First if using:
import firebase from 'firebase'
or
import * as firebase from "firebase";
working with dataSnapshot, snapshot, snap.
if i need object to array data from firebase example:
import firebase from 'firebase';
this.addProduct = firebase.database().ref('/product-List');
this.addProduct.on('value', snapshot => {
this.productList = [];
snapshot.forEach( snap => {
this.productList.push({
category: snap.val().category,
id: snap.key,
in_stock: snap.val().in_stock,
name: snap.val().name,
downloadURL: snap.val().downloadURL,
short_description: snap.val().short_description,
description: snap.val().description,
regular_price: snap.val().regular_price,
sale_price: snap.val().sale_price,
brand: snap.val().brand,
vendor: snap.val().vendor
});
});
});
}
another node-modules ionic-native/firebase
import {Firebase} from '#ionic-native/firebase';
plugin for push notifications, event tracking, crash reporting, analytics and more.
in my case. im using for login with phone and verifyPhoneNumber example:
import {Firebase} from '#ionic-native/firebase';
constructor(private firebasePlugin: Firebase) {
}
Private registerPhone(): void {
if (!this.phoneNumber.value) {
alert('Mohon isi nomor telepon anda');
return;
}
const appVerifier = this.recaptchaVerifier;
const phoneNo = '+62' + this.phoneNumber.value;
if (this.platform.is('cordova')) {
try {
this.firebasePlugin.verifyPhoneNumber(phoneNo, 60).then (credential=> {
// alert("SMS Kode Verifikasi Berhasil dikirim ke Nomor Telp anda");
console.log(credential);
this.showPrompt(credential.verificationId);
}).catch (error => {
console.error(error);
});
}catch(error){alert(error.message)}
}
}