The last word on uploading files.
"Uppy is a sleek, modular file uploader that integrates seemlessly with any framework. It's fast, easy to use and let's you worry about more important problems than building a file uploader.
- capabilities is mentioned before explained
- capabilities could also be confused with the crypto equivalent - different meaning tho it's cool probably
- capabilities also seem enumerable - enumerating them is probably worth it
- addFile() mentions plugin types - shoulda been mentioned sooner
- consider using hemingway
- or run this:
#!/bin/zsh
where alex >/dev/null
[ $? -eq 0 ] || npm i -g alex
where write-good >/dev/null
[ $? -eq 0 ] || npm i -g write-good
where aspell >/dev/null
[ $? -eq 0 ] || brew install aspell
printf '[aspell] running\n'
aspell check "$1"
printf '[write-good] running\n'
write-good "$1"
printf '[alex] running\n'
alex "$1"
- file size cuts rely on dead code elimination rather than specific imports
- terminology isn't always clear
- mash up of different API types (event emitter, external state, prototypes)
- not sure how to create new plugins
- import with
/
is not great for file sizes; not necessarily an issue with rollup but that's not for everyone new
can be unwieldy - useif (!(this insteanceof Foo))
Core
is an odd name; the thing being used is theuppy
file transfer framework; all instances ofCore
in code will look odd in the light of a real application I reckon- The
core
setup discourages third party integrations; they'd be imported differenty which leaves others to feel a bit lackluster - feels use of prototypes is leaking into API design - it's an implementation detail, really
- found it unintuitive they plugins were called by uppy rather than initialized by the user
- found it unintuitive args are passed later
- feels technical implementation is leaking into plugin design
- using closures is fine and given it's not in the hot path it's fast enough
- if there's only a single mandatory argument, it makes sense to make it the
first arg passed
- breaks the current single opts arg passing paradigm
- makes for a more intuitive API
- again: not hot path so it's all cool
state [patch] -> uppy -> state [complete]
const Progress = require('uppy/progress')
const dnd = require('uppy/drag-and-drop')
const tus10 = require('uppy/tus10')
const uppy = require('uppy')
const upload = uppy()
upload.use(dnd('#drop-target'))
upload.use(function (state, cb) {
const newState = changeState
cb(null, newState)
})
upload.use(Progress({ appendChild: 'body' }))
app.model({
namespace: 'uppy',
reducers: {
update: function(state, data) {
return data
},
addFile: function (state, data) {
return state.files.push(data)
}
}
state: {}
})
function (state, prev, send) {
const opts = { thumbnails: false }
const el = upload(opts, (err, state) => {
if (err) throw err
send('update', state)
})
document.body.appendChild(el)
}
el.set({ my: 'state' })
- so
.use()
would detect the.plugin
value on any given value passed in and use that as a plugin - allows for using a result as both a plugin and DOM render target without needing to introduce more keywords. - Just pass it in; similar to how pull-stream does it - lil bit of polymorphism is cool
We're not Java - heavy taxonomy is not cool. Uppy should be allowed to modify state in whichever way it wants. When all updates are done, callback is called with new state which can be used by any other framework if desired.
Default state:
{ files: [] }
Internal:
{ files: [ { file: File, thumbnail: Image }] }
// or
{ files: [], thumbnails: { filename: Image } }
- getState - remove and make part of callback
- setState - rename to set(), partial setting of vars is cool
- updateAll() - if state is flushed on each set, this is not needed
- updateMeta() - make files part of state
- addFile() - just push to files array OR perhaps we do need a special file adding API - it could make sense; matter of taste and what a file looks like internally
- capabilities - not needed; just read out state
- log - not needed; hooks that tie into lifecycle events might be more interesting - any more debuggint than that feels off
- .on(), .emit(), .emitter - not needed; use state
uppy.set({ files: [ File ] })
- Drag and Drop & Progressbar are inconsistent
- drag and drop adds functionality to a selector
- progress injects an element into the selector
Yeah I think that sounds good - from what you're saying that leads to a less
coupled architecture which is a good thing.
In the example you posted, the contents of the returned
el
can be updated byuppy
without any trouble, causing the DOM to be updated in return. You'reright in that it does complicate the views a little, but I feel that's the
nature of how unidirectional updates work; if you provide default props the
user can mount into their global state things become easier tho.
Yup, I feel using proper delimited names this would work well; in essence it's
the same idea as a central event bus, but using a different (more convenient)
API
I think that mounting in several places means you've got different elements
that need to be mounted. If that's the case then those elements are most likely
generated by different plugins, which could each return their own DOM element.
Good question. I don't have an answer from experience there, but instinctively
I'd say both.
nanoraf exists to make it so re-renders don't happen if new state wasn't
flushed down. Actually refreshing at 60fps causes most CPUs to spin so you
don't wanna do that; instead only re-render when new stuff happens, capped at
60fps is like a good way of doing things. That's what nanoraf does for you. the
raf
package is a polyfill for browsers that don't support it.Yeah, yo-yo is a low-level library - it might not be for everyone. I'm not sure
what I'd recommend for building libraries if not
yo-yo
; using JSX won'tnecessarily help with things like this. Have you taken a look at
cache-element
at all? - It's a bit young still, but I think it should helpsquash some of the duplicate fetch issues at least.
I hope this provides a sufficient answer to your questions! ✨