Upgrade to Pro — share decks privately, control downloads, hide ads and more …

純SPAでNext.jsに対抗する 〜ページによってmetaタグを切り替える編〜

kiyoshiro
September 12, 2023

純SPAでNext.jsに対抗する 〜ページによってmetaタグを切り替える編〜

純SPAではNext.jsとは異なり、基本的にひとつのindex.htmlを用いるため、ページによってmetaタグを切り替えるのが難しい。このスライドでは、CloudFrontやLambda@Edgeなどを使って純SPAでもページによってmetaタグを切り替える方法を4つ紹介する。

kiyoshiro

September 12, 2023
Tweet

More Decks by kiyoshiro

Other Decks in Programming

Transcript

  1. © DMM.com 自己紹介
 2 名前
 清川航一 (𝕏 @kiyoshiro944)
 おしごと
 おもにフロントエンド(React/TypeScript)

    
 バックエンドも書く(Golang) 
 所属
 
                   ポイントクラブチーム 
                   新卒2年目 
 
 
 

  2. © DMM.com 前提:用語の定義
 • SPA
 • ※人によって定義が違う😇
 • CSRしかしていないアプリ
 •

    CSR / SSR / SGを1つ以上組み合わせたアプリ
 • 純SPA
 • CSRしかしていないアプリ
 • 例:Create React AppやViteで作ったアプリ

  3. © DMM.com (色々あるけど、今回取り上げるのは) 
 「ページによってmetaタグを切り替える」
 metaタグの例:<meta name="og:description" content="ページの説明" />
 •

    Next.jsではページごとにHTMLを生成するのが簡単
 /users → users.html
 /posts → posts.html
 
 • 純SPAだと、基本的にページによらずひとつのindex.htmlを使う
 /users → index.html
 /posts → index.html
 
 純SPAだとムズいこと

  4. © DMM.com 「ページによってmetaタグを変えたい」の解像度を上げる
 • 動的か静的かの2種類に分類できる
 
 
 
 
 


    • 静的のほうがインフラ構成などが楽
 動的
 静的
 パターン数が多すぎて事前生成ができないのでリ クエスト時に実行する 
 
 例:/posts/1, /posts/2, …/posts/9999 
 でmetaタグを変える 
 パターン数が少なく事前生成できる 
 
 例:/aboutだけmetaタグを変える 

  5. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 ?
 ?
 ?
 ?
 インフラ
 構築難度
 ?
 ?
 ?
 ?
 保守難度
 ?
 ?
 ?
 ?
 その他
 
 
 
 
 ※dynamic-rendering以外の名称は自分が適当に考えました
  6. © DMM.com Lambda@Edge + CloudFront + S3の場合
 方法1:dynamic rendering(インフラ例)
 キャッシュの有無に関わらず、

    
 リクエストのたびに必ず実行される 
 • キャッシュヒットしなかったときだ け実行される
 • ここで返したレスポンスはキャッ シュされる

  7. © DMM.com 方法1:dynamic rendering
 😩BAD
 • 最初にインフラ構築するのが大変
 bot判定・ユーザーとbotでキャッシュの分離・ヘッドレスブラウザの実行etc… 
 •

    Google曰く、インフラが複雑になるので「回避策」
 • 回避策としてのダイナミック レンダリング | Google 検索セントラル
 • Next.jsとかのSSRと比べてレスポンスが遅くなりがち
 
 
 • Google Botへのレスポンスが遅くなると SEOに悪影響が(CoreWebVitals)
 • CloudFrontなどCDNのstale-while-revalidate機能 を使うと軽減できそう 
 
 ※キャッシュヒットしなかったとき
  8. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 ?
 ?
 ?
 インフラ
 構築難度
 ✕難
 ?
 ?
 ?
 保守難度
 ◎必要なし
 ?
 ?
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  9. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 ?
 ?
 ?
 インフラ
 構築難度
 ✕難
 ?
 ?
 ?
 保守難度
 ◎必要なし
 ?
 ?
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  10. © DMM.com 方法2:head-only SSR
 😄GOOD
 • dynamic renderingよりもインフラ構成が楽&レスポンスも早い
 😩BAD
 •

    保守性:ページが増えるたびにエッジ関数に追記してデプロイする必要あり
 例:/posts/:idに加えて、/users/:idパスが増えたらエッジ関数に追記 
 • SEO:ページのコンテンツはレンダリングしない
 

  11. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 エッジ関数でmeta タグを注入した HTMLを返却
 ?
 ?
 インフラ
 構築難度
 ✕難
 △微難
 ?
 ?
 保守難度
 ◎必要なし
 ✕大変
 ?
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  12. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 エッジ関数でmeta タグを注入した HTMLを返却
 ?
 ?
 インフラ
 構築難度
 ✕難
 △微難
 ?
 ?
 保守難度
 ◎必要なし
 ✕大変
 ?
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  13. © DMM.com 方法3:head-only SG
 ↑index.html
 ↓そこから生成したabout.html 
 例:/aboutページだけmetaタグを変えたい場合 
 インフラ


    /aboutでアクセスされたらabout.htmlを参照するよう に設定
 
 ビルド時
 /aboutページ用のabout.htmlを作る 
 (headタグだけ注入)

  14. © DMM.com 方法3:head-only SG dist
 ├ index.html
 ├ …
 dist


    ├ index.html
 ├ about.html
 ├ …
 ビルド スクリプト実 行 metaタグ注入

  15. © DMM.com 方法3:head-only SG
 😄GOOD
 • head-only SSRよりもインフラ構成が楽
 • /aboutを/about.htmlにルーティングするだけ


    😩BAD
 • 保守性:アプリコードとは別に、head注入するスクリプトを保持する必要あり
 • SEO:ページのコンテンツはレンダリングしない
 

  16. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 エッジ関数でmeta タグを注入した HTMLを返却
 ビルド時にmetaタグを 注入したHTMLをつくる 
 ?
 インフラ
 構築難度
 ✕難
 △微難
 ◯簡単
 ?
 保守難度
 ◎必要なし
 ✕大変
 △普通
 
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  17. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 エッジ関数でmeta タグを注入した HTMLを返却
 ビルド時にmetaタグを 注入したHTMLをつくる 
 ?
 インフラ
 構築難度
 ✕難
 △微難
 ◯簡単
 ?
 保守難度
 ◎必要なし
 ✕大変
 △普通
 
 ?
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 

  18. © DMM.com 方法4:static prerendering
 😄GOOD
 • head-only SGと同様、インフラ構成は楽
 • Botからのアクセス時に/aboutへのリクエストを/about.htmlにルーティングするだ

    け
 • SEO:ページコンテンツもレンダリングできる
 😩BAD
 • 保守性:アプリコードとは別で、ヘッドレスブラウザを実行するスクリプトを保守する必 要あり
 • ビルド時間:ヘッドレスブラウザを動かす分、時間がかかる
 

  19. © DMM.com 4種類の方法一覧
 
 動的(リクエスト時に実行) 
 静的(ビルド時に実行) 
 方法
 dynamic

    rendering
 head-only SSR
 head-only SG
 static prerendering
 概要
 botからアクセスされたとき だけヘッドレスブラウザでレ ンダリングしたHTMLを返却
 エッジ関数でmeta タグを注入した HTMLを返却
 ビルド時にmetaタグを 注入したHTMLをつくる 
 ビルド時にヘッドレスブ ラウザでHTMLを生成す る
 インフラ
 構築難度
 ✕難
 △微難
 ◯簡単
 ◯簡単
 保守難度
 ◎必要なし
 ✕大変
 △普通
 △普通
 その他
 😄ページコンテンツも レンダリング
 😩不安定で遅い
 
 
 😄ページコンテンツもレ ンダリング
 

  20. © DMM.com • 面倒なので、最初からNext.jsを採用しよう
 • ページによってmetaタグを切り替えられる以外にもメリット多い
 • zero config
 •

    viewportに入ったリンクのprefetch
 • 画像/フォント/外部scriptの読み込み最適化
 • etc…
 とはいえ・・・