🍱

Next.js × Cloud Firestore × Material-UIでオレオレCMS

4 min read

Jamstack Advent Calendar 2020 の 1 0日目の記事です。

記事なんて久方ぶりなので、誤字脱字などあるかもしれませんが、気づいたら直していきますのでお手柔らかにお願いいたします。
また、あまり時間が取れず事例が少なくなってしまったので、後ほど加筆したいとおもっていますm(_ _)m

今回はタイトルにもある通り、Next.js × Cloud Firestore × Material-UIを使って自作CMSを作ってみたよというお話です。

モチベーション

CMSサービスは多々存在するかと思いますが、今回の経緯としては、コンテンツ次第でビジュアルの変更が多々発生することや、急な変更にも対応できるような柔軟性が求められたため、いろいろと模索した結果、それなら自作したほうが良いのではないかと思い生まれたものとなります。

そこで至ったのが、Next.js × Cloud Firestore × Material-UIを利用したコンポーネントのスタイルをデータ管理で実現した自作CMSのページ作成です。

今回はスタイル制御するコンポーネントとしてMaterial-UIを採用しましたが、こちらはどのようなスタイルコンポーネントでも設計次第で利用できるのかなと思います。

Firestoreはドキュメント指向データベースのため、ドキュメントの中で保持できるデータ構造が、配列やオブジェクトなど複雑なものも管理できます。
これを利用して、コンポーネントのPropsを指定することで、柔軟なスタイル制御を行えるようになります。
また、ページ作成時にはNext.jsを使ってプリレンダリングすれば、UXを考慮しつつ柔軟なページを提供できるようになります。

自作したもの

一例として、よく使うであろうテキスト表示をご紹介します。

まずは型を定義しますが、今回はMaterial-UIを採用していることも有り、Material-UIのTypographyのProps定義を流用します。

このとき、色やテキストを外側から渡しやすくするために少し拡張しています。

import { TypographyProps } from '@material-ui/core/Typography';

// カラーをコード指定、テキスト指定できるようにしたTypography
interface CustomTypography extends Omit<TypographyProps, 'color'> {
  // 色(例:#57B1FF)
  color: string;

  // テキスト
  text: string;
}

次に定義した CustomTypography を使って、表示するようのカスタムコンポーネントを作成していきます。

利用したプロジェクトでは基本色をテーマカラー指定をしているため、 CustomColorText の中ではThemeProviderを使ってテーマ色を上書きできるようにしていますが、それ以外はMaterial-UIの Typographyを使っています。

<CustomColorText
        customColor={props.color}
        // 色を上書き
        {...omit(props, 'color')}
      >
        {props.text}
      </CustomColorText>

実際にFirestoreにデータを入れて表示して見たいと思います。

今回は青字で中央寄せのタイトルとして登録してみます。

{
    "title": {
        "align": "center",
        "text": "吾輩は猫である",
        "variant": "h2",
        "color": "#8a90cf"
    }
}

表示にあたって、PageやCustomColorTextを利用したコンポーネントは割愛させていただきますが、タイトルを持つアイテム要素のデータ型としては以下のようなものとなります。

interface CustomItem {
  title: CustomTypography;
}

画面に表示してみます。

一行だけでは寂しいので、複数行形式の説明も追加してみようと思います。

説明欄を追加してみますが、行単位にスタイルの変更を許容できるようにCustomTypographyの型を配列として持つことで対応できるようにします。

interface CustomItem {
  title: CustomTypography;
  description: CustomTypography[];
}

Firestoreには行ごとにスタイルを変更したデータをいれてみます。

一番下の要素はaタグを指定できるようにしていますが、こちらはMaterial-UIのTypographyを利用しているための利点といえます。

{
    "title": {
        "align": "center",
        "text": "吾輩は猫である",
        "variant": "h2",
        "color": "#8a90cf"
    },
    "discription": [
        {
            "align": "left",
            "text": "吾輩わがはいは猫である。名前はまだ無い。¥n",
            "variant": "h3",
            "color": "#161722"
        },
        {
            "align": "left",
            "text": "どこで生れたかとんと見当けんとうがつかぬ。¥n",
            "variant": "body1",
            "color": "#161722"
        },
        {
            "align": "left",
            "text": "何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。¥n",
            "variant": "subtitle2",
            "color": "#161722"
        },
        {
            "align": "left",
            "text": "続きはこちらから",
            "variant": "subtitle2",
            "color": "#161722",
            "href": "https://ja.wikipedia.org/wiki/%E5%90%BE%E8%BC%A9%E3%81%AF%E7%8C%AB%E3%81%A7%E3%81%82%E3%82%8B",
            "component": "a"
        }
    ]
}

画面に表示してみます。

このようにFirestoreのデータ構造とカスタムコンポーネントのPropsをうまく制御することで、自由の効くスタイル制御ができるようになります。

今回コンポーネントはTypographyのみのご紹介となりましたが、同じ方法で背景要素やボタンなど、流用できるコンポーネントは多いと思います。

あとはこれらのコンポーネントを組合わあせてPageとして定義し、
Next.jsのISR(Incremental Static Regeneration)や、キャッシュを効かせたSSR(Server Side Rendering)を使ってFirestoreからコンポーネント用のデータ取得も行えば、キャンペーン施策に伴うページ追加・変更にも耐えられるランディングページが作れます。

注意点として、スタイルのPropsをFirestoreのドキュメントとして持つため、場合によっては複雑なものになってしまうかもしれませんので、その点はご留意いただければと思います。