Firebase Cloud functionsでEXCELを読み込んで書き込む

# Firebase Cloud functionsでEXCELを作って画面側でダウンロードさせたい！

探してもあまり出てこないので初めて書いてみました

## 実現すること

Firebase functionsで、Firebase storageに置いたEXCELひな形ファイルを読み込み、書き込んでからstorageに新ファイルとして書き込む。
functionは画面上のボタンクリックからHTTP リクエストで呼び出し、そのファイルをダウンロードさせる。

#### functions側
```js:index.js
const cors = require('cors')({ origin: true });
const functions = require('firebase-functions');

const keyFilename = "./credential/XXXXXXXX.json";
const projectId = "project-id";

const gcs = require('@google-cloud/storage')({
    projectId,
    keyFilename
});
const bucket = gcs.bucket("ikeiketest");
const path = require('path');
const os = require('os');

exports.createExcel = functions.https.onRequest((req, res) => {

    const moment = require('moment');
    cors(req, res, () => {

        // storage上のファイル名
        var fileName = 'template.xlsx';
        // テンプレートファイルを一時的に置く場所のパス
        const tempFilePath = path.join(os.tmpdir(), fileName);

        bucket
            .file(fileName)
            .download({
                destination: tempFilePath
            })
            .catch(err => {
                console.error('テンプレファイルダウンロードエラー:', err);
            })
            .then(() => {
                const newFileName = 'sample.xlsx';
                const newFilePath = path.join(os.tmpdir(), newFileName);
                const metadata = { "contentType": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };

                var Excel = require('exceljs');
                var workbook = new Excel.Workbook();

                // テンプレートのEXCELを読み込む
                workbook.xlsx.readFile(tempFilePath).then(function () {

                    // なにか書き込む
                    var sheet1 = workbook.getWorksheet(1)
                    sheet1.getCell(rownum, 3).value = '書き込んだよ';

                    // 書き込んだファイルを保存
                    workbook.xlsx.writeFile(newFilePath).then(function () {
                        // storage上のパス
                        var destPath = '/tmp/' + newFileName;
                        bucket.upload(newFilePath
                            , {
                                destination: destPath, metadata: metadata
                            }).then(function () {
                                res.status(200).send(destPath);
                            })
                    })
                })
            })
    });
});
```

#### 画面側
```js:main.js
axios.post('createExcel'
            , {
// 本当はfirebase authenticationのtokenを送って認証する
                token: token,
            })
            .then(function (response) {
                var storage = firebase.storage();
                var pathReference = storage.ref(response.data);
                pathReference.getDownloadURL()
                    .then(function (url) {
                        var xhr = new XMLHttpRequest();
                        xhr.responseType = 'blob';
                        var blob;
                        xhr.open('GET', url);
                        xhr.send();
                        return xhr;
                    })
                    .catch(function (error) {
                        console.log(error.message);
                    })
                    .then(function (xhr) {
                        xhr.onload = function (event) {
                            blob = xhr.response;
                            saveAs(blob, fileName);
                            resolve();
                        };
                    })
            })

```