I am creating a site for my store and learning Vue js simultaneously. I'm stuck in the part regarding uploading a product image to firebase. I get that storageRef.put is not a function. I'm using Vue js 3 and firebase 9.
uploadImage(e) {
const file = e.target.files[0];
const storage = getStorage();
const storageRef = storageReference(storage, 'products/' + file.name);
storageRef.put(file);
}
This syntax you provide is for firebase version 8.
For version 9
import { getStorage, ref, uploadBytes } from "firebase/storage";
uploadImage(e) {
const file = e.target.files[0];
const storage = getStorage();
// Create a reference to 'mountains.jpg'
const storageRef = ref(storage, 'products/' + file.name);
uploadBytes(storageRef, file).then((snapshot) => {
console.log('Uploaded!');
});
}
For more resources.
https://firebase.google.com/docs/storage/web/upload-files#web-version-9
Related
I have a path in my bucket that has 10 images can I get the downlead URL of all those 10 images at once in a similar way when you for each doc fields in getDoc() ? or it it stricted to only one at time and to only a specific file name refrence?
const storage = getStorage();
getDownloadURL(ref(storage, 'images/1.jpg'))
.then((url) => {
}
const storage = getStorage();
getDownloadURL(ref(storage, 'images/'))
.then((url) => {
// all the images inside path images/
}
I am attempting to upload an mp3 to firebase storage using expo and react native. So far I've got the file into firebase storage, but it's only 9bytes large, so I'm doing something wrong. I've attempted this with blob as shown below with no success.
Here is a screenshot of the firebase storage folder showing the file uploaded but not the data of said file:
Any help is greatly appreciated, I feel like I'm missing a step to actually upload the data along with the file.
export default function SongPicker() {
const [song, setSong] = useState(null);
//Get current user through authentication
const user = auth.currentUser;
const pickDocument = async () => {
let result = await DocumentPicker.getDocumentAsync({});
// Fetch the photo with it's local URI
const response = fetch(result.uri);
alert(result.uri);
console.log(result);
const file = new Blob(
[response.value], {
type: 'audio/mpeg'
});
console.log('do we see this?');
try {
//Create the file reference
const storage = getStorage();
const storageRef = ref(storage, `songs/${user.uid}/${result.name}`);
// Upload Blob file to Firebase
const snapshot = uploadBytes(storageRef, file, 'blob').then((snapshot) => {
console.log('Uploaded a song to firebase storage!');
});
setSong(result.uri);
} catch (error) {
console.log(error);
}
}
The fetch() returns a Promise so you should add an await for that as well.
const response = await fetch(result.uri);
Then try using blob() method on the Response:
const file = await response.blob()
The third param in uploadBytes should be upload metadata object but you can skip that here:
const snapshot = await uploadBytes(storageRef, file).
I have on my site an page where I handled File upload, but since I upgraded Firebase (I guess it was Firebase v7/8) this particular feature is not working anymore.
To handled the file upload in firebase storage I created a custom hook, where I use the useEffect because I need it to run each time there is a new file value. I passed a parametter (file) for the file I'm trying to upload and store it in database, and that way databse contains all image's url. Then I used the datas to load images in a react components.
The error I've got:
Uncaught TypeError: projectStorage.ref is not a function
Since I'm on Firebase v9 I'm lillte bit confused about it, and don't know what to change. Thank you for your help, I really appreciate =).
useStorage.jsx (custom hook)
import {projectStorage, projectFirestore, timestamp} from '../Firebase'
import { useEffect, useState } from 'react'
function useStorage(file) {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
const storageRef = projectStorage.ref(file.name)
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percent = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percent >> 0); // or Math.trunc()
}, (err) => {
setError(err);
}, async () =>{
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt});
setUrl(url);
});
}, [file]);
return {progress, url, error};
}
export default useStorage;
There's a top level function uploadBytesResumable() to upload files while monitoring progress. Try refactoring the code as shown below:
import {projectStorage, projectFirestore, timestamp} from '../Firebase'
import { ref as storageRef, uploadBytesResumable } from "firebase/storage";
useEffect(() => {
// Creating a storage reference
const storageReference = storageRef(projectStorage, file.name);
// Creating an upload task
const uploadTask = uploadBytesResumable(storageReference, file);
// Monitoring upload progress
uploadTask.on("state_changed", (snapshot: any) => {
console.log(snapshot);
// render progress
});
}, [file])
Checkout the documentation on Upload files with Cloud Storage on Web.
I am using Jest to test my firebase functions. This is all in the browser, so I don't have any conflicts with firebase on the server side. When I use firebase.auth() or firebase.database() everything works fine. When I try to use firebase.storage() my tests fail.
Here is my firebase import and initialization:
import firebase from 'firebase';
import config from '../config';
export const firebaseApp = firebase.initializeApp(config.FIREBASE_CONFIG);
export const firebaseAuth = firebaseApp.auth();
export const firebaseDb = firebaseApp.database();
I have an imageUtils file that has an upload function in it:
import { firebaseApp } from './firebase';
export const uploadImage = (firebaseStoragePath, imageURL) => {
return new Promise((resolve, reject) => {
// reject if there is no imagePath provided
if (!firebaseStoragePath) reject('No image path was provided. Cannot upload the file.');
// reject if there is no imageURL provided
if (!imageURL) reject('No image url was provided. Cannot upload the file');
// create the reference
const imageRef = firebaseApp.storage().ref().child(firebaseStoragePath);
let uploadTask;
// check if this is a dataURL
if (isDataURL(imageURL)) {
// the image is a base64 image string
// create the upload task
uploadTask = imageRef.putString(imageURL);
} else {
// the image is a file
// create the upload task
uploadTask = imageRef.put(imageURL);
}
// monitor the upload process for state changes
const unsub = uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED,
(snapshot) => {
// this is where we can check on progress
}, (error) => {
reject(error.serverResponse);
unsub();
}, () => {
// success function
resolve(uploadTask.snapshot.downloadURL);
unsub();
});
});
};
And I am trying to create a test case for that function and every time it fails with:
TypeError: _firebase3.firebaseApp.storage is not a function
When I run the app normally everything works fine and I never get errors about storage() being undefined or not a function. It is only when I try to run a test case.
I have set a console.dir(firebaseApp); line in the firebase import, and it comes back with both auth() and database() but no storage. How can I get storage to import/initialize/exist properly?
Add the following import
import "firebase/storage";
It looks like this was fixed in a recent update to the firebase javascript package:
I had the same problem. Another possible solution:
import * as firebase from "firebase";
import "firebase/app";
import "firebase/storage";
I want to download an entire folder from Firebase storage. I can download single files using DownloadURL as follows, but it does not work for folders.
var storageRef = firebase.storage().ref();
// Create a reference to the file we want to download
var starsRef = storageRef.child(path);
// Get the download URL
starsRef.getDownloadURL().then(function(url) {
// Insert url into an <img> tag to "download"
ImageUrl = url;
console.log(ImageUrl);
}).catch(function(error) {
switch (error.code) {
case 'storage/object_not_found':
// File doesn't exist
break;
case 'storage/unauthorized':
// User doesn't have permission to access the object
break;
case 'storage/canceled':
// User canceled the upload
break;
case 'storage/unknown':
// Unknown error occurred, inspect the server response
break;
}
});
How to download entire folder from Firebase?
You can use gsutil to download the whole storage bucket
gsutil -m cp -R gs://<bucket_name> .
There is no API in Firebase Storage to download all files in a folder. You will have to download the files one by one, or create a zip file that contains all the files.
As Lahiru's answer shows it can be accomplished with gsutils, but that's a server-side operation - not something you'd run in your client-side application.
Related:
How to get a list of all files in Cloud Storage in a Firebase app?
Command gustil for Windows !!!
gsutil cp -r gs://<bucket_name>.appspot.com/OBJECT_NAME "D:\path"
Use Cloud tools for PowerShell
REF for install windows >> https://cloud.google.com/storage/docs/gsutil_install
You can download the folder by creating a zip file of it.
Here is a sample function:
import JSZip from 'jszip';
import { saveAs } from 'file-saver';
import {
getStorage,
listAll,
ref,
getDownloadURL,
getMetadata,
} from 'firebase/storage';
import { auth } from '../../Firebase';
export const downloadFolderAsZip = async () => {
const jszip = new JSZip();
const storage = getStorage();
const folderRef = ref(
storage,
'images'
);
const folder = await listAll(folderRef);
const promises = folder.items
.map(async (item) => {
const file = await getMetadata(item);
const fileRef = ref(storage, item.fullPath);
const fileBlob = await getDownloadURL(fileRef).then((url) => {
return fetch(url).then((response) => response.blob());
});
jszip.file(file.name, fileBlob);
})
.reduce((acc, curr) => acc.then(() => curr), Promise.resolve());
await promises;
const blob = await jszip.generateAsync({ type: 'blob' });
saveAs(blob, 'download.zip');
};
For a recursive solution that includes subfolders in the zip file, see the following sample. You'll instantiate a jszip object, await promises from a function that zips files and traverses the directories, then save the zip. If the content is a file ("item"), it is zipped into the jszip object. If it is a folder ("prefix"), the function is called again with a new subpath, passing in the same jszip object. For further improvement, you may want to get contents with list and pagination if your contents are too many for listAll, since listAll limits retrievals.
import JSZip from 'jszip';
import { saveAs } from 'file-saver';
import {
getStorage, ref, getBlob, listAll,
} from "firebase/storage";
const addFilesFromDirectoryToZip = async (directoryPath = "", zip) => {
const storage = getStorage();
const directoryContentsRef = ref(
storage,
directoryPath
);
const directoryContents = await listAll(directoryContentsRef);
for (const file of directoryContents.items) {
const fileRef = ref(storage, file.fullPath);
const fileBlob = await getBlob(fileRef)
zip.file(file.fullPath, fileBlob);
}
for (const folder of directoryContents.prefixes) {
await addFilesFromDirectoryToZip(folder.fullPath, zip);
};
};
export const downloadFolderAsZip = async (directoryPath = "") => {
const zip = new JSZip();
await addFilesFromDirectoryToZip(directoryPath, zip);
const blob = await zip.generateAsync({ type: "blob" });
const name = directoryPath.split('/').pop();
saveAs(blob, name);
};