2019-06-06に投稿

短歌投稿サイト「ちるなり」の技術メモ

この記事について

ちるなり|短歌の投稿サイトの技術的な話のメモです。

functionの配列を受け取ってasync.parallelする

複雑な処理になると自分でasync/awaitやPromiseをごにょごにょして書くのがつらいことがあるので、よくcaolan/asyncを使います。このなかのasync/parallelはfunctionの配列やオブジェクトを第一引数に、すべてのタスクのあとに実行するコールバックを第二引数に受け取ります。このとき、第一引数に渡されるfunctionはその第一引数としてコールバックをトリガーするfunctionを受け取るのでなければなりません。

で、そのようなfunctionの配列を任意のオブジェクトをわたして生成してasync.parallelしたかったときの実装のサンプルです。lodash/curryとかを使っています。

const express = require("express");
const async = require("async");
const _ = require("lodash");

const router = express.Router();

const admin = require("../admin/admin.js");
const refusers = admin.database.ref().child("users");  // firebaseのRealtimeDBの参照です

router.patch("/hogehoge", (req, res) => {
    const closures = _.partial(function (callback, album) {
        return _.map(req.body.patches, (patch, key) => {
            return _.curry(function (callback) {

                /*
                    何かの処理
                */

                callback(null, null);

            })(callback);
        });
    });
    function execClosures (album) {
        async.parallel(closures(_, album), (err, result) => {
            res.status(200).end();
        });
    }
    refusers.child(req.body.uid).once("value", (snapshot) => {
        if (snapshot) {
            const album = snapshot.val();
            execClosures(album);
        } else {
            res.status(500).send({ err: "No snapshot found" });
        }
    }).catch(err => {
        res.status(403).send({ err: err });
    });
});

HerokuにデプロイしたNuxt.jsのプロジェクトの静的ファイルをFirebase Hostingから配信する

静的ファイルだけvuepressで生成したページとあわせてHostingにあげます。package.jsonに以下のようなことを書きます。YOUR_TOKENの部分はfirebase-toolsのlogin:ciというコマンドであらかじめ取得しておいたトークンに読み替えてください。

  "scripts": {
    "dev": "cross-env NODE_ENV=\"development\" nodemon server/index.js --watch server",
    "build": "cross-env NODE_ENV=\"production\" nuxt build",
    "start": "cross-env NODE_ENV=\"production\" forever --killSignal=SIGTERM -c 'nodemon --exitcrash' server/index.js",
    "inspect": "cross-env NODE_ENV=\"development\" node --require dotenv/config --optimize_for_size --max_old_space_size=920 --gc_interval=100 --inspect server/index.js",
    "docs:dev": "vuepress dev docs",
    "docs:build": "vuepress build docs",
    "deploy:nuxt": "rimraf docs/.vuepress/dist/nuxt && mkdirp docs/.vuepress/dist/nuxt && cpy .nuxt/dist docs/.vuepress/dist/nuxt",
    "deploy:static": "rimraf docs/.vuepress/dist/static && mkdirp docs/.vuepress/dist/static && cpy static/contents docs/.vuepress/dist/static",
    "deploy:hosting": "firebase deploy --token 'YOUR_TOKEN' --except functions",
    "deploy:functions": "firebase deploy --only functions",
    "heroku-postbuild": "yarn build && yarn run docs:build && yarn run deploy:nuxt && yarn run deploy:static && yarn run deploy:hosting"
  },
  "devDependencies": {
    "cpy-cli": "^2.0.0",
    "cross-env": "^5.2.0",
    "dotenv": "^7.0.0",
    "firebase-tools": "^6.5.3",
    "forever": "^1.0.0",
    "mkdirp": "^0.5.1",
    "nodemon": "^1.18.10",
    "rimraf": "^2.6.3",
    "vuepress": "^1.0.0-alpha.47"
  }

nuxt.config.jsでアセットをFirebase Hostingから取得するように設定します。ローカルで開発しているときには手元のファイルを参照したいので、production時のみにしましょう。

const isdev = (process.env.NODE_ENV === "development")

module.exports = {
    // buildのところだけ抜粋
    build: {
        publicPath: isdev ? "/_nuxt/" : "https://your_project_name.firebaseapp.com/nuxt",
    }
}

firebase.jsonのhostingの設定をします。ヘッダーを設定しないとクロスオリジン制約で配信できなくなるので、ここで必ず設定します。

  "hosting": {
    "public": "docs/.vuepress/dist",
    "ignore": [
      "firebase.json",
    ],
    "headers": [
      {
        "source" : "**/assets/**",
        "headers" : [{
          "key" : "Access-Control-Allow-Origin",
          "value" : "*"
        }]
        }, {
        "source" : "**/nuxt/**",
        "headers" : [{
          "key" : "Access-Control-Allow-Origin",
          "value" : "*"
        }]
        }, {
        "source" : "**/static/**",
        "headers" : [{
          "key" : "Access-Control-Allow-Origin",
          "value" : "*"
        }]
    }],
    "cleanUrls": true,
    "trailingSlash": false
  },
Originally published at shinabitanori.qrunch.io

旧・ちるなり

アイコンのライセンスはサイトフッターをご覧ください。

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント