Flamelinkでブログ機能をVue+Firebaseで作ったSPAに追加する

## はじめに（言い訳）
クソアプリアドベントカレンダー初参加のかつおです！
昨年は完全に読む側で、投稿されるアプリのセンスや利用技術のレベルの高さ、力の入れ具合にただただ関心していました。みなさん本当に凄い！
まさか憧れのクソアプリアドベントカレンダーに記事を投稿する日が来ようとは想像だにしなかったのですが、今回は募集期間に偶然出会ってしまったので、勇気を出して申し込みをさせていただきました！！

伝統のクソアプリアドベントカレンダー
「クソアプリは俺が制す。」
断固たる決意を胸に秘め、脳内企画に技術を試したりとかしていたのですが、12月の某日、状況が一変します。

「[辛いものが好きアドベントカレンダー](https://adventar.org/calendars/4857)」たるものが、私が運営している[カライイネ](https://karaiine.jp/)のユーザー様の手によって立ち上がったのです！

「これは...クソアプリ作ってる場合じゃねーな。。」
私はカライイネのユーザー様に心臓を捧げた人間です。
[辛いものが好きアドベントカレンダー](https://adventar.org/calendars/4857)を少しでも盛り上げるべく、カライイネにアドベントカレンダーに合った新機能を作ろう！
（作った機能は大したことないのでクソっちゃクソです）

という流れで今回の開発に至ったのでした。。

## つくったもの
[カライイネマガジン](https://karaiine.jp/magazin)

もともと運用していた激辛口コミサイト[カライイネ](https://karaiine.jp/)のマガジン機能です。
CMSとして[Flamelink CMS](https://flamelink.io/)を使ってみました。

### Flamelink CMSとは？
* コンテンツ管理（記事投稿とか）のみをやってくれるSaaS
* 自分で用意したFirebaseプロジェクトと連携してCMSを構築
* 投稿したコンテンツは自分のFirebase上に保存される
* フロントはなし。コンテンツを取得するAPI等が用意されている
* Firebaseにデータ保持されるので、構造が理解できれば普通のデータアクセスも可能
* 無料枠あり。個人開発レベルなら無料枠に全然収まる。

### 使ってみた感想
#### good
* CMSが簡単に構築できるのは便利
* 使い慣れたFirebaseにデータが乗っかるので理解しやすい。

#### bad
* アップデートちゃんとされてるか、今後もされるか不安
* Wardpressと比較して画像の挿入とか面倒
* データ取得のAPIが権限エラーになって使えなかった..
  （Functionsから直接Firestoreを参照することで回避）

## システム構成
<img width="587" alt="システム構成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161023/91293bd6-d9f7-25c2-b07e-77bb88b246da.png">

* もともと本体もFirebaseで運用していたのですが、今回のマガジン用には別のFirebaseプロジェクトを作成しました。（計2プロジェクトのサービスに...）
* Flamelinkは記事の編集に利用。記事データはFirestoreとStorageに保存されます。
* SPAからの記事の取得はFunctionsで作成したAPIを利用しました。
* Functionsで記事の取得は普通にFirestoreの参照をしています。

## 作り方
### Flamelinkの設定
以下が詳しすぎるので、参照ください。
[今すぐ始められる！FIrebaseをブログのCMSに変える「Flamelink」を使ってみた！](https://paiza.hatenablog.com/entry/2018/11/21/%E4%BB%8A%E3%81%99%E3%81%90%E5%A7%8B%E3%82%81%E3%82%89%E3%82%8C%E3%82%8B%EF%BC%81FIrebase%E3%82%92%E3%83%96%E3%83%AD%E3%82%B0%E3%81%AECMS%E3%81%AB%E5%A4%89%E3%81%88%E3%82%8B%E3%80%8CFlamelink%E3%80%8D)

### 上記の記事通りにやってないと
#### ①DB
Realtime DatabaseとFirestoreの選択が必要なのですが、私は慣れてるFirestoreを選択しました。（PaizaさんはRealtime Database)

#### ②コンテンツの取得方法
「記事コンテンツを取得してみよう！」の章でflamelink.jsのライブラリ（[flamelink sdk](https://flamelink.github.io/flamelink/#/)）を利用して記事データを取得していますが、私は利用していません。。
flamelink sdkを利用しようとしたのですが、Firebaseの権限エラーを解消できず、もういいやって利用をやめました。
ググってみると同様のエラーに対して、RealtimeDatabaseを使えとの指示が...

#### ③flamelink sdkインストール時のエラー対処
（結局やめましたが）flamelink sdkはnpmでインストールして利用したのですが、npm installでエラーとなりました。
ググってみると、node.jsのバージョン10だとエラーになるとの記載が...
node.jsのバージョンを8に変更することで、エラー回避してインストールはできました。
権限エラーになるので、結局利用はやめましたが…
ちなみにnode.jsのバージョン変更には[nodist](https://github.com/nullivex/nodist/releases)を利用しました。（Windows環境）
nodist利用の際には、既存のnode.jsを1度アンインストールが必要なので面倒くさかったです。

#### ④functionsをAPI化
flamelinkのプロジェクトとフロントのプロジェクトが分かれているのでfunctions経由でflamelinkのデータを取得しています。
functionsのコードを載せておきます。

##### index.js
```javascript:index.js

const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)

const express = require('express')
const app = express()
app.use((req, res, next) => {
  // 許可ドメイン設定
  res.header('Access-Control-Allow-Origin', 'https://karaiine.jp')
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
  next()
})

app.use('/api/posts', require('./apps/posts.js'))
exports.app = functions.https.onRequest(app)

```
##### ./apps/posts.js
```javascript:./apps/posts.js
var router = require("express").Router()
const admin = require('firebase-admin');
var db = admin.firestore()

router.get('/', (request, response) => {
  // isOpen=trueで公開記事を、新しい順に取得
  db.collection('fl_content').where('isOpen', '==', true).orderBy('date', 'desc').get()
    .then((snapshot) => {
      let list = []
      snapshot.forEach(doc => {
        let data = doc.data()
        list.push(data)
      })
      response.json(list)
    })
    .catch(error => {
      console.log(error)
    })
})

module.exports = router
```

## さいごに
読んでいただきありがとうございます！
辛いものが好きな方、辛いものが好きアドベントカレンダーもお願いいたします！
[辛いものが好きアドベントカレンダー](https://adventar.org/calendars/4857)