How to make an image uploading app with Vue, Quasar, Firebase Storage and Cordova — Part 2

Jonathan Perry
Oct 20, 2019 · 6 min read

What we’re building

We’ll build a cross-platform mobile app for taking photos and uploading to firebase.

In Part 1, we saw how to take a picture and save it to Firebase Cloud Storage. In this post we’ll move the uploading to a separate thread via web worker, and use the blueimp library to generate a thumbnail locally and show it while uploading.

Web Workers

What is a web worker

Web Workers are a simple means for web content to run scripts in background threads. The worker thread can perform tasks without interfering with the user interface. (mozilla.org)

So we’ll use a web worker to offload code that can potentially block our UI thread — in our case the Firebase Storage code — to another thread.

Configuring workerize-loader

We’ll use workerize-loader to make using web workers a little easier (web workers interface is a little weird).

We need to add some webpack configuration to tell webpack to use workerize-loader. In quasar.conf.js in the build section add:

This tells webpack to load the file worker.js using workerize-loader.

Moving code to the worker

Let’s add the file src/services/worker.js and move our uploading code into it:

We’ve also added a deletePic call which we’ll see later in cloudStorage.js.

Adding simple state management

We’ll want to create an instance of the worker and save it in the app’s state. We don’t have state management yet, so let’s add a simple state management pattern using a store.js file:

A few things going on here:

  • We’re importing our worker using the prefix workerize-loader! which tells webpack to use the loader we configured earlier.
  • We moved the pics collection to the state object from Index.vue.
  • We exposed the method initWorker which initializes the worker instance.
  • We added some CRUD methods for persisting the pics collection in localStorage: addPic, loadPictures and delete.
  • updatePicUploaded and updatePicFailed changes the loading property of the picture. We’ll use this to show the spinner.

Generating thumbnails

We’re going to generate a thumbnail (on the client) to show while the image is uploading. We’ll use the blueimp library for this:

Let’s add another service for manipulating images: src/services/image-ops.js:

Notice we’ve moved the removeBase64Prefix and addBase64Prefix methods here. The generateThumbnail function takes imageData - a base64 string, uses the fetch API, converts it to a blob, and then uses blueimp’s loadImage to change it’s size to maxWidth. We’re loading maxWidth from a new config file we’ve added to make things tidy - src/services/config.js:

Adding the image-uploader service

We’ll extract all the image uploading flow to a service to keep our UI component clean. Add the file src/services/image-uploader.js:

What we’re doing in the uploadImageFromCamera method is: getting base64 from the cordova camera -> generating thumbnails using our imageOps -> generating a new pic object in our state with uploading=true -> uploading the picture to Firebase using the web worker -> updating the pic’s uploading state property when uploading is finished.

Putting it together

Now we’ve added all these services, we need to call them from our components.

In App.vue, we’ll use the mounted lifecycle hook to initialize the worker and load the saved picture urls from the saved state:

Finally, we’ll add the interface for viewing all this in Index.vue:

What’s going on here:

  • We’ve added a q-spinner to show when the uploading property of the picture is true.
  • We’re calling imageUploader.uploadImageFromCamera when clicking on the photo button, which handles our uploading.
  • We’ve added some actions to the q-card of the picture (only delete is implemented for now)

Final app

That’s it! We have an image uploading app that shows a blurred thumbnails with a spinner, a little like WhatsApp’s image upload. Running all this using quasar dev -m android/ios will show the final result:

Further improvements

Some ideas for improving this app further would be:

  • Offload thumbnail creation to another web worker
  • Handle long lists of images with a virtual list component like this one
  • Add a carousel / gallery component for viewing images full-size
  • Add a retry mechanism for failed uploads
  • Use firebase auth — so that users can only delete their own photos

Source code

The full code is on GitHub here: vue-firebase-image-upload.

Enjoy :)

Image for post
Image for post

New JavaScript + Web Development articles every day.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store