Vue.js + Contentfulでブログを作ったので使用技術・反省点をまとめる

※ブログ（ https://coincidence.netlify.app/#/post/vue-js-contentful ）からの転載です。

----

当ブログを作成するにあたって使用した技術、反省点を自分用にまとめておきます。
ソースコードはこちら→ https://github.com/AsazuTaiga/my-blog

## 環境・構成

当ブログの提供環境をざっくり図で表すと、下のような感じです。 

![environment](//images.ctfassets.net/i4hhogzjzr5w/5wRrYNlAUMveB5uXeYY7LS/bf0249afadb5448c3afb864787b0ab4e/_______1.png)

vue-cliで作成したVue製サイトを、Netlifyでホスティングしています。GitHubと連携してmasterへのmergeごとにビルド・デプロイが自動的に走ります。 
コンテンツ管理（バックエンド）には、Contentfulを使用しています。ContentfulはヘッドレスCMSであり、自身でコンテンツモデルおよびコンテンツを作成することができます。JavaScript用のSDKが用意されており、コンテンツを指定・フィルタリング・ソートして取得することができます。

![design](//images.ctfassets.net/i4hhogzjzr5w/5AkDEN1lmJJiE1modKHfxs/6a28024e1ec0bdfc7caa010c8aa4339d/_______________.png)

各View・ComponetsはVue Routerに対してパスの変更を行い、また検知します。
他のView・Componentsによるパスの変更が変更された場合、dataプロパティに保持しているコンテンツを一旦削除したうえで、現在のパスで表示したいデータの取得をContentfulAdapterに依頼します。AdapterはContentful Delivery APIを叩いたレスポンスをPromiseの形でView・Componentsに渡します。
データの取得中、すなわちdataプロパティが空の場合はローディングを表示しておき、Promiseがresolveしたらレスポンス内容をdataに取り込んで表示します。

Vuexどこで使っているの？というと、唯一グローバルに管理する必要がありそうだったメニューの展開/非展開の状態だけです。これも冷静に考えればメニュー用のコンポーネントで閉じているので、あまり意味はない（むしろ良くない）使い方ですね……。使いたかっただけです。

図には出していませんが、見た目を整えるのにVuetifyを使っています。

## 反省点
**①非同期処理＋ローディング表示のコンポーネントを作るべきだった** 
少なくとも、ローディング画面用のコンポーネント（ぐるぐる）を各Viewに配置して、同じCSSでセンタリングして、同じように非同期中はぐるぐるさせているのは、大変コスパが悪い気がしています。「コンポーネントは画面内での配置を意識しない」「Viewはコンポーネントの位置を決めて配置する」といった自分なりの方針でやっていたのですが、それにしたって同じコードを何度コピペしたかわかりません。こういった場合のベストプラクティスが何なのか、ご存じの方教えてください…。 

**②ストアを適切に使う、いらないなら削るべきだった** 
各記事の内容をキャッシュさせる必要はないとしても、最低限、タグのIDの一覧くらいは最初に控えておいたほうが効率的でした。現状、タグに紐づく記事の一覧表示には、次のステップが発生しています。 
(1) 選択されたタグの名前をもとにタグのIDを問い合わせる 
(2) タグのIDをもとにそれに紐づく記事を取得する 
 
```javascript
  async fetchBlogPostsByTagAtPage(tagName, pageNumber) {
    const tagResponse = await this.fetchTagsByName(tagName);
    if (tagResponse.total === 0) {
      throw new Error("タグが存在しません。");
    }

    const tag = tagResponse.items[0];

    return this.client.getEntries({
      content_type: "blogPost",
      "fields.tags.sys.id": tag.sys.id,
      order: "-fields.publishDate",
      skip: (pageNumber - 1) * POSTS_PER_PAGE,
      limit: POSTS_PER_PAGE
    });
  }

  async fetchTagsByName(name) {
    return this.client.getEntries({
      content_type: "tag",
      "fields.name": name,
      limit: 1
    });
  }
```
「タグのIDを問い合わせる」のひと手間を確実になくせて速度向上と通信量減が期待できるのにやらないのは、良くない怠慢です。そのうち直したいですね（こういう言い草をしてしまうときは、たいてい直さないパターンです）。
そもそも、各コンポーネントがContentful Adapterを直接使っているのもあまりよくない気がしています。Vuexで取得して保持、各コンポーネントは取得完了通知を受け取って表示を更新するだけなのが理想なのでしょうか。

もちろんコンポーネントが状態を持つこと自体は悪ではないと思います。状態を層で閉じるか、コンポーネントで閉じるかの違いで、それぞれのメリット・デメリットがあります。そして、システムの規模が大きくなればVuexの恩恵が大きくなってくるのだと思います。
このブログくらいのミニマムな機能であれば、基本的に各コンポーネントで状態を閉じておいてよさそうです。もし上述のようにタグのリストを別で保持しておくストアが必要があったとしても、Vuexではない普通のストアで十分かもしれません。

**③CSSの共通定義を適切に管理するべきだった** 
開発中、何度もCSSで見た目をいじくりまわしながらあーでもないこーでもないとやっていたので、色定義やbox-shadowの定義がはちゃめちゃにハードコーディングされてしまいました。「自分用だから別にいいや……」という言い訳を開発中何度独り言ちたかわかりません。怖い。 
序盤の手間を惜しむと、終盤・保守でかえって大変になります。Done is better than perfectといえど、限度はあります。 

**④Vuetifyは本当に必要だったのか？グリッドだけ使えばよかったのでは？** 
v-cardやv-btnあたりのコンポーネントのCSSを!importantしまくって色々弄ったので、果たしてこれが良い方針なのか？と問われるとモニョります。v-container, v-row, v-col, v-iconあたりだけ選んで入れればよかったような気がしますし、もっと最小のライブラリがあればそれでよかったのではないか、いっそflexbox最近覚えたのでなにもいらなかったのでは、という気がしてなりません。開発効率アップには間違いなく寄与したVuetifyですが、その改造に腐心して醜いコードが大きく増えたのもまた事実です……。 

**⑤Viewsに再利用性の低い部品を直接書くべきか、コンポーネント化すべきか** 
再利用が見込めないけどViewsが肥大化するのは防ぎたい、みたいな意味合いでコンポーネントを細かく分けるべきかどうか非常に悩みました。
**色々試した結果、個人的には次のいずれかを満たす場合にコンポーネントとして切り出すべきだと思います。**

1. 状態を持つatoms, moleculesである
2. 内部に複数のatoms, moleculesを抱えるorganismsである
3. 複数の場所で使用されている

「1か所でしか使われず、状態を持たないatomsである」くらいならコンポーネント化をわざわざする必要はないのかな、という印象です。となると、ほとんどの場合にコンポーネント化を検討することになりそうです。
今回に関してはこの原則に従えてない部分も多いです。反省。

## 良かった点

反省点だけ見ているとしんどいので、良かった点も。

**①とにかく完成した、作っている最中もテンション高く臨めた** 
独りで何か作るときはとにかくこれが一番重要だと考えています。何かを作るときは、私の場合5割以上の場合で挫折します。今回はなんとかここまでこれたので、良かった…。

**②触りながらVuexを覚えられた** 
やや無理に取り入れた形になってしまいましたが、コンセプト・便利さ自体は理解できた気がします。ファースト・ステップとしては良かったとポジティブにとらえています。 

**③コンポーネント設計をずっと考えながら生活できた** 
最終的にベストな形にもっていけたとは到底言えませんが、ブログ内のComponents(Atoms, Molecules, Organisims)とViews(Templates, Pages)をどうするかをずっとお風呂の中とかで考えていたので、このへんのコンポーネント志向の勘所みたいなものはだいぶつかめたのではないかと思います。お仕事中にデザイナーさんのカンプを見たときも、自然とコンポーネントの単位をどこにすべきかを、目で切り分けるようになってきました。

**④Neumorphismに触れられた** 
最新のデザイントレンドっぽいやつで、Neumorphismというものがあります。私の理解ですが、単色の画面にbox-shadowで光・陰・影を当てることで浮き出たように見せるワザのようです。 
自分でCSSを調整するのはしんどかったので、こちらを使わせていただきました。 
https://neumorphism.io/ 

## 蛇足;ブログを自作した理由

そもそもなぜ機能も見た目も整っている既存のブログサービスを使用せずに、ヘッドレスCMSを使用してフロント周りを自作したか？という理由を一応メモしておきます:

- 自作のほうが愛着がわいてブログが継続できると思った
- カテゴリ・タグがブログの前提機能になっているが、どちらかだけで十分では？というのを検証したかった（このブログにはカテゴリはなく、タグだけです）
- Contentfulを利用して作成しておけば、将来的に移行する場合もスムーズだと思った

色々ありますが、結局一番大きいのは「作りたかったから作った」です。
作りたいベースではなく「ブログをやりたい」という理由であれば、既存のものを使ったほうが絶対良いと思います。