Skip to content

Instantly share code, notes, and snippets.

@yoshuawuyts
Created November 1, 2016 23:21

Revisions

  1. yoshuawuyts created this gist Nov 1, 2016.
    154 changes: 154 additions & 0 deletions uppy-feedback.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,154 @@
    # uppy
    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.
    ## Readme
    - 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:

    ```sh
    #!/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"
    ```

    ## Issues
    - 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

    ## Core
    - import with `/` is not great for file sizes; not necessarily an issue with
    rollup but that's not for everyone
    - `new` can be unwieldy - use `if (!(this insteanceof Foo))`
    - `Core` is an odd name; the thing being used is the `uppy` file transfer
    framework; all instances of `Core` 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

    ## Plugins
    - 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

    ### proposal

    ```txt
    state [patch] -> uppy -> state [complete]
    ```

    ```js
    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

    ## API
    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:
    ```js
    { files: [] }
    ```

    Internal:
    ```js
    { 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

    ```js
    uppy.set({ files: [ File ] })
    ```

    ## Plugins
    - Drag and Drop & Progressbar are inconsistent
    - drag and drop adds functionality to a selector
    - progress injects an element into the selector