Nuxt.js + Netlify で RSS を取得して静的 JSON にする

// この記事は、 [note](https://note.mu/in_colors_net/n/nd00febead130) に投稿した記事の再掲です。

# やりたいこと

[IFTTT](https://ifttt.com/discover) を使って note の更新を検知
↓
Nuxt.js で note RSS を取得して、静的 JSON としてダウンロード
↓
コンポーネント内で読み込みたい

[けっこう改造した動作サンプルはこちら](https://rss-nuxt-app.netlify.com/)

# 使うもの

- [Nuxt.js](https://ja.nuxtjs.org/guide/)
- [Netlify](https://www.netlify.com/) (デプロイ方法は割愛)
- [IFTTT](https://ifttt.com/discover) (Netlify に note の更新通知を送信する)

# Nuxt.js をインストールする

今回は {rss-nuxt-app} という名前でインストール。色々聞かれるので、 `axios` を追加する。そのほかは任意。

```bash
$ yarn create nuxt-app rss-nuxt-app
```

## パッケージをインストールする

`axios` 以外のパッケージをインストール。
必要なのは `fs-extra`, `xml2js`, `@nuxtjs/moment`
そのほかは任意。

```bash
$ yarn add -D fs-extra xml2js @nuxtjs/moment
```

`@nuxtjs/moment`
タイムスタンプを整形するやつ。あると楽なので必須。

`fs-extra`
JSON をローカルに書き出して静的ファイルにするためのやつ。必須。

`xml2js`
RSS は XML 形式なので、 XML を JSON に変換するためのやつ。必須。

`pug`, `SCSS` の loader とか
プリプロセッサ。 `pug`, `SCSS` を使いたい場合は必須。

```bash
$ yarn add -D pug@2.0.3 pug-plain-loader node-sass sass-loader
```

## RSS を静的 JSON にするためのファイルを作る

`node_modules` がある階層に `modules` ディレクトリを作成。
`api-build-json.js` という空のファイルを作成して保存する。

### nuxt.config.js に設定を記述

`@nuxtjs/moment` と、さっき作った `api-build-json.js` を `modules` に追加

```javascript:nuxt.config.js
module.exports = {
  ...
  modules: [
    ...
    ['@nuxtjs/moment', ['ja']],
    '~/modules/api-build-json'
    ...
  ],
  ...
}
```

# `api-build-json.js` を編集する

RSS を 取得して 静的 JSON にするソースコード
以下が全文

```javascript:modules/api-build-json.js
import axios from 'axios'
import fse from 'fs-extra'
import ps from 'xml2js'

export default function apiBuildJson() {
  const api = axios.create()
  const distJosonFile = './static/_nuxt/api/index.json'
  const arr = []
  
  // サムネイルを取得する関数
  const getThumbnails = (data) => {
    let thumbnails = data.match(/https(.|\s)*?(jpg|png|gif|jpeg)/gi)
    return (thumbnails !== null && thumbnails !== undefined)
      ? Object.values(thumbnails)
      : false
  }

  // Axios で記事の RSS を取得
  return axios.all([
    api.get('https://note.nokura.me/rss'),
  ]).then(axios.spread((nokura) => {
    // XML を格納する
    const xml = nokura.data

    // 変換した JSON を格納するためのオブジェクト
    let json = {
      items: []
    }

    // XML オブジェクト を JSON に変換して JSON オブジェクトに格納する
    ps.parseString(xml, (message, xmlres) => {
      json.items = xmlres.rss.channel[0].item
    })

    // サムネイルを取得した配列を作成して結合
    json.items.forEach((data) => {
      let thumb = getThumbnails(data.description[0])
      Object.assign(data, { thumb: thumb })
    })

    // 空の配列に JSON オブジェクトを push
    arr.push(json)

    // 静的ファイルとして出力
    fse.outputFile(distJosonFile, JSON.stringify(arr))
  }))
}
```
use with <a href='http://manchan.github.io/gist-tool/'>Gist Search</a>

**7行目**

JSON ファイルを吐き出す先を指定

```javascript:modules/api-build-json.js
const distJosonFile = './static/_nuxt/api/index.json'
```

**33 - 35 行目**

ここで XML を JSON に変換している

```javascript:modules/api-build-json.js
// XML オブジェクト を JSON に変換して JSON オブジェクトに格納する
ps.parseString(xml, (message, xmlres) => {
    json.items = xmlres.rss.channel[0].item
})
```

**37 - 41 行目**

RSS だと本文とサムネイルが同じ要素内にあるので
正規表現を使って画像だけを取得して配列にする

```javascript:modules/api-build-json.js
// サムネイルを取得した配列を作成して結合
json.items.forEach((data) => {
    let thumb = getThumbnails(data.description[0])
    Object.assign(data, { thumb: thumb })
})
```

画像を取得して配列にする関数は **11 - 16 行目** にあるやつ

```javascript:modules/api-build-json.js
// サムネイルを取得する関数
const getThumbnails = (data) => {
  let thumbnails = data.match(/https(.|\s)*?(jpg|png|gif|jpeg)/gi)
  return (thumbnails !== null && thumbnails !== undefined)
    ? Object.values(thumbnails)
    : false
}
```

## ビルドしてみる

`~/dist/_nuxt/api/index.json` てファイルが生成されるはず

```bash
$ yarn build
```

## 生成された JSON を読み込む

ウェブサイト全体で読み込みたいので、 `~/store/index.js` で `import` する

```javascript:store/index.js
import jsonData from '~/static/_nuxt/api/index.json'

export const state = () => ({
  jsonData: jsonData
})
```
use with <a href='http://manchan.github.io/gist-tool/'>Gist Search</a>

## `~/pages/index.vue` で表示してみる

```vue:pages/index.js
 <template>
  <div v-if="$store.state.jsonData[0]" class="p_note_mu">
    <div class="p_note_mu-body">
      <a
        v-for="(post, index) in $store.state.jsonData[0].items"
        :key="index"
        :href="post.link[0]"
        target="_blank"
      >
        <article>
          <!-- サムネイル -->
          <div class="p_nt-mv">
            <img v-if="post.thumb" :src="post.thumb[0]" :alt="post.title[0]" />
            <div v-else class="no-image">
              <div class="no-image-text">NO IMAGE</div>
            </div>
          </div>
          <div class="p_nt-body">
            <div class="p_nt-body-header">
              <p>
                <!-- 日付 -->
                {{ getTheDate(post.pubDate[0]) }}
              </p>
              <h3 class="p_nt-body-heading-text">
                <!-- タイトル -->
                {{ post.title[0] }}
              </h3>
            </div>
          </div>
        </article>
      </a>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    getTheDate(date) {
      return this.$moment(date).format('YYYY.MM.DD (ddd)')
    }
  }
}
</script>

<style>
.p_note_mu {
  padding: 80px 0;
}

.p_note_mu-body {
  width: 960px;
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
}

a {
  width: 300px;
  margin: 0 10px 20px;
  border: 1px solid #ccc;
}

.p_nt-mv {
  width: 100%;
  height: 200px;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #f1f1f1;
}

.p_nt-body {
  padding: 20px;
  border-top: 1px solid #ccc;
}
</style>
```

use with <a href='http://manchan.github.io/gist-tool/'>Gist Search</a>

上記のコードでこんなかんじになる

![picture_pc_664b18c1faf845c62956661629b8b336.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/47adeff7-c685-f97a-4bd2-224933401a6f.png)

# IFTTT を使って Netlify に note の更新通知を送る

## Netlify 側での作業

### Netlify で webhook の URL を発行する

**Settings ＞ Build & deploy ＞ Build hooks ＞ Add build hook** で URL が発行できる。
ここで発行した URL をメモしておく。

## IFTTT を利用した作業

更新通知は IFTTT を利用して Netlify  に送る。

IFTTT
https://ifttt.com/


(1) 登録をして、右上のアカウント名をクリック → **New Applet**
![picture_pc_2333e352ff5c68d448d8f58021a36b06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/82c5c267-275c-5bcf-e086-889b4dd25471.png)


(2) **+this** をクリック
![picture_pc_728c26a80b53fc85944e1f0c23241b0e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/9be3dba2-1c32-3a30-16d4-2c19d359ec6c.png)


(3) **RSS** を選択
![picture_pc_96205dd46d44aeb04f49ddfa9f2797a7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/86ed6555-62f4-c592-8e5b-634ad359b496.png)


(4) **New feed item** を選択
![picture_pc_7dc4ada3371d97a1df8f6d04f5c05437.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/f0143cd1-d8ad-6bf6-0367-3b79b897f2a8.png)


(5) RSS の URL を入力し、 **Create trigger** をクリック
![picture_pc_374abfc642243d4703dc05a990f4d341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/d90ff2b2-dbc2-74e0-c5f5-18123f575c13.png)


(6) **+that** をクリック
![picture_pc_6119db8feec473d63c37abbd4e41efcb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/3e2cdb52-5752-a979-bfb2-e8882b155787.png)


(7) **Webhooks** を選択
![picture_pc_0462fc509bc9ec40844938b26576e45c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/43c6ed04-3af5-61fc-8160-67f741805c69.png)


(8) **Make a web request** をクリック
![picture_pc_eda961a888a4f2294b3092cc3c4018c3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/2e8e1e6c-c913-61ae-0e2f-a55f12212e31.png)

(9) 下記の設定項目を入力し、 **Create action** をクリックして終了

| 項目 | 内容 |
| :--: | :-- |
| **URL** | Netlify で発行した webhook の URL|
| **Method** | **POST** を選択 |
| **Content Type** | **application/json** を選択 |

![picture_pc_31c0b35fde2b0fd37b50076f56092979.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238267/5978e64b-8382-87f3-a944-050c1cbed1cd.png)

タイムラグはあるものの、 note の更新を Netlify が検知できるようになりました。

あとは普通に note を更新するだけ。

おわり。

# 参考リンク
のくらさんの note
https://note.nokura.me/

のくらさんの Twitter
https://twitter.com/riman114

けっこう改造した動作サンプル
https://rss-nuxt-app.netlify.com/

けっこう改造した動作サンプルのソースコード
https://github.com/incolorsnet/rss-nuxt-app.netlify.com