Slide 1

Slide 1 text

2万ページのSSG運用における 工夫と注意点 2024/10/19 まぁし / 知念

Slide 2

Slide 2 text

前提の共有 CSR / SSG / SSR / ISR / PPR

Slide 3

Slide 3 text

ビルド・レンダリングのパターン ● CSR(Client-side Rendering) ● SSG(Static Site Generation) -------------------------------------------------------------- ● SSR(Server-side Rendering) ● ISR(Incremental Static Regeneration) ● PPR(Partial Pre-Rendering) Hosting環境と フレームワークの黎明期 static generatorの時代 Hosting環境と フレームワークの普及後

Slide 4

Slide 4 text

ReactのCSR→RSCへの課題解決の歴史が参考になる 引用:https://www.builder.io/blog/why-react-server-components

Slide 5

Slide 5 text

株式会社TAM/TAMTO:フロントエンドエンジニア 兼 個人事業主 知念 昌史 / まぁし X @chocodogmagic ● Vue.js / Nuxt / Next.js / セマンティックHTML / PWA / アクセシビリティ ● コミュニティ運営(沖縄)v-okinawa (東京)PWA Night、MT東京、CSS福笑い ● 平日 9:00〜おはようエンジニア #ohayo_engineer(780回くらい) ○ X(旧Twitter)スペースでWeb関連のラジオ発信中、フォローしてね ● ゲーム好き ○ スプラトゥーン3(トライストリンガー/ハイドラント XP2050) ○ ポケモンSV スカーレット

Slide 6

Slide 6 text

https://www.tam-tam.co.jp/ フロントエンドエンジニア採用強化中!!

Slide 7

Slide 7 text

Vue.js / Nuxtの実績を一緒に作りませんか クラウドワークス様 GLOBIS様 SACCSY様 メディカ出版様 藤子・F・不二雄ミュージアム様

Slide 8

Slide 8 text

このスライドで話すこと 1. 前提の共有 CSR / SSG / SSR / ISR / PPR 2. なぜNuxt 3のSSG構成にしたか 3. SSGで発生した問題 4. 解決までに試したこと 5. SSGにおける注意点

Slide 9

Slide 9 text

なぜNuxt 3のSSG構成にしたか

Slide 10

Slide 10 text

技術選定(2021年頃) ● 翌年にNuxt 3リリース(2022年4月RC → 6月→11月) ● 社内でNuxt 2の実績は多かった(当時はCSR or SSG) ● バージョンアップのリスク(Nuxt 2→3) ● Hosting・ビルド環境の検討(当時NuxtのSSRがまだ不安) Nuxt 3 + SSG構成が良さそう (Nuxt 2の実績として2,000ページほどの生成10分)

Slide 11

Slide 11 text

WebサイトのJamstack 構成図 Headless CMS + Webフレームワーク → GitHub Actions → S3/CloudFront エンジニアがコードを更新 
 (git push)
 Web担当者がページ更新 
 (Webhook)
 GitHub Actionsでbuildコマンド実行 
 SSGでファイル生成してS3へ転送 
 S3に静的ファイル設置 
 CDN(Cloudfront)で配信 


Slide 12

Slide 12 text

問題発生:生成にかかる時間が長い

Slide 13

Slide 13 text

1500ページの生成で80分オーバー GitHub Actionsで generateを実行すると完了まで約80分 ※ローカルでは40分だったが本番運用を想定した環境では2倍 エラー対策やインフラの課金を抑えるため60分超で停止するようにしていた → 公開できない!!!

Slide 14

Slide 14 text

原因調査

Slide 15

Slide 15 text

原因調査 1. 重いコンポーネントがないか 2. CMSデータのフェッチ処理 3. Nuxtの設定(configやgenerateのオプション) 4. サーバー・インフラの設定

Slide 16

Slide 16 text

コンポート調査でデータフェッチの重複を発見 コンポーネントに重い処理はなかった(Webサイトなので記事のタイトルや本 文、フィールドの文字列の取得がほとんど) Nuxt 3では各コンポーネント内でもデータフェッチが可能になったため コンポーネント単位でAPIへリクエストしていた ※Nuxt 3ではuseFetch()、useAsyncData()がcomposableとしてどこでも使える ※v3.0の頃はキャッシュがうまく効かず、payloadが機能しなかった

Slide 17

Slide 17 text

データフェッチの重複 pagesコンポーネントで取得して、propsで各コンポーネントに渡すよう 処理を変更(ローカルで40分→20分へ短縮したがサーバー上では80分→60分) ComponentA.vue ComponentB.vue pages/index.vue

Slide 18

Slide 18 text

ビルド時間80分→60分へ改善👏

Slide 19

Slide 19 text

ローカルとGitHub Actionsで2〜3倍の差がある ローカルでは平均して1ページあたり生成1秒(25分)なのに対し、 GitHub Actionsのログでは1ページ3〜4秒かかっている(60分) Linuxからmac OSに変更してみるが・・・効果は出なかった ↓ フェッチ〜レスポンスまでの時間がかかっているのでは? 日本のmicroCMSに対してGitHub Actionsは海外からのアクセスになる? ↓ ビルド処理をAWSのCodeBuildやAmplify に変更してみる → 短縮した!

