Nuxt.js + uppyで洗練された画像アップロード

GitHubのトレンドを眺めていて、[uppy](https://github.com/transloadit/uppy)というアップロード用npmライブラリが気になったので、少し使ってみました。

## uppyとは
>Sleek, modular open source JavaScript file uploader

>Uppy fetches files locally and from remote places like Dropbox or Instagram. With its seamless integration, reliability and ease of use, Uppy is truly your best friend in file uploading.

ローカルのファイル以外にも、DropboxやGoogleDriveからファイルを選択してアップロードも可能なモジュールのようです。

[公式サイト](https://uppy.io/)
[GitHub](https://github.com/transloadit/uppy)

UIはこんな感じになります。

![uppy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/361a573e-cad4-9da3-6066-4d155ef03239.png)


## 環境
- node: v12.0.0
- nuxt: 2.6.3
- uppy: 1.0.0

## 試してみる
GoogleDriveやDropboxからのファイルアップロードはOAuth設定がひと手間あるので、今回は一番シンプルなローカルのファイルアップロードとカメラで撮影してアップロードの2種のみ試します。
また、サーバーサイドの実装も割愛するため、XHRリクエストでダミーのサイト(uppy開発元が用意している)に送信しています。

XHRでのリクエストが送信できるため、あとはexpressなりでサーバーサイドのアップロード処理を実装してあげれば、簡単にアップロードを実装できます。

また、本記事では特に触れませんが、Amazon S3へのクライアントからのアップロードも可能です。

本記事で実装したコードは下記のリポジトリで公開しています。
[reireias/nuxt-uppy-example](https://github.com/reireias/nuxt-uppy-example)

### プロジェクト作成
create-nuxt-appを利用します。(最後の引数のプロジェクト名は任意です)

```sh
yarn create nuxt-app nuxt-uppy-example
```

オプションは下記にのように選択します。

- `? Use a custom server framework`: expressを選択
  - サーバーサイドを実装するのを見越して(本記事では行っていません)
- `? Choose features to install`: LinterとPrettierを選択
  - 好み
- `? Use a custom UI framework`: vuetifyを選択
  - 好み

不要な実装を削っていきます。

```vue:layout/default.vue
<template>
  <v-app>
    <v-content>
      <v-container>
        <nuxt />
      </v-container>
    </v-content>
  </v-app>
</template>
```

```vue:page/index.vue
<template>
  <v-layout column justify-center align-center>
    <v-flex xs12 sm8 md6>
      <center>
        <h1>Nuxt.js + uppy example</h1>
      </center>
    </v-flex>
  </v-layout>
</template>
```

### uppyを追加する
[公式ドキュメント](https://uppy.io/docs/)を参考に実装していきます。

必要なパッケージを追加します。

```sh
yarn add @uppy/core @uppy/dashboard @uppy/webcam @uppy/xhr-upload
```

利用するcssを設定しておきます。

```js:nuxt.config.js
...
  css: [
    '~/assets/style/app.styl',
    '@uppy/core/dist/style.css',
    '@uppy/dashboard/dist/style.css',
    '@uppy/webcam/dist/style.css'
  ],
...
```

ボタンを押すとアップロードダイアログが表示されるように実装します。
uppyのモジュールをimportし、`mounted`の中で実装しています。
`Dashboard`単体ではローカルのファイルアップロードにしか対応していないため、他のアップロード手段(今回はweb camera)を追加するには、下記の様に`uppy.use`で追加する必要があります。

```vue:page/index.js
<template>
  <v-layout column justify-center align-center>
    <v-flex xs12 sm8 md6>
      <center>
        <h1>Nuxt.js + uppy example</h1>
        <v-btn id="select-files" color="primary">upload</v-btn>
      </center>
    </v-flex>
  </v-layout>
</template>

<script>
import Uppy from '@uppy/core'
import XHRUpload from '@uppy/xhr-upload'
import Dashboard from '@uppy/dashboard'
import Webcam from '@uppy/webcam'

export default {
  data() {
    return {
      uppyId: 'uppy-trigger'
    }
  },
  mounted() {
    const uppy = Uppy()
      .use(Dashboard, {
        trigger: '#select-files'
      })
      .use(Webcam, { target: Dashboard }) // ウェブカメラを追加
      .use(XHRUpload, { endpoint: 'https://api2.transloadit.com' }) // ダミーのURLへアップロード
    uppy.on('complete', result => {
      // eslint-disable-next-line no-console
      console.log(
        'Upload complete! We’ve uploaded these files:',
        result.successful
      )
    })
  }
}
</script>
```

`yarn dev`で起動し、ボタンを押してみましょう。
下記の画像のようにダイアログが表示されるはずです。

![uppy2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/78c400bf-f7d6-69d5-8d09-f841bfb45fe1.png)

複数ファイルのアップロードにも対応しています。

![uppy3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/8ad316a8-932c-d3b1-f499-e78b411dd347.png)

## まとめ
uppyを利用することで、リッチなアップロードダイアログを簡単にNuxt.jsのプロジェクトに追加することができました。

GoogleDriveやDropboxからのアップロードを行う際には、[companion](https://uppy.io/docs/companion/)というモジュールを利用し、server-to-serverでファイルをアップロードする必要があります。(必要になったら挑戦します)