Uppy: 1.0 Roadmap and React compatibility

Created on 14 Aug 2016  Âˇ  48Comments  Âˇ  Source: transloadit/uppy

Hi folks! The project looks great, and like others, I'm quite looking forward to it.

Since the readme says _don't use in production yet_, I am wondering if I could get a sense of what are the big parts remaining to make it production-usable in your view? And if you had a sense of how far out that might be?

Thank you for open-sourcing this!

PS. I have gone through the Changelog/Roadmap document which gives details about the tasks but didn't answer my question, so hence the issue created

Help Wanted 💬 Discussion

Most helpful comment

I'm pretty much on the same wavelength as @oyeanuj.

I'm also doing things in a react environment but I don't think it's hard to wrap things like the upload SDK in a react component because of the various events that get emitted so I don't need to wait for a React plugin or anything. My main concern, as @oyeanuj touched on, would be to have basic resumable upload functionality and a way to upload directly to TransloadIt. I found Uppy via TransloadIt, so that is my main need in using this library even though I see greater things in Uppy's future. Oauth, react-native, Instagram, webcam, etc would are secondary in my mind.

Another thing I'd also like is that I will be able to use Uppy without having any view stuff included. I just need the raw data and events from the upload process and I'll take care of any view/html myself. Anything else is bloat to me and would be better served as an extra wrapper/component to make things easier for new users to get started with Uppy.

With the current SDK, my initial thought was to load jQuery and the SDK asynchronously before I allow users to upload anything but even then, it assumed way too many view/i18n things for my taste so I just made a port which might work for someone working in a similar environment. I should mention that I don't plan on maintaining this. It is just a workaround for myself until I can use Uppy to upload to TransloadIt 😏

All 48 comments

Hi @oyeanuj, I appreciate the interest and kind words! I'm afraid though that we're not giving out ETAs as we don't have a fixed plan for Uppy other than our design goals and monthly release cycle. We feel it would be hurtful to try to think of everything thing/detail that uppy will become once, and then not deviate from that anymore. Rather, we brainstorm every week and sometimes revert previous decisions, causing a very unpredictable / non-linear flow.
Giving out dates or estimations is hence not realistic, and only going to lead to disappointment.

I'm sorry I can't be more helpful, I realize this is not the answer you were looking for. I can say that we're 100% committed to pushing out monthly releases though so it will be easy for you to track progress and see if Uppy is getting close to being fit for your usecase.

Question for you and @upq: what would be features/things that Uppy would need to add before you could use it in your project?

Refs #104

Actually, I think I can do a better job at answering this part of your question:

what are the big parts remaining to make it production-usable in your view?

Without being exhaustive, here are a few big things still on our plate that I can think of (without having consulted with the team yet so anyone, feel free to add to this or correct me)

  • Smoother oauth (and a example googe/instagram/etc accounts so visitors can more easily testdrive examples without being concerned about us stealing their data)
  • Deploy boilerplate for uppy-server so people can deploy and scale it onto aws lambda via a single apex.run command. Boilerplate for other environments is offered via Frey already
  • Dashboard overhaul (so that dragdrop is not a plugin, but incorporated into the working area, and uploading/tagging/modification all are too) Artur is in the middle of doing this heartsurgery
  • Webcam plugin (Harry is in the middle of this one)
  • Instagram plugin
  • Dropbox plugin
  • Encoding endpoints - after the upload. Advanced modifications such as labeling media or rotating video will be outsourced to this. uppy should be fully aware of this, track progress, and provide visual feedback
  • Uppy-server uploading - will need to coordinate with Uppy to directly post large (e.g.) Dropbox files to the uploading endpoint. This needs a lot of testing/hardening to get solid
  • Themes
  • React (Native) compatibility (a plan for this has just been finalized)

@kvz Thank you for the detailed answer, it answers what I was looking for :) I totally understand the part about not providing an ETA, I am not good at sticking to them myself. But it helps to understand the feature-set that you consider essential.

My only suggestion, would be around prioritizing features that help people get started over some of the other fancier plugins. In that spirit, I would love to see these ones in your list prioritized higher than others -

  • Examples including smoother o-auth one you mentioned above.
  • React compatibility (obviously, biased here)
  • Encoding endpoints/Uppy-server uploading
  • Boilerplates for uppy-server

