なぜ分割するのか
このブログは個人の記録サイトに過ぎませんが、それでも「クリーン、軽量、安定」であることを望んでいます。特に:
- 初回読み込み時に不要なものを読み込まない
- 記事閲覧ページを可能な限りスムーズに保つ
- コードハイライトやTOC(目次)のような「必須ではない」機能は後回しにする
読み込み戦略:軽いものを先に、重いものは後に
1) ルートレベルのレイジーロード
BlogList / BlogDetail は React.lazy によって分割されています。
ユーザーが実際にBlogセクションに入った時のみ、関連コードが読み込まれます。
2) データレイヤー:リストはメタ情報のみ取得
リストページではタイトル、抜粋、カテゴリ、公開日などのメタ情報のみを必要とします。
記事の本文は、詳細ページに入った時に初めて取得されます。
また、Markdownの解析が重複しないよう、ローダーにキャッシュを追加しました。
3) 詳細ページの「選択的読み込み」
詳細ページではまず構造と記事ヘッダーをレンダリングし、本文(Markdownレンダラー)は非同期で読み込みます:
react-markdown/remark/rehypeは遅延読み込みされます- コードハイライトコンポーネント
react-syntax-highlighterは、コードブロックがある場合のみ読み込まれます - TOCの解析(
extractTOC)も動的import内で実行されます
これにより、メインコンテンツがより早く届き、重いリソースは後から読み込まれるようになります。
レンダリング戦略:軽量なレンダリング、重厚な効果
Markdown レンダリング
- コンテンツは
ReactMarkdownによってレンダリングされます remark-gfmによりテーブルやタスクリストをサポートrehype-slugで見出しにアンカーを生成し、TOCを使いやすくします
コードブロック
コードブロックのレンダリングは、ハイライトコンポーネントの読み込みをトリガーします。
ハイライトがまだ読み込まれていない場合は、まず基本的な pre スタイルを表示し、読者を待たせないようにします。
画像
画像は統一コンポーネントで処理され、デフォルトで lazy/async 設定になっています。
これにより、本文のレンダリングが画像によってブロックされるのを防ぎます。
私が気にしているのは「速さ」ではなく「管理可能であること」
極限のパフォーマンススコアを追求しているわけではありませんが、以下のことを望んでいます:
- 初回読み込みが管理可能であること
- レンダリングパスが明確であること
- 体験が突然重くならないこと
そのため、今回の最適化は単なる圧縮や高速化ではなく、一種の「秩序」に近いものです。
まとめ
この戦略の核は一言に尽きます:
「後回しにできるものは後回しにし、オンデマンドで読み込めるものはオンデマンドで読み込む」
これは個人サイトに適しており、私の好みにも合致しています。