Next.js App Router 多言語サイトの SEO を改善した記録
canonical の重複エラーをきっかけに SEO を棚卸し。サイトマップの漏れ、構造化データの不足、OG 画像の欠落など、Next.js App Router + 多言語構成で踏んだ落とし穴と修正を記録した。
「nextjs」タグが付いたコンテンツ一覧
canonical の重複エラーをきっかけに SEO を棚卸し。サイトマップの漏れ、構造化データの不足、OG 画像の欠落など、Next.js App Router + 多言語構成で踏んだ落とし穴と修正を記録した。
Velite に新しいコレクションを定義し、既存コンポーネントを最小限の適応で再利用して TIL セクションを実装。検索統合まで含めて、新しい依存関係はゼロだった。
再利用できる3つのパターン:Velite の default(false) による安全なスキーマ拡張、MAX_TAGS によるタグ溢れ対策、空のとき自動的に消えるセクションの条件付きレンダリング。
カテゴリとタグの共通性でスコアリングするシンプルなアルゴリズムで関連記事を表示する。ML も全文検索も不要 — メタデータの重み付けと既存関数だけで十分だった。
個別ページはあるのに一覧がなかった問題を解決。データ層のコードは一切追加不要 — 既存のヘルパー関数がそのまま新ページに組み合わさった。
opengraph-image.tsx と Satori でビルド時に記事ごとの OG 画像を静的生成する。最大の落とし穴は Satori のインラインスタイル制約 — Tailwind も className も使えない。
ハンバーガーメニュー、レスポンシブスペーシング、タッチターゲットを追加。最大の学びは、CSS の backdrop-filter が fixed 子要素の包含ブロックを暗黙的に作るという仕様だった。
壊れていた3段階ビルドを @serwist/turbopack の Route Handler ベース設計に置き換え、プリキャッシュを修復しつつ Turbopack を有効化した過程と、そこから得た知見。
shinyaz.com のアーキテクチャを深掘り — Contentlayer ではなく Velite を選んだ理由、i18n ライブラリなしで日英対応を実現した方法、ミニマルなモノトーンブログの設計判断を紹介する。
Next.js App Router で /ja/存在しないページ にアクセスすると /en にリダイレクトされてしまう問題。[...slug] catch-all ルートの追加とルートの not-found.tsx の修正が両方必要だった。
src/lib/i18n.ts を src/lib/i18n/index.ts に分割した際、@/lib/i18n からのインポートがそのまま動作した。Node.jsのモジュール解決でindex.tsが自動的に参照される。
タグ/カテゴリの詳細ページから一覧ページへ戻る導線がなく、ブラウザバックに頼るしかなかった。i18n辞書にキーを追加し、headerの直前にLinkを配置して解決した。
タグページの generateStaticParams と表示ロジックがブログ記事のみを参照していたため、TIL にしか存在しないタグが 404 になっていた。getAllTags に TIL のタグも統合して解決した。
Aboutとは別にColophonページを用意することで、サイトの技術スタックや設計方針を整理して公開できる
link rel=alternateだけではユーザーにRSSフィードの存在が伝わらない。フッターにアイコンとテキストリンクを追加して解決した
mermaid ライブラリは DOM API に依存するため Server Component では使えない。dynamic import + useEffect でクライアント描画し、next-themes の resolvedTheme でダークモードにも対応できる。
MDX のコードブロックで言語を省略すると rehype-pretty-code のレンダリングが崩れる。```text のように必ず言語を指定する必要がある。
'use cache' ディレクティブを使うと、fetch に限らず任意の非同期関数の出力をキャッシュできる。従来の fetch レベルのキャッシュオプションに代わる新しい仕組み。