ローカルファイルを監視してS3に自動アップロード（Node.js & Chokidar）

# はじめに
やることはタイトルそのまんま。色々な使い道があると思うのですが、
僕がやりたかったのは「JavaScriptコードをS3でホスティングしながら開発」
もっと言うと「kintoneでJavaScriptカスタマイズ中のデバッグ」なんです。

[Dropboxで同期](https://developer.cybozu.io/hc/ja/articles/201308690-JavaScript%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E3%81%AE%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%82%92%E3%81%8B%E3%82%93%E3%81%9F%E3%82%93%E3%81%AB%E3%81%99%E3%82%8B%E3%82%A6%E3%83%A9%E3%83%AF%E3%82%B6)するのが常套手段なんですが、
最近Dropboxの同期後にkintoneに反映されるのがとても遅くて
なんかとても開発効率下がってたんですよね。

なので、これを機にAWS S3を使って脱Dropboxしちゃおうと思ったのでした。

# コード
[nodejs aws-sdkでs3ファイルアップロード](https://qiita.com/hashito/items/dff9adc37fb683e6c738)
をかなり参考にさせていただきました。ありがとうございます！

```json:rootkey.json
{
  "accessKeyId": "xxxxxxxxxxxxxxxxxxxx",
  "secretAccessKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```
```js:s3.js

#!/usr/bin/env node

const AWS = require('aws-sdk')
const fs = require('fs')
const path = require('path')
const chokidar = require('chokidar')

AWS.config.loadFromPath('./rootkey.json')
AWS.config.update({ region: 'リージョン名' })

const s3 = new AWS.S3()
const params = {
  Bucket: 'バケット名',
  ContentType: 'application/javascript', // JS以外も混じる場合は一工夫必要
  ACL: 'public-read',
}

const FILES = [
  'ソースコード1.js',
  'ソースコード2.js',
  'ソースコード3.js',
  'ソースコード4.js',
  'ソースコード5.js',
  'ソースコード6.js',
  'ソースコード7.js',
  'ソースコード8.js',
]
const S3_FOLDER = 'S3のフォルダ名'
const RANDOM = 'no3EGxETfddCoouWXV77'

chokidar.watch(FILES).on('all', (event, filePath) => {
  console.log(event, filePath)
  if (!(event === 'add' || event === 'change')) {
    return
  }

  params.Body = fs.readFileSync(filePath)

  const ext = path.extname(filePath)
  const filePathWithoutExt = filePath.replace(new RegExp(ext + '$'), '')
  params.Key = `${S3_FOLDER}/${filePathWithoutExt}-${RANDOM}${ext}`

  s3.putObject(params, function(err, data) {
    if (err) console.log(err, err.stack)
    else console.log(data)
  })
})
```

## 実行
Node.jsがインストールされている状態で、

```shell-session
$ npm i -g aws-sdk
$ npm i -g chokidar
$ node s3.js
```
これで`FILES`配列に列挙したJSソースコードが監視されて、
エディタでファイルを保存次第、随時S3にアップロードされます！

## 解説
- Node.jsの[Chokidar](https://github.com/paulmillr/chokidar)ライブラリでファイル監視
- 定義済みファイルが追加・更新されたら[aws-sdk](https://github.com/aws/aws-sdk-js)ライブラリでS3にアップロード

というのが基本の仕組みです。
S3の設定周り詳細は割愛しますが、ググったらすぐ情報見つかるはず。

デフォルト設定から変更してる部分はここですね。

```js
  ContentType: 'application/javascript',
  ACL: 'public-read',
```

そしてこのランダム文字列。

```js
const RANDOM = 'no3EGxETfddCoouWXV77'
```

これはなくても動作しますが、ファイル名を予測され辛くしておかないと
ホスティングされてるURLが暴かれてしまう危険性があるので、その工夫です。

本当はS3側で細かくいろいろ設定してやればセキュアに出来るんでしょうけど、
本番環境では使わない想定なので、そこまで面倒なことはしたくなかったので。
その辺はDropboxの公開URLの仕様に似せてます。

ちなみにフォルダ名じゃなくてファイル名の末尾に付けた理由は、
「ファイルパスの途中まで読めば何のファイルか分かるから」です。
kintoneにURL載せる時とか、末尾は省略されちゃうんでね。

ランダム文字列の生成は、Macだとこんなワンライナーで。

```shell
env LC_CTYPE=C tr -dc "a-zA-Z0-9" < /dev/urandom | head -c 20
```

# Webpackを使っている場合
`output`に出力されるJSファイルをこの方法で監視すればできますが、[webpack-s3-plugin](https://www.npmjs.com/package/webpack-s3-plugin)を使うともっとスムーズです。また早めに記事書きたいなー。


# 参考サイト
- [nodejs aws-sdkでs3ファイルアップロード](https://qiita.com/hashito/items/dff9adc37fb683e6c738)
- [Node.jsでファイル監視を行うchokidarを使ってみよう](https://dotstud.io/blog/nodejs-npm-chokidar-fswatch/)
- [Macでランダムな文字列をサクッと生成する方法](https://qiita.com/reoring/items/bcdaf6a4f538b8ff4243)