Two more things that I'd add -

  • Since a lot of people might be coming from transloadit, examples of integration with transloadit (and/or with other such libraries).
  • Mobile plans? Maybe this is more of a question of compatibility plans with mobile browsers.

Given the plugin architecture, Instagram, Dropbox, etc can easily be added by users later. Having boilerplates, React-compatibility, examples, etc will help a bunch in getting more people started.

My very biased two cents based on my situation, feel free to disregard them :)

Thank you for your work on this!

I totally agree with @oyeanuj , I think the two points he added are a priority higher than plugins and themes and even the react native integeration.

Im in the same situation as him too and I got here from transloadit and I feel that most people who gets to uppy are coming for the same reason.

@kvz Btw, I am curious if in your above comment, were you implying compatibility with both react and react native? Or is it already compatible with React and React Native was your point?

Thanks for the feedback @upq & @oyeanuj

Or is it already compatible with React

Not just yet, but the planning for this is nearing finalization

Am I correct in summarizing/simplifying your feedback as:

  • get it to work with both React & Transloadit asap so you can ditch the jquery-sdk and start testdriving with Uppy already, plugins to for different sources are less a priority than dragdrop/local file select (?)

If so, I'll discuss this with the team in our call today, and see if we can prioritize things that way. No promises, we care more about doing :dog: right, than fast. One concern is, different file sources (e.g. webcam) may very well cause changes in the core, so if you are going to use Uppy early, be sure to pin versions and test upgrades inside your app very carefully..

@kvz thats correct,

different file sources (e.g. webcam) may very well cause changes in the core

Shouldnt those be optional to add by the developer or something or am I understanding that wrong? Im not sure what the plans are you maybe doing this already but having it light and clean (fewer features) and everything else adds as a plugin or something (including file sources other than DND and Local file select) is better IMO.

Having a very basic _fully functional uploading client that is highly extensible_ , delaying the other plugins development is better anyways because who knows , if you finish working on the core the community may already start working on the plugins and different inputs.

@upq, yeah everything is a plugin and will be optional. It's just that by creating different types of plugins, the core design changes, as we suddenly find we want to support e.g. labeling of videos, but only after the webcam has finished recording, and that might force adding options / changing design of the core. Ideally we don't have a lot of people using Uppy while the core still undergoes multiple of these backwards breaking design changes. Adding more crazy plugins right now, helps us to create a flexible core that can remain stable for a long time.

@kvz Yes, I think your summary is accurate. I'd just add 'examples and boilerplates' to that list. As for the core changes, the risks one takes for being an early adopter.. :)

I'm pretty much on the same wavelength as @oyeanuj.

I'm also doing things in a react environment but I don't think it's hard to wrap things like the upload SDK in a react component because of the various events that get emitted so I don't need to wait for a React plugin or anything. My main concern, as @oyeanuj touched on, would be to have basic resumable upload functionality and a way to upload directly to TransloadIt. I found Uppy via TransloadIt, so that is my main need in using this library even though I see greater things in Uppy's future. Oauth, react-native, Instagram, webcam, etc would are secondary in my mind.

Another thing I'd also like is that I will be able to use Uppy without having any view stuff included. I just need the raw data and events from the upload process and I'll take care of any view/html myself. Anything else is bloat to me and would be better served as an extra wrapper/component to make things easier for new users to get started with Uppy.

With the current SDK, my initial thought was to load jQuery and the SDK asynchronously before I allow users to upload anything but even then, it assumed way too many view/i18n things for my taste so I just made a port which might work for someone working in a similar environment. I should mention that I don't plan on maintaining this. It is just a workaround for myself until I can use Uppy to upload to TransloadIt 😏

Thanks @okcoker!

So roughly the same priorities as @oyeanuj and @upq, only a lower prio for React compatibility in your case it would seem.

Another thing I'd also like is that I will be able to use Uppy without having any view stuff included.

This is a very good point, also discussed in our call today, and we're planning this for the next release. So not the one of August 26th, but the month after that (v0.10.0).

I just made a port

Wow this looks really good - too bad you won't be maintaining this :D Something that may still interest you though, is that a v3 of the jQuery SDK is https://github.com/transloadit/jquery-sdk/pull/49 being worked on alongside of Uppy, as a means to offer resumability and a somewhat easier to maintain codebase (it adds bower, and for instances sourced uuid as an external dependency, but we're not going out of our way) just so that existing customers will be able to get tus-enabled uploads quickly without having to switch over to Uppy just yet.

