Cut0 Blog

Next.js + microCMSで個人ブログを開発した。〜技術スタック〜

はじめに

はじめまして。この度、個人用ブログを開発した Cut0 と申します。今後は本ブログを通して技術的なことや、そうでないことを適当に発信しようと考えています。
今回は本ブログで利用した技術について解説しようと思います。そのため、詳細なブログの作り方は別の記事で解説しようと考えています。

パッケージ

利用したパッケージに関してメジャーなものを説明します。

Next.js

TypeScript と Hooks を利用したモダンな構成にしております。当初は 20 件までのデータを getStaticProps 発火時(ビルド時)に取得し、それ以上のデータは IntersectionObserverカスタムフック を利用して取得することで無限スクロールを再現しようと考えておりましたが、useSWRInfinite でのキャッシュが難しいケースであるため(私の実装が悪いだけかもしれませんが)、ビルド時に全件取得をおこなっています。
https://nextjs.org/docs/basic-features/data-fetching/get-static-props
https://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API
https://swr.vercel.app/ja/docs/pagination
また、Next.js に関しては、以下に挙げるような Vercel との親和性を考慮して採用しました。

  • main ブランチマージ時に自動的にデプロイが走る点
  • PR 作成時にプレビューサイトを生成してくれる点
  • next/image の最適化

Next.js 自体も非常に良いフレームワークだと思っており

  • webpack の細かい設定を隠蔽してくれる。
  • SSG が簡単。
  • かといって厚すぎないフレームワークである。

また、Gatsby はブラックボックスな点が Next.js に比べて多く Shadowingも今回のケースでは必要なかったため、採用しませんでした。
https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/shadowing/

SWR

キャッシュを可能な限り最新に保つという思想や、サーバーのレスポンスのキャッシュに関するロジックを薄くできるという点が好みで採用しました。useSWR に関しては第三引数のfallbackData に初期値を入れて利用することができます。本ブログでは前述のビルド時に取得したデータを fallbackData に入れているため、undefined の状態で画面がレンダリングされなくなっており、レイアウトシフトを軽減しています。
https://swr.vercel.app/ja/docs/prefetching
SWRに関しては以下の記事が非常に参考になりました。
https://zenn.dev/uttk/articles/b3bcbedbc1fd00
https://zenn.dev/yoshiko/articles/607ec0c9b0408d

vanilla-extract

下記の理由から採用しました。

  • ビルド時に CSS が生成され、パフォーマンスに期待ができる。
  • *.css.tsにコードを書くため、比較的型安全に CSS を記載できる。
  • ライブラリ特有の記法が少なく生の CSS に近いため、他のライブラリにスタリングを移行する際にも比較的簡単である。

Tailwind CSS や styled-components に比べるとまだまだ成熟していないと思いますが、今回は少しチャレンジングなこともしたかったですし、使い勝手も好みだったため採用して良かったと感じております。
余談ですが PLAID さんのプロダクトでも採用されているようです。
https://tech.plaid.co.jp/karte-blocks-vanilla-extract-adr

microCMS

ぶっちゃけてしまうと、ヘッドレスCMSに関してはあまり比較せずに採用してしまいました。ただ、microCMS は日本製であり、チュートリアルが非常に充実しています。(単にブログを開発するというケースではチュートリアルを参考にするのがベストかもしれない、、、)
また、microcms-js-sdk の完成度が非常に高く、データ取得に関する HTTP のロジックを直接書かずに済み、それでいて比較的型安全に開発できました。
https://blog.microcms.io/microcms-next-jamstack-blog/
https://github.com/microcmsio/microcms-js-sdk
ただ、API スキーマでリッチエディタを利用してしまうと API が Html を返してしまい、後述の Zenn 対応がうまくいかなくなってしまうため注意が必要です。

Zenn 対応

今後 Zenn でも投稿するような記事を書く可能性があったため(未定です。)、採用しました。採用したライブラリは zenn-markdown-htmlzenn-embed-elementzenn-content-cssとなります。
下記の記事が非常に参考になりました。
https://zenn.dev/waddy/articles/intro-zenn-markdown
ただ、現時点で zenn-markdown-htmlmarkdownToHtml はサーバーサイドでのみ動かすことができるようなので、こちら のような実装に落ち着きました。
https://githubhot.com/repo/zenn-dev/zenn-editor/issues/183
zenn-embed-element に関しては下記ドキュメントを参考にし、zenn-content-css は記事をマウントするコンポーネント内で import "zenn-content-css" のように利用すれば問題ないと思います。
https://www.npmjs.com/package/zenn-embed-elements

CI/CD

Jest

テスティングフレームワークとして Jest を採用しました。各ビジネスロジックに対して Unit Test を書く方針で開発しています。

Vercel

前述の通り、PR 作成時と main ブランチにマージした際に走ります。プレビューサイトを生成したり、デプロイを自動でやってくれたりと非常に使い勝手が良いです。
ただ、Vercel は Node.js の 16系に対応しておらず、MSW は16系以降を必要としているため利用を断念しました。
https://github.com/vercel/vercel/issues/7004

GitHub Actions

主に二つの機能を採用しています。
一つ目は PR を作成した際に、型チェックや lint、テストを行う機能です。
もう一つは、Vercel がプレビューサイトを生成した際 Lighthouse のスコアを計測し該当する PR にコメントする機能です。これらにより、プロダクトの品質を保つことができます。Lighthouse のスコア計測に関しては下記の記事を参考にしました。
https://dev.to/oskarahl/automated-lighthouse-score-on-your-pr-with-vercel-and-github-actions-2ng2

今後に関して

今後もまだまだ新機能開発やプロダクト改善を行おうと考えております。
具体的には

  1. 記事投稿時、更新時に自動でサイトをビルドしていない。これにより、getStaticPropsが発火しないため、古いキャッシュが残ってしまう。
  2. 新規機能の開発フローが整っていない。
  3. UIコンポーネントの管理が甘い。

というのが改善点として挙げられます。

現時点では未定ですが、それぞれ次のような対処法を取ろうと考えています。

Webhook の利用

ドキュメントによると Webhook を利用できるようなので試してみようと思います。
https://document.microcms.io/manual/webhook-setting

フィーチャーフラグを利用したトランクベース開発

現時点でもトランクベース開発寄りの開発を心がけていたのですが、効率よくフィーチャーフラグを管理できていないため何かしら考える必要がありそうです。
https://developers.cyberagent.co.jp/blog/archives/31837/

Storybook の採用

個人的に今後プロダクトが肥大化した際に Storybook のようなコンポーネントを視覚的に確認できるものが必要だと考えています。ただし、本ブログは個人的な開発ですので、試験的に Ladle を採用するのもありかもしれません。
https://www.ladle.dev/

最後に

ここまで読んでくださり、ありがとうございます。本ブログは下記に公開しておりますので、改善点や問題点、質問など issue に投げてくださるとうれしいです!
https://github.com/Cut0/cut0-blog