Uppy File Uploading

By  on  
Uppy

One of the big tasks I was charged with at my first job was setting up a system by which any customer or potential customer (aka anonymous user) could upload PDF and image files. I had loads of constraints to deal with: browser support, server settings, variance in user tech knowledge, etc. Ultimately we needed to use a Java Applet (!) to get the job done. Gross.

Luckily all of the constraints I had to deal with back then have improved and most of the limitations I faced have been resolved. Today I could use Uppy, an open source, elegant, robust utility for file uploading. It's super customizable and easy for you, the developer, to implement and for your users to use. Let's have a look!

Quick Hits

  • Open source!
  • Very little code required to implement
  • Front-end widget is elegant and easy to use
  • Uploads can happen without page reload
  • State recovery (making uploads survive browser crashes or accidental navigate-aways)
  • Works well on mobile
  • Works with any JavaScript framework
  • Provides a wide array of plugins to enrich the uploading experience
  • Easy to localize strings (supply your own pirate language, Shiver me timbers!)
  • Can upload to your existing Apache server (XHR)
  • or: Can upload directly to S3
  • or: Can upload to a Tus-enabled server (making uploads survive travel- and poor network conditions)
  • Provides a server utility that lets your users fetch from Google Drive, Dropbox, Instagram
  • Brought to you by the people behind Transloadit. They offer encoding features, and hosted versions of the Uppy Server utility and Tus

At a Glance Demo

Have a look at usage of Uppy's widget in action:

The Uppy widget:

  • provides a elegant, well-designed interface
  • features drag and drop file uploading
  • allows pausable and resumable uploading
  • provides a method for renaming uploaded files

Let's have a look at the code to put this together!

Implementing the Uppy File Uploader

The creators of Uppy got implementation right: make the developer implement the least amount of code necessary to have a functional, "drop in place" utility. Start by installing Uppy:

Add the CSS and JavaScript libraries to the page:

<!-- In the header -->
<link href="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.css" rel="stylesheet">

<!-- Where the drag and drop will be -->
<div id="drag-drop-area"></div>

<!-- Bottom of the page -->
<script src="https://transloadit.edgly.net/releases/uppy/v0.25.2/dist/uppy.min.js"></script>

Then initialize Uppy!

<script>
  var uppy = Uppy.Core({ autoProceed: false })
  uppy.use(Uppy.Dashboard, { target: '#drag-drop-area', inline: true })
  uppy.use(Uppy.XHRUpload, { endpoint: 'https://mywebsite.com/receive-file.php' })
</script>

Boom! You have an awesome file upload utility with little hassle that looks great! Check out the live version on CodePen

If you don't want to run Uppy of a CDN and prefer to build it yourself with Browserify or Webpack, just use npm instead:

npm install uppy --save
<script>
var Uppy = require('uppy/lib/core')
var Dashboard = require('uppy/lib/plugins/Dashboard')
var XHRUpload = require('uppy/lib/plugins/XHRUpload')

const uppy = Uppy({ autoProceed: false })
uppy.use(Dashboard, { target: '#drag-drop-area', inline: true })
uppy.use(XHRUpload, { endpoint: 'https://mywebsite.com/receive-file.php' })
</script>

Uppy also provides you a number of events for file uploads:

uppy.on('file-added', (file) => {
  // Do something
});

uppy.on('upload', (data) => {
  // Do something
})

uppy.on('complete', (result) => {
  // Do something
})

Uppy's API is so easy to use that you can consider it a "drop in" API for incredible JavaScript uploading

Want to use any of the Uppy plugins? It's actually pretty easy -- let's check out implementation of what everyone expects from uploads these days, drag & drop:

const Dashboard = require('uppy/lib/plugins/Dashboard')

uppy.use(Dashboard, { target: '#drag-drop-area', inline: true })

The Dashboard plugin here renders a clean and simple drag and drop area, shows file previews, lets you edit meta data and shows upload progress. It acts as a host for other plugins. When you add the Webcam or Instagram plugins, they appear in the Dashboard as tabs, and your users can then select files from any of those as well.

Now let's add the Webcam plugin:

const Webcam = require('uppy/lib/plugins/Webcam')

uppy.use(Webcam, {
  countdown: false,
  mirror: true,
  facingMode: 'user',
  target: Dashboard // Webcam will be installed to the Dashboard
})

Uppy Server

With the XHRUpload plugin Uppy will upload to your existing Apache/Nginx/Node.js/Ruby/PHP server from local disk or webcam. No Uppy Server required. If however you want to add fetching files from Dropbox and Instagram, you will need to run an Uppy Server in the cloud. Uppy Server is open source as well, so you can host it yourself. The API docs are super detailed!

The advantages of having a helper like Uppy Server in the cloud are clear. If your user is on mobile, and picks a 5GB file from their Dropbox, it won't have to be fetched to their phone, and then uploaded. Instead, the file is moved directly between servers. This saves a lot of bandwidth and battery. This is what Uppy Server facilitates, as well as managing the secrets required to access these files.

