stin's Blog

ブログをフルリニューアルした!


すてぃんブログレボリューション 21 (updated)

このブログサイトをフルリニューアルしました!(5 記事しか書いていなかったのにもうリニューアルとかwwというのはそれはそう)

今回はこのリニューアルについて、こだわりポイントと技術的な内容の 2 つを書こうと思います。

こだわりポイント

Web デザイン

リニューアル前のデザインは、情報量が多かったと感じていました。

リニューアル前のトップページのスクリーンショット

ブログサイトによくあるデザインを目指そうと頑張っていたのを記憶しています。ですが、Web デザインの基本に立ち返り、ブログ閲覧者にとって本当に必要な情報量だけを表示することと、「近接・整列・反復・対比」を意識してデザインの再考を行いました。

記事アイテムのサムネイルや、紐付けされた記事数が併記されたタグ一覧、そしてプロフィールエリア。自分のデザイン力の無さも相まってあんまり引き締まって見えません。加えて、記事アイテムのタグリンクのフォントサイズがめちゃめちゃ小さい。 Google Search Console から何度も「小さいから直せ」とメールが届いていましたね。

サムネイルは、明示的に指定できるようにするか記事内に画像 URL があればそれを使うようにする予定だったんですが、実は未実装で NoImage のフォールバック画像しか表示できません(笑)。その機能を追加する前にそもそも記事サムネイルとか必要か?と疑問になり、なくしました。正直言うと実装が面倒。

プロフィールについては誰も興味ないと思うのでばっさりなくしました。そのうち about.stin.ink みたいなプロフィールサイトでも作ってリンクを貼っときます。

ライトモードとダークモードの切り替え機能

もともと暗い背景だったのでダークモードとは?と思われるかもしれません。

これは完全に自己満足です。

リンクカードを表示可能に

Zenn のように URL だけのパラグラフをリンクカードに変換するように実装しました。下のようなやつです。

リンクカード機能はけっこう憧れていたので、リニューアル時には絶対実装したいと思っていました。リンクカードがあるだけでかなりリッチなブログに見えると思います。

Zenn の記事一覧を表示可能に

Zenn のプラットフォームという性質上、広く読んでほしい内容の記事はそちらに書いたほうがいいなと考えました。ただこのサイトに訪問してくれた人に「こんな記事を Zenn で書いてるよ」というアピールをしたかったので、Zenn の記事も含めてトップページに表示しています。決して記事数のカサ増しではない。

技術面について

こちらのトピックのほうが興味がある人が多いかもしれません。

こだわりポイントを実現する方法を中心に記述していきます。

ディレクトリ構成について

src
├── components
│   ├── pages
│   │   ├── Home.tsx
│   │   └── Articles.tsx
│   └── shared
│       ├── Footer.tsx
│       └── Header.tsx
├── lib
│   ├── $path.ts
│   └── posts.ts
└── pages
    ├── _app.tsx
    ├── articles
    │   ├── [slug].tsx
    │   └── index.tsx
    └── index.tsx

(省略ファイル多数有り)

よしこさんの次の記事を参考にしつつ、個人ブログの規模(ステート管理なし、ログインなし、ページ数少ない)や CSS in JS によるファイル数の少なさから上記のような構成にしました。

src/pages の責務はよしこさん同様ルーティングがメインですが、ページのメタデータを埋め込むための SEO コンポーネントだけ設置しています。人の目に触れるビューは src/components/pages で組み立てます。

src/components/shared に置くモジュールは色々なページから利用可能なコンポーネントを想定しています。よしこさんの記事ではアプリのモデルに依存するかどうかでさらに細分化していますが、個人ブログの規模ならそこまで細かくする必要はないかと思います。

Chakra UI でスタイリング

コンポーネントライブラリの Chakra UI を導入しました。 CSS を模した props を指定することでスタイリングする Chakra UI の手軽さが手放せなくなっています。

<Box fontSize="2xl" color="purple.500">
  foo
</Box>

ダークモード・ライトモードの切り替えも Chakra UI に乗っかればまったく苦労することなく実装することが可能です。現在選択中のモードを取得したり、モードに応じて値をリアクティブに切り替えるカスタムフックも用意されています。