Slide 20

Slide 20 text

ビルド時間60分→25分へ改善👏

Slide 21

Slide 21 text

さらにフェッチを減らす 記事のカテゴリ情報のようなデータはTOPページだけでなく一覧ページ、詳細 ページ、共通のナビゲーション等、多くの場所で使用している ビルド開始時にjsonファイルを生成し、generateのタイミングではデータフェッ チせずにローカルのjsonを参照する → 1ページあたり0.7秒台へ(25分→15分) 記事データもすべてjson化しようとしたが数千件で JavaScript heap out of memory😇 ・・・このあたり詳しい方、あとで話しましょう

Slide 22

Slide 22 text

事前データ生成のイメージ package.json getCMSData.mjs

Slide 23

Slide 23 text

ビルド時間25分→15分へ改善👏

Slide 24

Slide 24 text

3000ページのビルド時間 80分超→15分へ改善👏 (2万ページに増えても25分)

Slide 25

Slide 25 text

ビルド時間削減までのまとめ 1. データフェッチするタイミングを絞る 2. APIとビルド環境はリージョンを合わせておく 3. 固定の情報は事前に別ファイルとして用意しておく ※Nuxt最新バージョンなら解決できそう(まだ試せていない) ● フェッチしたデータをキャッシュしてくれる ● payloadによってビルド時間をさらに短縮

Slide 26

Slide 26 text

SSGにおける注意点

Slide 27

Slide 27 text

注意!! ビルド開始してから実際にユーザーが見れるまで数分の差がある ● 公開したものに修正が発生しても直るまで時間がかかる ○ URLのミス等はビルド自体もエラーになる ● 複数ページのうち1つでもデータ取得失敗したらビルドエラー ● 時間ぴったりに公開ができない(予約投稿もずれる) ● 他のサイトからAPI参照して連携したときに時差が発生する

Slide 28

Slide 28 text

注意:Build中に記事を更新したらエラー Buildの途中でCMSの記事を非公開にすると、タスクはその記事を生成しようとす るがCMSにデータが無いのでエラーとなる(運用でカバーもできるが・・・) → 変更が発生した場合、現在の処理を止めて再Buildし直す仕組みが必要 Webhookで再実行し、GitHub Actionsでconcurrencyでキャンセルする 例えばVercelではQueueで順番に処理してくれる

Slide 29

Slide 29 text

注意:ネットワークエラーやAPIの500系エラー 生成するファイル数だけフェッチするデータの量が増える 仮に2万ページのサイトで1ページ1リクエストだとしたら、 2万回のリクエストのうち一度でもエラーが発生するとBuildが失敗する ● タイムアウトしないようDBへの処理に負荷がかかるものは避ける (全件取得など) ● microCMSにはリトライオプションがある(2回まで再リクエストする) ● リクエスト数制限にかからないよう処理にインターバルを挟む

Slide 30

Slide 30 text

注意:他サイトからリアルタイムに取得すると困る サイトA:SSG サイトB:CSR(もしくはSSR) このような構成でサイトAを更新すると完了まで 数分のBuildが走るが、サイトBは更新した時点で リアルタイムにAPIから取得して情報を表示する サイトBからサイトAへリンクしているとBuildが終 わるまで404になる ※APIではなくSSG時点でjsonを生成して参照する サイトA サイトB 記事 記事 記事3 ・記事リンク1 ・記事リンク2 ・記事リンク3 ・記事リンク4 記事4 生成中...

Slide 31

Slide 31 text

まとめ

Slide 32

Slide 32 text

Webサイトの構成・運用に合わせて検討すること ● 即時性の求められるWebサービスやWebアプリはSSGに向かない ● WebサイトならSSGはパフォーマンス・SEO・インフラ低コスト・ ユーザー体験が最強、だが・・・ ○ 即時更新が必須なら困る(キャンペーンやIR情報など) ○ 週1くらいの頻度で更新するなら困る(年に数回なら良い) ○ 数千ページを超えるような構成には困る(ビルド長時間) SSR/ISRにしよう!

Slide 33

Slide 33 text

とはいえ ● ビジネス上の理由もありSSGを選択せざるを得ないこともある ○ Vercel利用申請通らないとか ○ オンプレ使って〜とか ○ 既存のS3に置いて〜とか ○ 今までレンタルサーバーだったし〜とか SSGの課題を事前に共有してしっかり対策しておこう!

Slide 34

Slide 34 text

SSGの運用で困ったら この登壇を思い出してね

Slide 35

Slide 35 text

ご清聴、ありがとうございました! X(旧Twitter) まぁし@chocodogmagic 平日9:00〜スペースでWeb情報発信中! Web制作/Webアプリ開発ご依頼ください TAMはフロントエンドエンジニア採用中!