$30 off During Our Annual Pro Sale. View Details »

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. SSG is compiler
    Yuta Ide (@sadnessOjisan)
    JSConfJP2021

    View Slide

  2. SSG is like a magic

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. SSG is your friend

    View Slide

  8. Agenda
    1. SSG is useful
    2. Inside SSG
    3. Look back SSR

    View Slide

  9. Is SSG only for
    Blog / LP / Q&A ?

    View Slide

  10. 言葉の定義

    - SST

    - CSR

    - SSR

    - SSG 



    n番煎じな話なので詳細には立ち入りません。

    それぞれのパフォーマンス上の特性は @takepepe さんの 「より速いWebを目指す
    Next.js」にまとまっており、こちらを参照してください。

    また、これらは完全に分離できるものでもないことを断っておきます。

    ex) template に react を CDN 経由で読み込んだものはどれ?
    https://speakerdeck.com/takefumiyoshii/nextjs-make-the-web-faster

    View Slide

  11. SST: Server Side Templating

    - Server で HTML Template に値を埋め込み、HTML を生成してクライアントへ返す

    - 素直な構成だと TTFB の遅さが問題になりがち

    - 一方で後述するCSRと比較し、通信の往復は減る


    View Slide

  12. CSR: Client Side Rendering

    - サーバーから取得したデータを元に、コンテンツの
    描画をクライアントサイドで完結させる

    - TTFB は速いが、LCP を悪化させる要因を含む

    - コンテンツ描画のためにはクライアントでのデータ取得が
    必要

    - HTML / Styling を生成する仕事はクライアントが担う 

    - コンテンツのアップデートにはHTMLを取得しなくて
    いいため SST より効率的になる


    View Slide

  13. SSR: Server Side Rendering

    - サーバーからテンプレートに値が埋め込まれた
    HTMLを受け取る

    - クライアントでそのHTMLは hydration される

    - hydration 後は CSR できる

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


    View Slide

  14. (re)hydration

    - dehydration

    - JS世界にあるVDOM を HTML に変換する処理 

    - SSR サーバーがクライアントにHTMLを返す 


    - (re)hydration

    - HTML を JS の世界で使えるように戻す処理 

    - Client ライブラリが実行する 


    View Slide

  15. SSG: Static Site Generation

    - サーバーはリクエストに対してHTMLを返すだ
    け

    - HTMLをリクエストより前に生成しておく

    - ビルド時の静的コンテンツとして固定されるデメ
    リットはある

    - しかしツールによっては hydration して
    dynamic な性質を取り込み、そのデメリットを回
    避する 


    View Slide

  16. SSG: Static Site Generation

    - 歴史は長い

    - 2000年前半 Database Driven な Site への対
    抗として SSG が注目される

    - props: DBアクセスの削減 / TTFB の削減 

    - cons: ページ数に応じたビルドコスト 

    - これまでに多くのツールが開発されている

    - 興味がある人は jamstack.org にあるまとめサイトを
    チェック 

    https://jamstack.org/generators/ 


    View Slide

  17. SSG: Static Site Generation

    現代的なSSG

    伝統的なSSG

    コンテンツから HTML を作る SSG したものを hydration する


    View Slide

  18. 伝統的なSSG

    - テンプレートからHTMLファイルを生成するツール

    - Markdown ドキュメント、画像などのアセットを元にコンテンツページを作り出せ
    る

    - 任意の言語が利用できる


    View Slide

  19. 現代的なSSG

    - SSR FW や JS ツールチェインの上に作られる

    - hydration + CSR の要素がある

    JS ツールチェインの上に作られることで、transpiler, bundler,
    compressor などの恩恵が受けられる 

    ex) Next, Gatsby, Nuxt, … 


    View Slide

  20. hydration ≠ JS FW

    - wasm によって任意の言語で SSR + hydration が可能

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


    View Slide

  21. SSG に対する批判

    全てが静的に決まらないと使えない

    Twitter を SSG で作れますか? 

    現代的なSSGでCSRすれば対処できるケースも多い

    EC の商品ページを静的生成、在庫はCSRで取得 


    View Slide

  22. Headless Comerce

    https://www.gatsbyjs.com/solutions/shopify

    View Slide

  23. SSG に対する批判

    全てが静的に決まらないと使えない

    Twitter を SSG で作れますか? 

    現代的なSSGでCSRすれば対処できるケースも多い

    EC の商品ページを静的生成、在庫はCSRで取得 

    要件によってはCSRでも難しい

    C to C のECでページ作成が頻繁、通報された商品はページごとは消したい 


    View Slide

  24. Look back SSR later

    View Slide

  25. Agenda
    1. SSG is useful
    2. Inside SSG
    3. Look back SSR

    View Slide

  26. 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/

    View Slide

  27. Let's dive into SSG

    View Slide

  28. Chunk

    - SPA の問題の一つに bundle した JS が巨大過ぎるという問題

    - 必要なページに必要なパーツさえあればいいよね

    → chunk という単位でJSを分割する


    View Slide

  29. 大量の script は chunk が理由

    - 必要なページで、必要なchunk
    だけを使う

    - chunk は bundler の設定で作
    る


    View Slide

  30. 複雑な名前はchunkの規則

    - ${key}-${hash}

    - app-44f67102fd3fe7d6ed63.js 

    - component---src-pages-inde
    x-jsx-b3759d3c0476f9883dba.
    js

    - commons-fa6c875ea4a0d1a31
    7de.js

    - styles.80e97039b81d20471ead
    .css

    - hash があるとビルドごとに
    キャッシュを破棄できる


    View Slide

  31. chunk の作り方 (webpack の場合)

    - chunk 名に対して条件を書く

    - 条件設定の指針

    - ページごとに分ける 

    - 共通ライブラリをくくり出す 

    - 詳しくは @mizchi さんの「webpack chunk 最適 テク
    ニック」

    https://qiita.com/mizchi/items/418be9abee5f785696f0

    View Slide

  32. Gatsbyはどのような chunk か

    - `framework-${hash}`

    - React などの明らかにどのコンポーネントからも使うライブラリを共通の
    chunk にまとめる


    View Slide

  33. Gatsbyはどのような chunk か

    - `lib-${hash}`

    - module が 160kb を超えると別 chunk


    View Slide

  34. Gatsbyはどのような chunk か

    - ページごとに chunk

    - 共通モジュールは chunk

    - 重いライブラリは chunk

    - スタイリング系もchunk

    Improved Next.js and Gatsby page load performance with granular
    chunking

    https://web.dev/granular-chunking-nextjs/

    View Slide

  35. View Slide

  36. navigate

    - 現代的な SSG では CSR として遷移できる

    - ではなく 

    - ex) @gatsby/reach-router 

    - 遷移先の chunk が必要


    View Slide

  37. prefetch

    - resource の先読み

    - A から B に遷移する前に B の chunk があれば即座に遷移可能

    - Gatsby の場合、 に hover したら chunk を取ってこれる


    View Slide

  38. Image optimaization

    - ビルド時に画像とHTMLを最適化

    - Size, Resolution

    - Tag: picture, source, lazy load 

    - Traced SVG: 小サイズのSVG placeholder を生成、画
    像ロード時に差し替え 

    - JSConfJP の Speaker が分かりやすい

    - https://jsconf.jp/2021/speakers/ 


    View Slide

  39. 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 


    View Slide

  40. Gatsby での Zero Runtime CSS in JS の実現

    - ビルド時に勝手に HTML に埋め込んでくれる
    (便利)

    - ただしランタイムでCSSを書き換える時は、CSS
    in JS ライブラリ環境下では対応するプラグイン
    が必要

    - gatsby-plugin-emotion など 


    View Slide

  41. How about Performance

    View Slide

  42. 手書きHTMLが最速?

    - 個人的な誤解: React / Next / Gatsby を使えば早くなる

    - They say “diffing”, “blazing fast”, … 

    - 駆け出しエンジニア時代、SPA はすごいことをしているという誤解をする 

    - 【翻訳】 2016年にJavaScriptを学んでどう感じたか ← これめちゃくちゃ面白い 

    - https://www.fendo181.me/entry/2016/10/26/172404 

    - 冷静に考えると・・・

    - 差分検知なんぞせず、手で直接実DOMを部分更新した方がエコでは? 

    - そもそもランタイムにReactライブラリを含めない方がエコでは? 


    View Slide

  43. Handwritten
    VS
    Gatsby

    View Slide

  44. Handwritten must have advantage
    in simple condition

    View Slide

  45. Hello World だけを比較

    手書きHTML
 Gatsby

    ランタイムのJSが遅れるものの、FCPには影響がない。


    View Slide

  46. 手書きが勝てない理由, FCP に影響がない理由

    - SSG (=静的化)しているのだから HTML に支払うコストは同じになる

    - ランタイムが膨らむと言っても chunk へのリンクが挟まれているだけで、それは
    async load されるのでブロッキングされない

    - Gatsby のビルドは自然と HTML が minify される


    View Slide

  47. Gatsby に嫌がらせをしてみた

    - Gatsby の遷移は CSR としての遷移

    - つまり、遷移を妨害すれば良い

    - 遷移先の chunk を巨大にする 

    - 嫌がらせ chunk が分離されないように 1page
    component にベタ書く 

    - 巨大 prefetch 中に遷移する 

    20MB のDOM要素を用意しました
    heavy_heavy_heavy_…

    View Slide

  48. Gatsby に嫌がらせをしてみた

    手書きHTMLなら、HTMLごと遷移すれ
    ば先頭の表示はされる 

    Gatsby の場合、固まる 


    やったね!


    View Slide

  49. あ

    ほ

    く

    さ


    View Slide

  50. SSGした方が良い?

    - SPA (1HTML しかない CSR) に対してはライブラリの分の容量分のアドバンテー
    ジがある

    - SSG に対しては、SSG 側もライブラリ分の容量を HTML からは削るので差が出
    にくい

    - ランタイムで動かしたいJSがあっても(ex カルーセル、モーダル)、別チャンクに
    切り出せば HTML を読み込むコストとしての差は出ない

    - 別コンポーネントに分けて、2カ所以上から読み込む 

    SSGした方が良い

    View Slide

  51. Agenda
    1. SSG is useful
    2. Inside SSG
    3. Look back SSR

    View Slide

  52. SSR, CSR の弱点、なぜ SSG は速いのか

    - 一番効いてるのは事前生成によるTTFBの削減

    - SSR はここが弱点

    - I/O

    - CPU負荷


    View Slide

  53. SSG の弱点

    大量コンテンツのビルド
 Incremental Build

    コンテンツの追加・削除・編集

    ISR

    DSG

    SSR + CDN

    弱点 対策

    View Slide

  54. Incremental Build

    - Gatsby のビルドモードの一つ

    - ビルド時の cache を使って、次回は差分のみをビルド

    - Gatsby Cloud でしか使えなかったが v3 でオープンに

    - とはいえ問題が根本的に解消はされない

    - うっかり cache を消した時のリカバリは? 

    - cache 全体に影響があるような変更が入ると? 

    - 運用者目線ではすぐにデプロイし直せる保証が欲しい 

    - DSG (後述)


    View Slide

  55. DSG: Deferred Static Generation

    - Gatsby v4~

    - ビルドタイミングを制御する機能

    - 静的ビルドするパスを宣言できる 

    - ビルド時に生成しなかったページはユーザーの
    アクセス時に作られる = SSR 

    - CDNレイヤーにcache

    - アクセスされたページの HTML が static/ フォ
    ルダに作られるわけではない 

    - Gatsby Cloud を使う必要がある 

    - 使わなくても良い方法があるが、それは後述す
    る方法と同じやり方

    https://www.gatsbyjs.com/docs/conceptual/rendering-options/

    View Slide

  56. ISR: Incremental Static Regeneration

    - NextJS のモードの一つ

    - SSR と SSG のいいところ取り

    - 一度 SSR した HTML をキャッシュし、次回のアクセスからそれを返す 

    - 処理軽減

    - IO削減

    - stale な cache を返しつつ cache を fresh にできる 

    - (基本的には)Vercel 環境でしか動かせない


    View Slide

  57. That’s lock-in

    View Slide

  58. lock-in が嫌われている気がする

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

    - 個人的には 「Vercel に乗っかりなよ」とは思うが、lock-in されたくない気持
    ちも理解できる

    - よし、内製しよう

    - DSG / ISR のような動作は CDN で担保する 

    - SSR FW を自作すればいい 


    View Slide

  59. SSR + CDN

    - SSR した HTML を CDN に cache

    - 一番素直で FW や Hosting 環境にし
    ばられないやり方

    - cache の制御もしやすい

    - stale-while-revalidate => ISR 

    - vary

    - dynamic cache purging 


    View Slide

  60. 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

    View Slide

  61. FW を使わないメリット

    - ランタイムライブラリの選択が自由

    - 不都合なく preact が使える 

    - _app.js, gatsby-browser.js より細かい粒度で共通設定を書ける

    - ビルドチェインの拡張が容易

    - React app 以外のコードをビルド、SSR時に script tag で挟み込むといったことがやりや
    すい

    - 1 サービスを複数チームで育てる時に管理しやすい 

    - partial hydration

    - とはいえ Astro, Next12 も凄い! 


    View Slide

  62. FW を使わないデメリット、その指摘

    - FW を作ることに消耗したくない、案件を進めたい

    - Next の完コピを目指すと大変だけど、ただのSSRサーバーを作るだけならそこまでコスト
    はない

    - バックエンドの扱いは慣れていない

    - cache hit ratio を上げる 

    ※ と、ここまで偉そうに話しましたがほとんどが知人の実装やおかげです

    View Slide

  63. まとめ

    - 現代的な SSG は dynamic な要件に対応できる

    - SSG が内部でしていることはページの事前生成とパフォーマンスの最適化

    - SSG の辛さへの回答として、SSR で HTML を Generate して CDN で
    Cache

    - FW や PFM へのロックインが気になるなら自作できる


    View Slide