microCMSブログをNext.jsで構築しました。
更新情報
2022/01/23
aspida
を使った実装からmicrocms-js-sdk
に変更完了しました。
microCMS 固有の型を、独自に作成したものから公式のものに変更できていますので、
仕様変更にもある程度強くなっていると思います。
2021/07/14
Next.js ver.11 に対応しました!
また、その他ライブラリのアップデートも完了しています。
なぜ作ったのか
公式 microCMS ブログでソースコードが公開されました。
ご存知の方もいるとは思いますが、こちらのフロントエンドフレームワークは Nuxt.js となっています。
しかし、僕の勤務する会社もですが、Next.js を採用しているところは多いかと思います。
そうなると、できるだけ同じ見た目、機能で、技術構成のみ違うという物が公開されていたら、
ハードルが下がって、使い始める人や使い始める会社も増え、
Jamstack な構成や HeadlessCMS がもっと世の中に広まりやすくなるのではないかと考え、
構築するに至りました。
ちょっと前に同じような記事あったよね?
ここまで期間的に被ってしまうとは思っていませんでしたが、
同じ試みがこちらの記事でされています。
ただ、こちらの記事の方と私に、コードスタイル、技術構成などにおいて違いもあり、
僕のコードをあげる価値もあるだろうと思い、被ってはしまいますが、あげる判断をしました。
僕の方で、比較ポイントを抜粋しましたので、
ご自身のコードスタイルと合う方をご参考ください!
- aspida,pathpida の使用
- useSWR の使用
- 目次機能、シンタックスハイライトの処理タイミング
- 全てのパスをビルド時に検出(getStaticPaths の完全使用)
- postcss のプラグイン機能
- title,meta 系の記述
一部詳しく解説させて頂きます。
aspida,pathpida の使用
aspida,pathpida とは、型安全性のなかったものに、
ディレクトリ構造に基づいて自動的に型情報を与えることのできるライブラリです。
aspida は WebAPI の、pathpida はルーティングの型情報を自動生成してくれます。
個人的には typescript でアプリケーションや web サイトを作るなら、必須級のライブラリになっています。
VSCode の補完が効かないと不安になる体になってしまっていました。。。
目次機能、シンタックスハイライトの処理タイミング
こちらの2つをセットで考えているのは、
どちらも microCMS 上のリッチエディタで返ってきた HTML テキストをパーサ上で処理する点で一致しているからです。
そして、これらの機能をブラウザで、行ってしまうと表示までに時間がかかってしまうので
ユーザビリティがよくありません。
せっかく Jamstack な構成を採用しているのにこれではもったいないので、
ビルド時にこれを行います。
また、ここに Nuxt.js と Next.js の違いが出てきます。
Next.js では使っていないライブラリがクライアントビルドに含まれません。
なので、サイズの大きいライブラリを、ビルド時、またはサーバーサイドのみで使っているなら、
その分だけ Next.js の方が、軽くできます。(もちろん react のサイズと vue のサイズなどにも違いはありますが)
公式 microCMS ブログのソースコードとの違い
本家の microCMS ブログとの違いも少々ありますので、
そちらも追記します。
- スクロール時にヘッダー分ずれないように調整
- active クラス名によるスタイル指定からカスタムデータ属性によるスタイル指定に変更
- cheerio から jsdom に変更
- microCMS の API 登録で必須にチェックをいれる
こちらも適宜解説させて頂きます。
カスタムデータ属性によるスタイルの指定
詳しくはこちらの記事をご覧いただきたいのですが、
簡単にいうと、状態を表すクラス名や、BEM でいう Modifier は
カスタムデータ属性を活用した方が見通しも良く、css modules を使っている場合は簡潔にかけるよ、というものです。
僕はこれを知ってからは、単純な HTML ベースで書くときも状態を表すスタイルはカスタムデータ属性を用いています。
cheerio から jsdom へ変更
cheerio、jsdom は HTML をパースできるライブラリで(合ってますよね??💦)、
cheerio は jQuery ライクに書けるのが特徴なのですが、いかんせん jQuery の実務経験がほとんどないため、
標準の DOM API が使える jsdom を選択しました。
ただ、処理速度の面で、cheerio の方が優れているため、$
などに抵抗がない方はそちらをお勧めします!
僕は、ビルド時のみの処理に基本的にはなり、表示速度には影響しないということで割り切りました。
microCMS の API 登録では適宜必須にチェックをいれる
ここがこだわりポイントのひとつなのですが、API 登録で必須にチェックを入れることをお勧めします。
もちろん、場合によるのですが、最終的な表示画面に登録しておいて欲しい物は極力必須にした方がいいです。
理由は
フロントエンド側でのバリデーションが少なくて済み、バグを生むリスクが減る。
です。
必須になっていない項目は、null
や空配列で返ってくる可能性があるので、
都度バリデーションをするコストがかかり、隠れたバグを生むリスクもあります。
例えばプレビュー画面など登録者が途中経過を確認する場面を思い浮かべてみてください。
登録者「よし、少し登録したから、とりあえずみてみよう!」
登録者「あれ、表示されないぞ。」
登録者「不完全品じゃないか!!」
エンジニア (...null のバリデーションを忘れていた。。)
となるケースがあります。(実際に僕が経験しました。。。)
これに aspida を組み合わせることでこうなるケースはほぼゼロにできると思います。
microCMS を Typescript で使う時のおすすめ
aspida を用いるというのもそうなのですが、その時に、
- API Sceme の型
を定義しておくのがお勧めです。
今回のソースコードでは、
export type TextField = string
export type TextArea = string
export type RichEdit = string
export type Image = {
url: string
width: number
height: number
}
こちらを定義しています。
Image
に関しては画像 API からの返り値に違う Key が追加された時に対応しやすくするためなのですが、
重要なのは上 3 つです。
それぞれ返ってくる値はstring
型で一緒なのですが、それぞれで表示の仕方、加工の仕方が変わります。
表示の仕方からいくとTextField
、TextArea
は jsx の{}で通常通り表示できますが、
RichEdit
から返ってくる値は HTML テキストなので、dangerouslySetInnerHTML
を用いる必要があります。
そして、加工の仕方での違いはTextArea
の改行を<br />
にしたい場合、
String.replace(/\n/g, "<br />");
とする必要があります。
このように同じstring
型ではありますが、扱い方がまるで変わってくるため、
何かしらでわかるようにしておくことをおすすめします。
microCMS の管理画面を見にいけば済む話ではありますが、
typescript を使ったり、aspida を使っている以上、できるだけコードの中で完結させた方が効率がいいですし、コードにドキュメントがある方が便利だと思います。
最後に、個人的な思い
最初のなぜ作ったのかでもほとんど話したのですが、Jamstack や HeadlessCMS をもっと広めたいと考えています!
そう思うに至ったのは、これらの技術のおかげで成長できたと感じているからです。
僕は web 制作会社で働く2年目のエンジニアなのですが、1年目の前半に microCMS に出会って、
いわゆる Jamstack に関わる部分に注力したおかげで、web 全体への理解が深まり、
結果的に社内での信用や立ち位置を強くすることができました。
僕の会社ではもともと WordPress などの CMS を使わない運用をしていたので、
部分的に採用できる microCMS は相性が良かったのも後押ししてくれました。
こんな経験から、僕自身が成長できたのは(勝手に)microCMS や Jamstack という技術のおかげだと思っていて、とても感謝をしています。
だからこそ、今回のソースコードがこれらの技術が広まるきっかけに少しでもなってくれたら嬉しいです。
拙い文章ではありますが、最後までお読み頂きありがとうございます!
間違ってる箇所やご意見あればどしどしコメントやリポジトリに issue 投げてください!
Discussion