Also - sorry to have kept you waiting on jquery-less Transloadit browser integrations, we'll work hard to fix this!

@oyeanuj, @upq, @okcoker, thank you for your feedback! We are listening and taking all that into account when discussing roadmap and future releases, feedback helps a lot.

Not that it directly addresses the aforementioned issues, but I thought some you might be interested to find out about @arturi's latest blogpost on 0.8.0, that we pushed out recently http://uppy.io/blog/2016/08/0.8.0/

wow blogpost sounds awesome and may attract even more people :-)

Just one topic which imho is also important for v1.0:
the possibility to restrict uploads in two basic points (small part of "possibility to restrict upload" #69)

  • to a/some special filetype(s)
  • number of files

There are several major usecases where this is quite important...

always used example for this (no I'm not in this business, but everybody can imagine how this works):
a photo printing shop:
only could work with *.jpeg, *.jpg
and wants to accept for a four image poster only 4 images.

that restricting filetype is probably important for many people could be proofed by a short google search for
upload restrict filetype
direct: https://www.google.de/#q=upload+restrict+filetype
=> there are about 400.000 results talking about this topic

Thanks for the feedback @okcoker.

Another thing I'd also like is that I will be able to use Uppy without having any view stuff included. I just need the raw data and events from the upload process and I'll take care of any view/html myself. Anything else is bloat to me and would be better served as an extra wrapper/component to make things easier for new users to get started with Uppy.

As someone who works with React a lot, I've been a proponent of heading in this direction. The most razor thin solution for your needs may look something like this, where component-App.js would be what you wrote in your React app: https://gist.github.com/hedgerh/3a553a45e10d832628e125c60ba96491

In this solution:

  • There is no Uppy object/core.
  • You are provided barebones plugins.
  • You call plugin methods directly, and they return whatever data you need.
  • You manage your own state.

Would that be an ideal solution for you? Abstractions could maybe be made with higher order components or container components, although I don't know what they'd look like exactly just yet.

Anyway, I'd love to hear your thoughts about the solution I proposed.

@hedgerh This is definitely closer to what I'd be looking for. I'd think that the Uploader component you have _would_ be the core. It seems you have it being imported as if it were a separate plugin alongside GoogleDrive? The core in my mind is the uploader which emits different events based on the flow/progress of the upload.

I was thinking more like:

import Uploader, { GoogleDrive } from 'uppy';

or since the plugins are in a separate folder, maybe something like:

import Uploader from 'uppy';
import GoogleDrive from 'uppy/plugins/GoogleDrive';

// or a separate installable package completely although I'd prefer the above over 
// this one so we only need to `npm i uppy` for all our upload needs
import GoogleDrive from 'uppy-plugin-googledrive';

Wrapping the uploader or it's plugins in a react component would just be a matter of creating an instance of the Uploader within the component and calling prop methods for each event just like you have for <GoogleDriveBrowser /> with onFileSelect.

Sorry, I used a generic name to describe an uploader plugin. We actually have multiple uploader plugins. For instance, the Tus10 plugin is an uploader plugin for uploading with the Tus protocol. So pretend the Uploader in my example is Tus10 instead.

uploader plugins could extend EventEmitter so that you can subscribe to progress/flow events. It would look something like:

import { Tus10, GoogleDrive } from 'uppy'
const uploader = new Tus10({/* options */})

class App extends Component {
  constructor() {
    super()
  }

  componentDidMount() {
    uploader.on('progress', this.handleProgress)
  }

  startUpload() {
    uploader.start(this.state.files)
  }
}

Aside from that, I'm not sure what purpose a "core" module, or default module for uppy, as you showed in your first line of code, would serve in this kind of architecture.

Regarding separating plugins into their own modules, there wouldn't be too many plugins in this architecture, and they would all be very small. I should also note that there would ideally not be individual plugins for all of the third party storage providers (Google Drive, Dropbox, Instagram, etc.). I'm hoping to create a generic Provider plugin that could be used as such:

import {Provider, Tus10} from 'uppy'
const googleDrive = new Provider({ provider: 'google' })
const uploader = new Tus10({ target: ... })

Ah okay! I think we are on the same page 👍

As far as the plugins, an easy way to include them such as the Provider method you mentioned sounds fine. It reminds me a little of nodemailer's "well-known" functionality.

Alright, I want to lay out a proposal.

So the limited API (.use) of Uppy and encapsulation of plugins inside the Uppy core adds a lot of constraints when trying to solve certain problems. It also requires a lot of extra code and methods (install, focus, etc.) to make it all work. It's great because the API is very straightforward and simple for basic/beginner uses, but it adds way too much complexity when trying to do things like de-couple rendering from Uppy and get it to work with React.

I've whittled away every non-essential feature and think I've come up with a razor thin library. It contains no core. I realized that it only makes things messy and isn't necessary if you have direct access to all of the plugins APIs. It contains no UI and only a handful of plugins that are whittled down to their bare functionality.

The library is used by importing plugins and calling each one's methods directly. The methods take parameters, perform a very specific task, then return the resulting data. The developer then decides what to do with that data.

Example plugins:

Provider

Generic plugin for interfacing with Uppy Server and third party storage providers. Takes a provider string as an option to specify between Google Drive/Instagram/Dropbox/etc. Has only 3 methods:

  • auth: checks auth status, returns auth status
  • list: fetches list of files from provider, returns array of files
  • logout: logs user out of provider, returns logout success status

Tus10:

Tus10 and other uploader plugins handle various upload protocols. All uploader plugins extend EventEmitter so that developers can subscribe to progress/flow events. Uploader plugins have 3 methods:

  • start: takes an array of files and starts uploading them
  • upload: handles local uploads
  • uploadRemote: handles remote uploads

We can then build abstractions/wrappers/implementations on top of that foundation, including our current implementation of the basic Uppy lib. We can also easily make React abstractions for it.

Another thing I'd also like is that I will be able to use Uppy without having any view stuff included. I just need the raw data and events from the upload process and I'll take care of any view/html myself. Anything else is bloat to me and would be better served as an extra wrapper/component to make things easier for new users to get started with Uppy.

This is roughly how I envisioned that. Can work with or without React, if you don’t need some of Uppy’s functionality, just call methods directly:

import Uppy from 'uppy'
import Tus from 'uppy-tus'

const uppy = new Uppy({
  onProgress: function (progress) {
    console.log(`progress for ${progress.fileName} is ${progress.percentage}`)
  },
  onSuccess: function () {
    console.log('all files have been uploaded')
  }
})
uppy.use(Tus, {endpoint: 'http://example.com'})

const fileInput = document.querySelector('.myInput')
const uploadBtn = document.querySelector('.uploadBtn')

fileInput.addEventListener('change', (ev) => {
  const files = ev.target.files
  files.forEach((file) => {
    uppy.addFile(file)
  })
})

uploadBtn.addEventListener('click', () => {
  uppy.upload()
})

API would include: setMeta(fileID, meta), removeFile(fileID), getFile(fileID) — something like that. Could be a whole event-based system with: uppy.on('add-file', callback), uppy.on('file-uploaded', callback), uppy.on('all-files-uploaded', callback), uppy.emit('addFile', file).

My previous comment is not about “my approach is better” at all, it’s just how I’ve been picturing it for a while. And there is some middle ground between what we all are proposing.

I definitely understand the idea of decoupling everything and I don’t like how plugins currently call this.core.i18n('string') or this.core.log(string).

However, Harry’s component-App.js is kind of a core replacement, right? But one that the user has to write manually, even if he just wants to upload two files, he’ll have to repeat some or all of the boilerplate. And we loose the ability to pick which plugins to use when you are not going through a build-step. Or are you proposing to solve this with some sort of optional preset wrapper?

What core currently does for us is serves as a source of truth for all the plugins, selected files and progress events. It also normalizes things for you: when you call addFile it adds basic metadata to it, sets proper filetype, generates image thumbnail (that some users might not need, yes, but then those who do will have to import a separate lib and call generateThumbnail()?) isRemote, that any plugin can then use and check if (file.isRemote) doThis().

@hedgerh , in your proposal, is component-App.js the way to use Uppy for most users you think? Instead of the current way of the current way

Again, I’m all for the change, I just have ideas and concerns that I want to discuss.

So now I'm confused because I feel as if I agree with you both but it seems like @arturi doesn't completely agree with @hedgerh.

To make things easier, let's just ignore the React part. A simple way of using Uppy as @arturi mentioned will make it easier for react component wrappers to be developed down the road. It is the simplicity that @arturi showed is what I'd personally be looking for. uppy.use and "Provider" mentioned by @hedgerh are the same thing to me (correct me if I'm wrong) since they just add 3rd party (or 1st and 2nd party) integration.

I think Core, as is, is pretty lean. The only part I think is a bit questionable is the thumbnail generation since it assumes a width of 200. I think I'd much rather see this function use image.naturalWidth and have the consumer do with it what they want, or it be an uppy option. Maybe something like:

export function createImageThumbnail (imgURL, width = 200) {
  return new Promise((resolve, reject) => {
    var img = new Image()
    img.addEventListener('load', () => {
      const newImageWidth = Math.max(width, img.naturalWidth)
      const newImageHeight = getProportionalImageHeight(img, newImageWidth)
      // ...

As the code is now, I don't see myself doing import uppy from 'uppy' since it includes all the works. This isn't a problem assuming the finished project also provides the component files. I would want to be able to do something like:

import UppyCore from 'uppy/src/core';
import Tus from 'uppy/src/plugins/Tus10';

const uppy = new UppyCore({
  onProgress: function (progress) {
    console.log(`progress for ${progress.fileName} is ${progress.percentage}`)
  },
  onSuccess: function () {
    console.log('all files have been uploaded')
  }
})
uppy.use(Tus, {endpoint: 'http://example.com'})

// ...rest of @arturi's code

However, Harry’s component-App.js is kind of a core replacement, right? But one that the user has to write manually, even if he just wants to upload two files, he’ll have to repeat some or all of the boilerplate.

No, it's essentially the React version of what you posted above. The only difference is that the user in that example is responsible for handling the state.

You can easily abstract that away, though. Check this out. I took all of the Uppy functionality from my previous example and put it in an UppyContainer component. Now the functionality can easily be reused in any component or application. UppyContainer is something we would provide to React users as an abstraction.

Take a look at App.js (formerly component-App) now. That is all users would need to write. https://gist.github.com/hedgerh/3170e2caa77444dc1e0dca57be713f01

In regards to the solution that you presented, I'm totally on board for abstractions/wrappers like that do things like handle state and reduce boilerplate. The solution I'm suggesting can be the foundation/building blocks for building wrappers and libraries for different environments, or even just a flexible solution for someone whose use case needs Uppy to be as un-opinionated as possible.

We should definitely do both, then have the really basic Uppy that's super opinionated for beginners/basic use cases.

PS.

And we loose the ability to pick which plugins to use when you are not going through a build-step.
Can you clarify what you mean by this?

Take a look at App.js (formerly component-App) now. That is all users would need to write.

How would a user choose that he wants GoogleDrive + Webcam + Instagram or Webcam + DragDrop? In your example they are sort of embedded in UppyContainer. How can he choose for those to be rendered in a Dashboard, like we currently have? In React it probably means Dashboard should be a wrapper component like your UppyContainer, but what about without React?

Basically, what would your examples look like without React?

Can we say that what we want essentially is: every plugin exposes some methods/callbacks that we can call directly, or that get called once certain events happen? But then we’ll create a wrapper, like UppyContainer, that does what core currently does — instead of having to call upload on both Tus and Multipart, you’ll call it on core, which will then somehow manually call it on each of the plugins. Currently this is solved with events — each plugin is listening to start-upload event in core, it’s the glue that ties them together. With UppyContainer example it’s not dynamic — you are hardcoding plugins and the way methods are called into it.

Hi guys,

I read all the conversation and as someone who wants to use Uppy with React (I am building a File Browser and the user will be able to upload files) I just wanted to share my thoughts as well.

I feel that the following two cases can be covered when it comes to React:

1. A higher order component which will work out of the box and will basically wrap the Dashboard. You will be able to pass props to it such as which plugins to load, callbacks for events such as onProgress and basically anything useful to someone who wants to use the component.

2. The higher order component will obviously not cover everybody, specially if they want their own customized view so a lower level example, which will be basically a guideline, would be nice to have. For example lets say someone wants to use the Drag n Drop plugin with Tus and to implement handlers for the exposed events in order e.g. to update his view, or a progress bar or the state or anything at all basically.

In general by reading the whole discussion I think you are on track to getting somewhere and I feel that if the two cases above are covered then everybody will be happy :)

I am in the process of trying to implement a React component which basically follows the example from here so I can get a better grasp of the underlying API and be able to provide more feedback.

Update. We are still in the process of figuring out how Uppy would work across frameworks. We’ve had some more discussions in Slack, so I decided to add points here too. Basically it’s about: 1. “Maybe current core is redundant” and 2. if someone uses Redux, Uppy shouldn’t have its own inner state, which is currently in core.

Harry’s made an example comparison — Core vs. No Core: https://gist.github.com/hedgerh/9ad63f467ce816246044f3f9e83bd7e7.

Ok, so what Core currently does for us:

  1. tracks online/offline state (should set flag in capabilities or something), checks for and sets capabilities flags like resumable: true, touch: true, dragdrop: true that could possibly be used by all plugins.
  2. Normalizes files, so when you do uppy.addFile(blob) it will generate preview/thumbnail for that file (if its an image), try to figure out file type by extension if mime is missing, say noname if name is missing and so on.
  3. Calculates total progress for all files that are currently being uploaded.
  4. Brings unity (questionable): you don’t have to know how many uploaders are currently used or what they are called (after uppy is initialised), you just say uppy.upload(files) and it uploads, using whatever. Or you can say uppy.info('message!') and it will display that message somehow, whichever way (or multiple ways) is set up, or it will ignore it if no Informers are present.
  5. Logs stuff to console only if user specified debug: true, so can be silent in production.
  6. Can add metadata to files after they have been added, by way of uppy.addMeta({resize: 1200})

So basically it structures things and gives users and plugin authors a framework and set of standards like “file object should look like this”, “metadata should be added like that and shaped like this”. Do you think this could all not turn into a mess if we have it as separate utils + documentation, and no single lib which glues it all together?

With current state of affairs plugins like Tus, Multipart and Metadata can work in Uppy + React right away, and only views like DragDrop or Dashboard have to be re-implemented (that is if we don’t just go JSX route or people are not using hyperx instead of JSX in React, which is possible, actually). But when someone does uppy.addFile(blob) we can be sure that the file will be processed like we need it in order to work with uppy-server. And when he does uppy.getCapabilities().resumable he can decide whether to show pause button or not. This normalisation could live somewhere else, I suppose, but where? Or should it just become pieces that expose their thing, like getCapabilities() is a util and normalizeFile() is a util, and then you manually use it and glue to your own state or components.

Looking at other libs: Moment has plugins and holds locale info and some settings it its “state”. Codemirror React: instantiates a “normal” Coremirror instance and sets it to this.codemirror and then outputs stuff from it in render(). The latter is actually how I would ideally see Uppy working, but I understand our case might be different.

Also looking through https://github.com/FineUploader/react-fine-uploader — closest to out project.

https://github.com/FineUploader/react-fine-uploader/blob/master/src/wrappers/traditional.js — creates higher-level wrapper (like UppyContainer) that instantiates core, then things like uploader (core) and fileID are passed as props to smaller components: https://github.com/FineUploader/react-fine-uploader/blob/master/src/components/filename.jsx, and then used like this:

this.state = {
  filename: props.uploader.methods.getName(props.id)
}

Going to respond to these asynchronously, as I'm still thinking over some of the points, but starting here:

Looking at other libs: Moment has plugins and holds locale info and some settings it its “state”. Codemirror React: instantiates a “normal” Coremirror instance and sets it to this.codemirror and then outputs stuff from it in render(). The latter is actually how I would ideally see Uppy working, but I understand our case might be different.

Moment isn't really applicable to our use case. Moment will also mostly be used in a stateless way in react. With regards to moment's state, such as locale, its a minor cost of doing business with moment that isn't something that should dictate our API approach. A couple of props checks in componentWillMount and componentWillReceiveProps can sort those out. Also, plugins are largely irrelevant for moment since we are mainly concerned with what they output. we dont really need to track some state that a plugin brings to the table.

Moment React Example:
http://codepen.io/hedgerh/pen/xEOpKx

As for Codemirror, the react-codemirror is a retrofitting to get it to work with react. It uses an invisible input element to just track the value thats being entered into codemirror. furthermore, codemirror is virtually only a UI component. it would require a huge reimplementation to get it to work not-hacky in React.


I just ran tests to see how much bloat react-filepicker, react-fine-uploader, UppyContainer with uppy-base, and finally UppyContainer with importing {Core} fromuppyincur onto a react project after minification of the final project bundle. I usedreact-hot-boilerplate` as the base project.

| Sample | Project Output (min + gzipped) |
| --- | --- |
| React Hot Boilerplate | 74kb |
| RHB w/ UppyContainer + Uppy Base | 85kb |
| RHB w/ React Filepicker | 99kb |
| RHB w/ React Fine Uploader | 113kb |
| RHB w/ UppyContainer + Uppy Base + Uppy Core | 153kb |

There may be ways to optimize down Uppy's footprint, but I think looking at react-fine-uploader and react-filepicker's results, it can kinda be seen how easy it is to add unnecessary bloat to a project by just importing the core of a library. Food for thought, more than anything. Going to work on a response to your other points now.

Discussion continued:

Artur:

If we used Uppy the way I showed in my codepen example (with some alterations and refactors), the same thing could be used anywhere. Only problem is it stores things internally, but I would say its ok since it is a library that does stuff for you, so it manages files for you, they are not part of your application state.

And then if you wanted to re-implement things and only use parts, you could use uppy-base and built your own ReactUppy. Which you are trying to do, it seems.

We are circling back, because we jumped over the question why this is so bad http://codepen.io/arturi/pen/yaZEzz?editors=0010. I only remember no time travel and no single source of truth.

What I don’t like is trying to optimise mostly for React, cause that’s what’s cool and used today.
Everybody seems to be building apps with React/Redux, so we are like “lets make it very good with those”. And then what about Vue and Angular or something else?

Harry:

Your codepen example isnt set up so that the user can display a list of added files as they are being added. you’d need to add something like this.uppy.on('add-file', (file) => { this.setState({ files: this.state.files.concat([file]) }) }).

Then you’re just managing state in two different places and then if the user is using his own redux store, its a mess if uppy is internally working off its own state.

Hi @arturi @kvz! Just wanted to loop back in since I was about to start my work on file upload finally (after like 3.5 months later!). Are there any updates on how to proceed on integrating it in a React-Redux environment? Or should I hang on tight to Transloadit with a custom React implementation for now?

@hedgerh Did you find a happy place with Uppy-React library? Any thoughts on the best way forward for now?

PS. Is there a recommended way/library to use React + Transloadit if that is the way you recommend?

Hey, @oyeanuj! Sorry for the delay.

We are still in the process of finding the optimal solution, but the gist of it is: Uppy itself can work with any view lib/framework right now, and we’ll do more to improve that in the future. So React version that we’ll provide will either be a “black box” component that wraps an empty div and Uppy Dashboard is mounted into it, or we’ll add a full JSX-version later. Either way, it can already be used like this:

const Uppy = require('uppy/lib/core')
const Tus = require('uppy/lib/plugins/tus10')

const uppy = Uppy().use(Tus, {endpoint: 'http://master.tus.io/files/'})
uppy.run()
uppy.addFile(myFile)
uppy.startUpload()

Then you subscribe to events and update your React/Redux how you see fit.

Or should I hang on tight to Transloadit with a custom React implementation for now?

Yes, that would be a better option for now, since Transloadit support for Uppy is not there yet.

@arturi Thank you for the detailed response, appreciate it.

One quick follow-up, given your last comment - since the transloadit support isn't there yet and hanging on to Transloadit is advised, is there any react-transloadit component/implementation that you'd recommend? I didn't find anything in the docs (maybe, I missed it) but I'd love to check out a 'blessed' integration, if any..

Hi @oyeanuj, we unfortunately do not have an 'official' way to do React ❤️ Transloadit yet. There is this community project https://github.com/danielmahon/react-transloadit by @danielmahon that seems to work though - you might try it out.

If all else fails we do have a well document HTTP API and xhr examples so carving out your own could also work - but depending on your timeframe it might be better to wait on us integrating Transloadit support into Uppy (if you can live with it being a black box for starters)

Hey @oyeanuj I have managed to wrap the existing system within a custom FileUploader React component that I made. So far it looks to work pretty well. It just wraps and delegates at the moment. :)

Does anyone know of ways to restrict file types? Is this in the roadmap or a "hidden" feature? 😀

A good explanation can be seen here StackOverflow

@ctrlplusb Good to know! Do you have an example somewhere of the integration (and/or is it part of react-universally)?

@ctrlplusb

Does anyone know of ways to restrict file types? Is this in the roadmap or a "hidden" feature?

Are you talking about Uppy? Yes, its in the roadmap! PRs welcome :)

@hedgerh @okcoker I am curious where did you guys end up with how to use uppy? Since the React components aren't available, I was also leaning towards using the core (like how @hedgerh) suggested in a barebones manner (de-coupled from the Uppy UI) and plug it into my own UI. So, I would love to know if you guys had any luck with that?

@arturi @kvz I'm curious if there is a WIP react component (or planned API) that one could look at? Or alternatively, what would be the best way to use Uppy without necessarily the UI part of it? FWIW, I'd like to use just the basic upload functionality (without 3rd party services).

I'm curious if there is a WIP react component

@goto-bus-stop has been doing some recent experimentations, but I'm not sure what the status of that is

@oyeanuj The current React experiments are in #170, but they've been on hold until at least the next release (scheduled for next Friday). They're going to be React-y wrappers around the existing Uppy UI plugins, so they may not quite be what you're looking for.

As for the UI-less use case, the 0.16 release next Friday will contain an upload() method on the Core instance that can be used to trigger an upload programmatically and wait for it to complete. That would look something like this:

const UppyCore = require('uppy/lib/core')
const Tus10 = require('uppy/lib/plugins/Tus10')
const uppy = new UppyCore()
uppy.use(Tus10, { endpoint: 'https://master.tus.io' }) // or Multipart...
uppy.run()

function addAFile() {
  uppy.addFile({
    name: 'my-file.txt',
    // an instance of https://mdn.io/blob containing the file contents
    // for example, a File instance from the `.files` property of `<input type="file">`
    data: someBlob,
    // optional MIME type
    type: 'text/plain',
  })
}

function doUpload() {
  return uppy.upload().then(() => {
    // upload done
  }).catch((err) => {
    // something went wrong!
  })
}

Of course with the usual v0.x warning that this may change in any minor release :)

@goto-bus-stop Thank you for the detailed comment! A follow-up question: in this UI-less case that you mentioned above, would I still be able to tap in to other events from Core (upload-progress, upload-success), Metadata and Transloadit plugins?

In other words, are there events or plugins or core features that I wouldn't be able to use (apart from any UI artefacts)?

in this UI-less case that you mentioned above, would I still be able to tap in to other events from

Yes, everything should be available through events: core:upload-success, core:error, transloadit:result and the like. We’ll update the docs with more + plus the recent changes to these APIs. Metadata too, actually, like this: uppy.emit('core:update-meta', meta, fileID). But, as Renee mentioned, this API is subject to changes, as we are trying to figure out what works best.

Remote provider plugins, like GoogleDrive and Dropbox, and also some local like Webcam, currently don’t expose an easy to use API for usage without the UI. I think they should, so you can get file list from Google Drive and then add file too, all programmatically, so that’s something we should put on TODO, what do you think @ifedapoolarewaju @goto-bus-stop?

I've been chatting with @oyeanuj to see if I could help him find a solution to using uppy with react/redux.

Remote provider plugins, like GoogleDrive and Dropbox, and also some local like Webcam, currently don’t expose an easy to use API for usage without the UI.

@arturi https://github.com/transloadit/uppy/blob/master/src/uppy-base/src/plugins/Provider.js

You can just trigger those when the user emits events, if you're exposing the bus/emitter.

As for the UI-less use case, the 0.16 release next Friday will contain an upload() method on the Core instance that can be used to trigger an upload programmatically and wait for it to complete.

Why not allow upload to optionally accept a files parameter, so React/Redux users can manage their own file state? That, with access to plugin APIs, should make legitimate React usage doable.

You can just trigger those when the user emits events

@hedgerh Yes, correct! Thanks. But this won’t let you select files, for example, right? Just auth, list, logout.

Why not allow upload to optionally accept a files parameter, so React/Redux users can manage their own file state? That, with access to plugin APIs, should make legitimate React usage doable.

This brings up the issue with files having certain shape that we expect in uploader plugins, and status plugins, and all around Uppy really. That’s why, I think, adding each file with uppy.addFile() is necessary, and shouldn’t be that complicated? Yes, black box 📦 but you can look into it, and subscribe to events to mirror internal state changes to your Redux state.

Thoughts, @goto-bus-stop?

We have React components for Uppy now, basic Redux support: https://uppy.io/blog/2017/10/0.20/, and swappable state managers (so you can plug Uppy into your Redux app) coming in this release. Thank you everybody for you feedback! Closing this, feel free to open new issues to discuss further.

Was this page helpful?
0 / 5 - 0 ratings