Firebase Storage XMLHttpRequest is not defined error with Nuxt JS - firebase

I am in need of help with my web app that is uploading an image to firebase storage then wanting to display that image in a thumbnail.
I am getting the error this.xhr_ = new XMLHTTPREQUEST is not defined
I don't have 10 rep points so it seems I can't upload my image directly.
If there was a better way to do this please let me know.
I have looked through firebase docs and many stack overflow answers but can seem to have anything that works. I have tried to globally install xmlhttprequest, also as a dependency.
As you can see I also attempted to import XmlHttpRequest but it did nothing.
The error I am getting comes from the last statement with getdownloadurl()
<script>
import XMLHTTPREQUEST from 'xmlhttprequest'
import ImageCard from '../../components/ImageCard/ImageCard'
import {db} from '../../firebase/init.js'
import {storage} from '../../firebase/init.js'
export default {
name: "explore",
components: {
ImageCard,
db,
storage,
XMLHTTPREQUEST
},
data() {
return {
cards: [],
downloadUrl: ''
}
},
created(){
//fetch data from firestore
db.collection('Assets').get()
.then(snapshot => {
snapshot.forEach( doc => {
let card = doc.data()
console.log(card)
// the card.id is adding an id property onto the let card variable
card.id = doc.id
this.cards.push(card)
console.log(this.cards)
})
})
},
created() {
const storageRef = storage.ref()
const imagesRef = storageRef.child('AshAngelPaid.jpg');
console.log('Before getting requesting download url')
imagesRef.getDownloadURL().then( (url) => {
document.querySelector('img').src = url;
console.log('got download url');

Basically, while nuxtjs is rendering your component on the server side there's no xmlhttprequest, just move .getDownloadURL and related stuff into mounted() or beforeMount() lifecycle hook.

Related

Error when setting up Firebase automated backup with Google Cloud Functions

I'm trying to setup automatic backup of my Firestore using instructions here: https://firebase.google.com/docs/firestore/solutions/schedule-export
I get error:
firestoreExpert
g2o6pmdwatdp
TypeError: Cannot read properties of undefined (reading 'charCodeAt')
at peg$parsetemplate (/workspace/node_modules/google-gax/build/src/pathTemplateParser.js:304:17)
at Object.peg$parse [as parse] (/workspace/node_modules/google-gax/build/src/pathTemplateParser.js:633:18)
at new PathTemplate (/workspace/node_modules/google-gax/build/src/pathTemplate.js:55:54)
Any suggestions to debug this?
I've tried looking for errors in my permissions. E.g. I don't know how to check if the service has access to the specific bucket, although the GCL ran OK.
I've also tried looking for errors in the script.
index.js
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
// Replace BUCKET_NAME
const bucket = 'gs://EDITEDHERE.appspot.com'
exports.scheduledFirestoreExport = (event, context) => {
const databaseName = client.databasePath(
process.env.GCLOUD_PROJECT,
'(default)'
);
return client
.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
// Leave collectionIds empty to export all collections
// or define a list of collection IDs:
// collectionIds: ['users', 'posts']
collectionIds: [],
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
return response;
})
.catch(err => {
console.error(err);
});
};
and package.json
{
"dependencies": {
"#google-cloud/firestore": "^1.3.0"
}
}
I found these great video tutorials
How to schedule firestorm backups and
How To Transfer Firestore Data From One Project To Another

Next.js with Firebase Remote Config

I was trying to integrate Google's Firebase Remote config into my Next.js app.
When following Firebase's docs, and just inserted the functions directly into my component's code block, like so:
const remoteConfig = getRemoteConfig(app);
I keep getting the following error when following their documentation:
FirebaseError: Remote Config: Undefined window object. This SDK only supports usage in a browser environment.
I understand that it happens since Nextjs is rendered server-side, so there's no window object yet, so here's my solution:
import {
fetchAndActivate,
getRemoteConfig,
getString,
} from 'firebase/remote-config';
const Home: NextPage<Props> = (props) => {
const [title, setTitle] = useState<string | null>('Is It True?');
useEffect(() => {
if (typeof window !== 'undefined') {
const remoteConfig = getRemoteConfig(app);
remoteConfig.settings.minimumFetchIntervalMillis = 3600000;
fetchAndActivate(remoteConfig)
.then(() => {
const titleData = getString(remoteConfig, 'trueOrFalse');
setTitle(titleData);
})
.catch((err) => {
console.log(err);
});
}
});
return <h1>{title}</h1>}
Basically, the important part is the if statement that checks if the window object exists, then it execute the Remote Config functions according to Firebase documents.
Also, it worked outside a useEffect, but I think that's probably a bad idea to leave it outside, maybe even it should have a dependency, can't think of one at the moment.

How to use Coinbase SDK in a Server-Side Rendered app?

I was trying to follow the guide here to get user's wallet through Coinbase in my Next.js app:
https://docs.cloud.coinbase.com/wallet-sdk/docs/initializing
But I get this when I tried to render the component with the SDK initiating.
Server Error
ReferenceError: localStorage is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Is there a proper way to make it work in a server-side rendered app?
These are the code btw if that matters.
// Coinbase START
// TypeScript
import CoinbaseWalletSDK from '#coinbase/wallet-sdk'
import Web3 from 'web3'
const APP_NAME = process.env.NAME
const APP_LOGO_URL = process.env.WEBSITE_URL + '/logo.png'
const DEFAULT_ETH_JSONRPC_URL = 'https://mainnet.infura.io/v3/' + process.env.INFURA_PROJECT_ID
const DEFAULT_CHAIN_ID = 1
// Initialize Coinbase Wallet SDK
export const coinbaseWallet = new CoinbaseWalletSDK({
appName: APP_NAME,
appLogoUrl: APP_LOGO_URL,
darkMode: false
})
// Initialize a Web3 Provider object
export const ethereum = coinbaseWallet.makeWeb3Provider(DEFAULT_ETH_JSONRPC_URL, DEFAULT_CHAIN_ID)
// Initialize a Web3 object
export const web3 = new Web3(ethereum as any)
// Coinbase END
Related call:
function connectCoinBase() {
console.log('connectCoinBase is triggered');
if (ethereum && mounted) {
setLoading(true);
ethereum.request({
method: 'eth_requestAccounts'
})
.then((res) => {
const accounts: string[] = res as string[];
if (accounts && accounts.length) {
setWalletId(accounts[0]);
setWalletType(2);
connectCrypto();
}
setLoading(false);
})
.catch(err => {
console.error('Coinbase eth_requestAccounts failed, error: ', err);
setLoading(false);
})
}
}
The error was thrown without calling this function but happens when this function is added and the page is rendered.
UPDATE: This error is related to the ScopedLocalStorage class inside the #coinbase/wallet-sdk dependency. The localStorage is not available in server-side rendering.

Next.js: How to create multiple dynamic pages coming from different types of API?

This is my first experience with Next.js. I am trying to create a dynamic route from the data coming from server.
I do convert the id to string but have the same error.
Server Error
Error: A required parameter (articleid) was not provided as a string in getStaticPaths for /article/[articleid]
I tried something similar with the data from web api it works fine but not for the data that I fetch from server. Can't figure out what I am missing.
Also why error message is pointing out server error in the first line?
Here is the component the error is coming from: pages/article/[articleid]/index.js
export const getStaticProps = async (context) => {
const res = await fetch(`${server}/api/article/${context.params.id}`);
const article = await res.json();
return {
props: {
article,
},
};
};
export const getStaticPaths = async () => {
const res = await fetch(`${server}/api/article/`);
const articles = await res.json();
const ids = articles.map((article) => article.id);
const paths = ids.map((id) => ({ params: { id: id.toString() } }));
return {
fallback: "blocking",
paths: paths,
};
};
`pages/api/article/[id].js file
import { articles } from "../../../data";
export default function handler({ query: { id } }, res) {
const filteredData = articles.filter((article) => article.id === id);
if (filteredData.length > 0) {
res.status(200).json(filteredData[0]);
} else {
res.status(404).json({ message: `article with id of ${id} is not found` });
}
}
UPDATE
I found out that my problem is definitely not from the code provided above.
Actually in my app I have another dynamic page where I fetch the data from another web api, which works fine. Changing the urls I found out that now web api dynamic page is throwing the same error. I assume the problem is that how I defined the paths, , [articleid] I mean.
Here is my components structure
The problem is with `pages/article/[articleid].
Here is how I am linking to the specific item
<Link href="/article/[articleid]" as={`/article/${article.id}`}>
<a className={styles.container}>
<h1>{article.title} →</h1>
<p>{article.body}</p>
</a>
</Link>
Any help will be appreciated
Actually I made it work changing the dynamic route id name in brackets, in my case [articleid], to just [id] and it worked fine. Image below.
But honestly, I didn't understand why the previous keyword ([articleid]) in brackets was not working.
I also tried another keywords inside the brackets for dynamic route like [article] and nothing worked except [id].
I didn't find anything related in Next.js docs about that.
I'd welcome any explanations why only [id] worked.

Uploading Image to Firebase in React Native

I have two image paths in my component state
I try to upload one of the images inside of a function but get an error:
Firebase Storage: Invalid argument in 'put' at index 0: Expected Blob or file
and my function
submitImages = () => {
// Upload images to Firebase storage
let user = firebaseAuth.currentUser;
let imagesRef = storageRef.child('productImages/' + user.uid);
imagesRef.put(this.state.imageFront).then(snapshot => {
console.log('Uploaded ' + this.state.imageFront);
});
}
What should I be doing instead to get these images up to Firebase. Thanks!
What the error says is that you need to use a blob. You can use react-native-fetch-blob: https://github.com/wkh237/react-native-fetch-blob
Check out this example: https://github.com/dailydrip/react-native-firebase-storage/blob/master/src/App.js#L43-L69
I am posting my code since this was a bit frustrating for me:
To upload images to firebase.storage you need to upload the images as Blobs. If you don't know what Blobs are, don't worry: BLOB stands for Binary Large OBject.
Step 1.
npm install --save react-native-fetch-blob
Step 2.
// copy and paste this code where you will handle the file upload
import RNFetchBlob from 'react-native-fetch-blob'
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
Step 3.
// The uploadImage function that you are going to use:
function uploadImage(uri, mime = 'image/jpeg', name) {
return new Promise((resolve, reject) => {
let imgUri = uri; let uploadBlob = null;
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
const { currentUser } = firebase.auth();
const imageRef = firebase.storage().ref(`/jobs/${currentUser.uid}`)
fs.readFile(uploadUri, 'base64')
.then(data => {
return Blob.build(data, { type: `${mime};BASE64` });
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime, name: name });
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error)
})
})
}
So how do you call this function?
Pass the URI of the image as the first argument. In my case img1, img2, img3 where variables that pointed to the URIs of the images, that I wanted to upload which were on my phone. They looked something like '/Phone/Pics/imageToUpload.jpeg', etc.
As the second argument you can pass 'image/jpeg' and the last argument is the name that you want to give the image. Chose the name that you like.
But what if I have several images and want to upload them and want to handle the upload correctly. What if one upload succeeds and the other does not?
Do this then:
let imgPromises = [];
imgPromises.push(uploadImage(img1, 'image/jpeg', 'imageOne'));
imgPromises.push(uploadImage(img2, 'image/jpeg', 'imageTwo'));
imgPromises.push(uploadImage(img3, 'image/jpeg', 'imageOne'));
Promise.all(imgPromises).then(urls => {
// ALL IMAGES SUCCEEDED and you will get an array of URIS that you can save to your database for later use!
}).catch(error => {
// One OR many images failed the upload. Give feedback to someone.
})
You can use react-native-firebase to upload image to storge https://rnfirebase.io/
const storage = firebase.storage();
const sessionId = new Date().getTime();
const imageRef = storage.ref('images').child(`${sessionId}`);
return imageRef.putFile(uri);
So far this is the best method I found to upload a file/image to a Firebase Storage with React Native. This method does not use any third party libraries except for the Expo SDK.
Get the File URI of the image to upload. To do this we will need to use Expo ImagePicker. The best place to include this code block is on to a button with an onPress handler.
ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images"
}).then((result)=>{
if (!result.cancelled) {
// User picked an image
const {height, width, type, uri} = result;
return uriToBlob(uri); // will follow later
}
})
Generate a BLOB from the image URI. There are a lot of third party libraries to help do this. But if you don't want to install a library, then you can use XMLHttpRequest. The React Native docs recommends we use the Fetch API, but right now we can't use it because it will throw an error that we can only fetch https:// urls, but our URI is a file://. There is a way to get pass this, but using XMLHttpRequest will make things a lot simpler.
uriToBlob = (uri) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function() {
// return the blob
resolve(xhr.response);
};
xhr.onerror = function() {
// something went wrong
reject(new Error('uriToBlob failed'));
};
// this helps us get a blob
xhr.responseType = 'blob';
xhr.open('GET', uri, true);
xhr.send(null);
});
}
We have our BLOB, let's upload it to Firebase. This part is pretty straightforward as explained in the Firebase Docs.
uploadToFirebase = (blob) => {
return new Promise((resolve, reject)=>{
var storageRef = firebase.storage().ref();
storageRef.child('uploads/photo.jpg').put(blob, {
contentType: 'image/jpeg'
}).then((snapshot)=>{
blob.close(); // let's free up the blob
resolve(snapshot);
}).catch((error)=>{
reject(error);
});
});
}
That's it, you can now upload a file to Firebase Storage. The key part to this is getting a File URI and converting it to a BLOB. You can read more about this method here.
For some time I used the Firebase JS SDK with React Native. Using this library, as referred in this thread you need to use a library like rn-fetch-blob (react-native-fetch-blob is not maintained anymore) in order to provide a blob to Firebase Storage put() method.
Recently I started using React Native Firebase. As they say in their website "Using the native Firebase SDKs with React Native Firebase allows you to consume device SDKs which don't exist on the Firebase JS SDK".
Using React-Native-Firebase you don't need any extra library to upload images to Firebase Storage, and your code gets much cleaner:
export const uploadImage = (path, mime = 'application/octet-stream') => {
return new Promise((resolve, reject) => {
const imageRef = firebase.storage().ref('images').child('filename.jpg');
return imageRef.put(path, { contentType: mime })
.then(() => {
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error);
console.log('Error uploading image: ', error);
});
});
};
if you don’t mind using cloudinary, I show how to upload and then get the uploaded url to save to firebase
https://medium.com/#ifeoluwaking24/how-to-upload-an-image-in-expo-react-native-to-firebase-using-cloudinary-24aac981c87
Also you can try it snack but make sure you add your cloud_name and upload_preset
https://snack.expo.io/#ifeking/upload-to-cloudinary

Resources