Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

SSG is a compiler

sadnessOjisan
November 27, 2021

SSG is a compiler

sadnessOjisan

November 27, 2021
Tweet

More Decks by sadnessOjisan

Other Decks in Technology

Transcript

  1. 言葉の定義
 - SST
 - CSR
 - SSR
 - SSG 


    
 
 n番煎じな話なので詳細には立ち入りません。 
 それぞれのパフォーマンス上の特性は @takepepe さんの 「より速いWebを目指す Next.js」にまとまっており、こちらを参照してください。 
 また、これらは完全に分離できるものでもないことを断っておきます。 
 ex) template に react を CDN 経由で読み込んだものはどれ? https://speakerdeck.com/takefumiyoshii/nextjs-make-the-web-faster
  2. SST: Server Side Templating
 - Server で HTML Template に値を埋め込み、HTML

    を生成してクライアントへ返す
 - 素直な構成だと TTFB の遅さが問題になりがち
 - 一方で後述するCSRと比較し、通信の往復は減る

  3. CSR: Client Side Rendering
 - サーバーから取得したデータを元に、コンテンツの 描画をクライアントサイドで完結させる
 - TTFB は速いが、LCP

    を悪化させる要因を含む
 - コンテンツ描画のためにはクライアントでのデータ取得が 必要
 - HTML / Styling を生成する仕事はクライアントが担う 
 - コンテンツのアップデートにはHTMLを取得しなくて いいため SST より効率的になる

  4. SSR: Server Side Rendering
 - サーバーからテンプレートに値が埋め込まれた HTMLを受け取る
 - クライアントでそのHTMLは hydration

    される
 - hydration 後は CSR できる
 - SST における TTFB 周りのデメリットは引き継 ぐが、CSRの良いところを享受できる

  5. (re)hydration
 - dehydration
 - JS世界にあるVDOM を HTML に変換する処理 
 -

    SSR サーバーがクライアントにHTMLを返す 
 
 - (re)hydration
 - HTML を JS の世界で使えるように戻す処理 
 - Client ライブラリが実行する 

  6. SSG: Static Site Generation
 - サーバーはリクエストに対してHTMLを返すだ け
 - HTMLをリクエストより前に生成しておく
 -

    ビルド時の静的コンテンツとして固定されるデメ リットはある
 - しかしツールによっては hydration して dynamic な性質を取り込み、そのデメリットを回 避する 

  7. SSG: Static Site Generation
 - 歴史は長い
 - 2000年前半 Database Driven

    な Site への対 抗として SSG が注目される
 - props: DBアクセスの削減 / TTFB の削減 
 - cons: ページ数に応じたビルドコスト 
 - これまでに多くのツールが開発されている
 - 興味がある人は jamstack.org にあるまとめサイトを チェック 
 https://jamstack.org/generators/ 

  8. 現代的なSSG
 - SSR FW や JS ツールチェインの上に作られる
 - hydration +

    CSR の要素がある
 JS ツールチェインの上に作られることで、transpiler, bundler, compressor などの恩恵が受けられる 
 ex) Next, Gatsby, Nuxt, … 

  9. hydration ≠ JS FW
 - wasm によって任意の言語で SSR + hydration

    が可能
 - 技術的には hydration 付きの SSG も可能である

  10. SSG に対する批判
 全てが静的に決まらないと使えない
 Twitter を SSG で作れますか? 
 現代的なSSGでCSRすれば対処できるケースも多い
 EC

    の商品ページを静的生成、在庫はCSRで取得 
 要件によってはCSRでも難しい
 C to C のECでページ作成が頻繁、通報された商品はページごとは消したい 

  11. SSG is meta-compiler
 - Web performance 101
 - 2017年の Gatsby

    作者のブログ 
 - Gatsby is meta-compiler 
 - Gatsby は普通のサイトを速いサ イトへと変換する
 - Gatsby は webpack の設定ファイ ルを生成している
 https://www.gatsbyjs.com/blog/2017-09-13-why-is-gatsby-so-fast/
  12. 複雑な名前はchunkの規則
 - ${key}-${hash}
 - app-44f67102fd3fe7d6ed63.js 
 - component---src-pages-inde x-jsx-b3759d3c0476f9883dba. js


    - commons-fa6c875ea4a0d1a31 7de.js
 - styles.80e97039b81d20471ead .css
 - hash があるとビルドごとに キャッシュを破棄できる

  13. chunk の作り方 (webpack の場合)
 - chunk 名に対して条件を書く
 - 条件設定の指針
 -

    ページごとに分ける 
 - 共通ライブラリをくくり出す 
 - 詳しくは @mizchi さんの「webpack chunk 最適 テク ニック」
 https://qiita.com/mizchi/items/418be9abee5f785696f0
  14. Gatsbyはどのような chunk か
 - ページごとに chunk
 - 共通モジュールは chunk
 -

    重いライブラリは chunk
 - スタイリング系もchunk
 Improved Next.js and Gatsby page load performance with granular chunking
 https://web.dev/granular-chunking-nextjs/
  15. navigate
 - 現代的な SSG では CSR として遷移できる
 - <a />

    ではなく <Link /> 
 - ex) @gatsby/reach-router 
 - 遷移先の chunk が必要

  16. prefetch
 - resource の先読み
 - A から B に遷移する前に B

    の chunk があれば即座に遷移可能
 - Gatsby の場合、<Link /> に hover したら chunk を取ってこれる

  17. Image optimaization
 - ビルド時に画像とHTMLを最適化
 - Size, Resolution
 - Tag: picture,

    source, lazy load 
 - Traced SVG: 小サイズのSVG placeholder を生成、画 像ロード時に差し替え 
 - JSConfJP の Speaker が分かりやすい
 - https://jsconf.jp/2021/speakers/ 

  18. Zero Runtime CSS in JS
 - VDOMからのスタイル生成はクライアントで行わ れる
 - React

    の style
 - CSS in JS lib: (ex) styled-component, emotion, 
 - LCP に影響あり
 - とはいえほとんどの場合は大丈夫 
 - ビルド時にCSSをHTMLに埋め込む
 - zero runtime xxx が流行 “静的に埋め込めるものは事 前に埋め込んでしまおう” 
 - ex) linaria, vanila-extract 

  19. Gatsby での Zero Runtime CSS in JS の実現
 - ビルド時に勝手に

    HTML に埋め込んでくれる (便利)
 - ただしランタイムでCSSを書き換える時は、CSS in JS ライブラリ環境下では対応するプラグイン が必要
 - gatsby-plugin-emotion など 

  20. 手書きHTMLが最速?
 - 個人的な誤解: React / Next / Gatsby を使えば早くなる
 -

    They say “diffing”, “blazing fast”, … 
 - 駆け出しエンジニア時代、SPA はすごいことをしているという誤解をする 
 - 【翻訳】 2016年にJavaScriptを学んでどう感じたか ← これめちゃくちゃ面白い 
 - https://www.fendo181.me/entry/2016/10/26/172404 
 - 冷静に考えると・・・
 - 差分検知なんぞせず、手で直接実DOMを部分更新した方がエコでは? 
 - そもそもランタイムにReactライブラリを含めない方がエコでは? 

  21. 手書きが勝てない理由, FCP に影響がない理由
 - SSG (=静的化)しているのだから HTML に支払うコストは同じになる
 - ランタイムが膨らむと言っても

    chunk へのリンクが挟まれているだけで、それは async load されるのでブロッキングされない
 - Gatsby のビルドは自然と HTML が minify される

  22. Gatsby に嫌がらせをしてみた
 - Gatsby の遷移は CSR としての遷移
 - つまり、遷移を妨害すれば良い
 -

    遷移先の chunk を巨大にする 
 - 嫌がらせ chunk が分離されないように 1page component にベタ書く 
 - 巨大 prefetch 中に遷移する 
 20MB のDOM要素を用意しました <p>heavy_heavy_heavy_…</p>
  23. SSGした方が良い?
 - SPA (1HTML しかない CSR) に対してはライブラリの分の容量分のアドバンテー ジがある
 - SSG

    に対しては、SSG 側もライブラリ分の容量を HTML からは削るので差が出 にくい
 - ランタイムで動かしたいJSがあっても(ex カルーセル、モーダル)、別チャンクに 切り出せば HTML を読み込むコストとしての差は出ない
 - 別コンポーネントに分けて、2カ所以上から読み込む 
 SSGした方が良い
  24. Incremental Build
 - Gatsby のビルドモードの一つ
 - ビルド時の cache を使って、次回は差分のみをビルド
 -

    Gatsby Cloud でしか使えなかったが v3 でオープンに
 - とはいえ問題が根本的に解消はされない
 - うっかり cache を消した時のリカバリは? 
 - cache 全体に影響があるような変更が入ると? 
 - 運用者目線ではすぐにデプロイし直せる保証が欲しい 
 - DSG (後述)

  25. DSG: Deferred Static Generation
 - Gatsby v4~
 - ビルドタイミングを制御する機能
 -

    静的ビルドするパスを宣言できる 
 - ビルド時に生成しなかったページはユーザーの アクセス時に作られる = SSR 
 - CDNレイヤーにcache
 - アクセスされたページの HTML が static/ フォ ルダに作られるわけではない 
 - Gatsby Cloud を使う必要がある 
 - 使わなくても良い方法があるが、それは後述す る方法と同じやり方
 https://www.gatsbyjs.com/docs/conceptual/rendering-options/
  26. ISR: Incremental Static Regeneration
 - NextJS のモードの一つ
 - SSR と

    SSG のいいところ取り
 - 一度 SSR した HTML をキャッシュし、次回のアクセスからそれを返す 
 - 処理軽減
 - IO削減
 - stale な cache を返しつつ cache を fresh にできる 
 - (基本的には)Vercel 環境でしか動かせない

  27. lock-in が嫌われている気がする
 - Vercel や Gatsby が素晴らしい機能を出すたびに lock-in が心配される
 -

    個人的には 「Vercel に乗っかりなよ」とは思うが、lock-in されたくない気持 ちも理解できる
 - よし、内製しよう
 - DSG / ISR のような動作は CDN で担保する 
 - SSR FW を自作すればいい 

  28. SSR + CDN
 - SSR した HTML を CDN に

    cache
 - 一番素直で FW や Hosting 環境にし ばられないやり方
 - cache の制御もしやすい
 - stale-while-revalidate => ISR 
 - vary
 - dynamic cache purging 

  29. FW を使わない SSR -とある実装を参考に- 
 - Best practice component library

    を作っておく
 - ビルド時にクライアントコードの最適化
 - chunk の作成
 - linaria の実行
 - NodeJS サーバーのエンドポイントで リクエストを待ち受ける
 - (p) react をサーバーで実行して HTML を作成
 - cache control header を設定して返す
 意外とシンプル
 preactとfastifyでSSR https://zenn.dev/takurinton/articles/4 c8625a43f024b
  30. FW を使わないメリット
 - ランタイムライブラリの選択が自由
 - 不都合なく preact が使える 
 -

    _app.js, gatsby-browser.js より細かい粒度で共通設定を書ける
 - ビルドチェインの拡張が容易
 - React app 以外のコードをビルド、SSR時に script tag で挟み込むといったことがやりや すい
 - 1 サービスを複数チームで育てる時に管理しやすい 
 - partial hydration
 - とはいえ Astro, Next12 も凄い! 

  31. FW を使わないデメリット、その指摘
 - FW を作ることに消耗したくない、案件を進めたい
 - Next の完コピを目指すと大変だけど、ただのSSRサーバーを作るだけならそこまでコスト はない
 -

    バックエンドの扱いは慣れていない
 - cache hit ratio を上げる 
 ※ と、ここまで偉そうに話しましたがほとんどが知人の実装やおかげです
  32. まとめ
 - 現代的な SSG は dynamic な要件に対応できる
 - SSG が内部でしていることはページの事前生成とパフォーマンスの最適化


    - SSG の辛さへの回答として、SSR で HTML を Generate して CDN で Cache
 - FW や PFM へのロックインが気になるなら自作できる