Let's look at a demo how you could easily allow fetching from remote providers like Google Drive and Dropbox or a plain accessible URL:

const GoogleDrive = require('uppy/lib/plugins/GoogleDrive')
const Url = require('uppy/lib/plugins/Url')

// remote providers require the uppy server utility. 
// we're using the public demo server in this case:
uppy.use(GoogleDrive, { target: Dashboard, host: 'https://server.uppy.io/' })
uppy.use(Url, { target: Dashboard, host: 'https://server.uppy.io/ })

If you decide you want Uppy Server but not host it, you could also let Transloadit handle that. Transloadit created both Uppy and the Tus standard. It might come in handy that Transloadit also offers integrated virus scan, image crop, transcode, face detect, and more. They will store the results on storage of your choosing. This way you'll always own all content, and you can be confident that what is uploaded, displays optimally on all devices and browsers.

Transloadit

I hadn't heard about Transloadit before but it seems they're a small remote company that's been relentlessly trying to advance the file uploading & processing space, and that the majority of their tech has been released as open source 💗

Transloadit's uploading and processing service delivers an awesome array of functionality:

  • Resize, crop, and watermark images
  • Convert videos to GIFs, and visa versa
  • Transcode video and extract thumbnails
  • Take website screenshots
  • Create waveform images from audio
  • Create slideshow videos from images and audio
  • Chain conversions together to create unique "workflows" in a single declaritive JSON language
  • Stability of 99.99% uptime over 9 years
  • Manipulate media on the fly
  • Integrates well for different media types and different languages and frameworks
  • Trusted by Coursera, The New York Times, Oracle, Cambridge University, and more

As a final demo, let's look at a simple example of how Uppy plays with Transloadit, for when you want to, say, add a "Powered by Uppy" text to images that your users are uploading:

const Uppy = require('uppy/lib/core')
const Dashboard = require('uppy/lib/plugins/Dashboard')
const Transloadit = require('uppy/lib/plugins/Transloadit')

const uppy = Uppy()
  .use(Dashboard, { target: '#drag-drop-area', inline: true })
  .use(Transloadit, {
    waitForEncoding: true,
    params: {
      auth: { key: YOUR_TRANSLOADIT_KEY },
      steps: {
        resize: {
          width: 250,
          height: 250,
          robot: '/image/resize',
          text: [{'text': 'Powered by Uppy', 'font': 'Ubuntu', 'color': '#eeeeee', 'valign': 'bottom', 'align': 'right', 'x_offset': 16, 'y_offset': -10}]
        }
      }
    }
  })

uppy.on('transloadit:result', (stepName, result) => {
  // use transloadit encoding result here.
  console.log('Result here ====>', stepName, result)
  console.log('Cropped image url is here ====>', result.url)
})

Check out an interactive Uppy+Transloadit demo

Managing file uploads, from both the client side and server side perspectives can be a total nightmare; add how difficult drag & drop as well as upload validation can be and having an awesome file uploader seems like a unicorn. Uppy seems like the real deal: configurable, easy to implement, elegant UI, server control, open source, modern, modular, and more -- you can't ask for much else!

Recent Features

  • By
    Write Better JavaScript with Promises

    You've probably heard the talk around the water cooler about how promises are the future. All of the cool kids are using them, but you don't see what makes them so special. Can't you just use a callback? What's the big deal? In this article, we'll...

  • By
    Chris Coyier&#8217;s Favorite CodePen Demos

    David asked me if I'd be up for a guest post picking out some of my favorite Pens from CodePen. A daunting task! There are so many! I managed to pick a few though that have blown me away over the past few months. If you...

Incredible Demos

  • By
    Translate Content with the Google Translate API and JavaScript

    Note:  For this tutorial, I'm using version1 of the Google Translate API.  A newer REST-based version is available. In an ideal world, all websites would have a feature that allowed the user to translate a website into their native language (or even more ideally, translation would be...

  • By
    Generate Dojo GFX Drawings from SVG Files

    One of the most awesome parts of the Dojo / Dijit / DojoX family is the amazing GFX library.  GFX lives within the dojox.gfx namespace and provides the foundation of Dojo's charting, drawing, and sketch libraries.  GFX allows you to create vector graphics (SVG, VML...

Discussion

  1. Seems very compelling. I’ve been using PLUpload for the last 5+ years and it’s been great. But, it has some timing problems in that it initializes asynchronously, which can lead to bugs that I can’t fix easily. I’ll take a look at Uppy to see how it looks.

  2. Warren Churulich

    Nice article. I appreciate the working demos.
    I’d love to see a working demo with instructions for uploading directly to AWS S3.

  3. How to create those companion endpoint in the same PHP server rather than using Node. Any ideas will be appreciated!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!