const { colorMode, toggleColorMode } = useColorMode();
const fontColor = useColorModeValue("black", "white"); // light mode の時は第1引数を、 dark mode の時は第2引数を採用する

return (
  <Button onClick={toggleColorMode} color={fontColor}>
    {colorMode} mode
  </Button>
);

そして、僕が一番 Chakra UI のいいと思う点は「Chakra UI 臭くならない」ということです。

Material Design 実装の MUI(Material UI) を使うとどうしても「マテリアルデザイン臭さ」が残る気がします。うまく消すか活かすかできればいいのですが、かなりデザイン力が求められると思います。

一方 Chakra UI のコンポーネントは癖のないシンプルなデザインをしていることに加え、 props でさくっとスタイルを調整できるので 「Chakra UI 臭さ」というのがほとんどないのではないでしょうか。(気づく人は気づくかもしれませんが)

Next.js の Incremental Static Regeneration を使ってみる

個人ブログなので頻繁な更新はありません。なのですべてのページを getStaticProps によってビルド時生成しています。

ですが今回 Zenn の記事一覧表示機能追加によってランタイムの更新が必要になりました。 Zenn に記事を投稿した後、このブログサイトで Zenn のデータを表示しているページを再ビルドしないといけません。

どうせ Zenn もそんなに更新しないんだから都度手でビルド実行でいいでしょ、と思われるかもしれません。そのとおりです。でも、自動化できることはすべて自動でやっといてほしいというのがエンジニアの性です。知らんけど。

ということで、 Zenn の記事を表示するページの getStaticProps からは revalidate を返すようにします。具体的には以下の 2 箇所。

revalidate 間隔は 1 日としました。これで Zenn を更新した次の日までにはこのサイトも更新されるはずです。

Zenn の記事取得方法

Zenn は RSS フィードをユーザー別に用意してくれています。 (ex: https://zenn.dev/stin/feed)

これを取得して parse して記事一覧に表示するだけですね。

npm には rss-parser というドンピシャなライブラリがあります。これを使って RSS フィードを parse して、通常の記事データとインターフェイスを揃えて返すだけで実現できます。

リンクカードの実装方法

リンクカードにはリンク先のメタデータが表示されます(主に OGP 系)。リンク先のメタデータは HTML に埋め込まれているので HTML を GET して parse して値を抽出するのですが、当然ブラウザの JavaScript からリクエストを送信しても CORS 違反で弾かれます。

そこで、Web サイトの URL を渡すと、代わりにサーバーからリクエストを送信したあと HTML からメタデータを抽出して JSON に詰め込んで返す API を Next.js で用意しました。

HTML の parse には、 Node.js 環境でもブラウザの DOM 操作と同じインターフェイスを提供してくれる jsdom を使用しました。(このようなサイトのメタデータを収集して返してくれて誰でも Welcome な Web API、誰か用意しれくれていないのだろうか…🤔)

リンクカードコンポーネントでは、上記の API に URL を添えてリクエストを送信し、レスポンスの JSON に色を付けるだけです。

HTTP リクエストの先で HTTP リクエストを行っているため、表示は遅いです。そのためローディングスケルトンを表示しています。ここだけいわゆる Client Side Rendering ですね。

複数人がブログを閲覧する際、同じサイトのメタデータを何度も抽出する作業を行うためとても非効率なのですが、 Next.js API のキャッシュってできるのでしょうか…。どなたかご存知なら教えていただけると幸いです 🙏

今後の展望

今後の機能拡張の展望です。

  • Twitter や Instagram などの Embed 要素を URL から生成
  • ブラウザ上で記事を編集できるように Markdown エディターを搭載
  • next-seo の使用検討
  • RSS フィード取得ページ
  • サイトマップとか?

予定は未定です。(TODO:後で実装 と同等)

まとめ

すてぃんのブログをリニューアルして、その内容や技術面についてお話しました。 Next.js と Chakra UI 依存症はしばらく治りそうにありません。

さて、ブログをリニューアルしてブログの更新頻度は上がるのでしょうか?乞うご期待!