コミュニティ

Webアプリパターンの歴史 - SST、AJAX、CSR、SSR、SSG、そしてISR

Webアプリパターンの歴史 - SST、AJAX、CSR、SSR、SSG、そしてISR

by kimizuy
1 / 25

はじめに (1/2)

Webアプリの動作するパターンをまとめました。歴史を振り返ることで JAMStack といったモダンなスタックがどういった点で有用なのか理解していきましょう。

発表者:@kimizuy
日々スプラのXPをどう上げるかに頭を悩ませています。ブログもあります。


はじめに (2/2)

これは2020年9月16日開催のりあクト! TypeScriptで始めるつらくないReact開発 第3版Ⅰ. 言語・環境編 読書会のLT用資料として作成しました。

※ 続きの会も企画する予定です。どちらかというと初学者〜中級者向けです。興味のある方はお気軽にご参加ください。


SST (1/3)

概要

  • Server Side Templating の略
  • 基本的にはサーバサイドのフレームワークとテンプレートエンジンの組み合わせ
  • 完成した HTML をクライアントに返すため正確にはサーバサイドレンダリングだが、当時はこの手法しかなかったので後付けでこの呼び方になった
  • 主役は Ruby などのサーバーサイドで HTML や JavaScript は脇役だった
  • サーバーのレスポンスを受けると画面がクリアされ新しいページがレンダリングされる(都度画面がリセットされる)
  • 内容の更新にはリロードなどが必要

SST (2/3)

gen1st.png

出典:渋川よしき『Real World HTTP ミニ版』図5-6

サーバサイドで取得したデータをテンプレートに流し込んでHTMLを生成し、それをブラウザに返します


SST (3/3)


AJAX (1/2)

概要

  • Asynchronous JavaScript + XML の略
  • IE 製の XMLHttpRequest API が発端
  • 次いで Server-sent Event、WebSocket、fetch といった通信APIが規格化される
  • フロントエンドの仕事が増大して、JQuery で DOM を操作したり、状態管理のために Backbone.js などのクライアントサイドMVCフレームワークが導入されたりする
  • XML ってついてるけどパフォーマンスの観点から JSON が一般的なデータフォーマットとして利用されている

AJAX (2/2)

gen2nd.png

出典:渋川よしき『Real World HTTP ミニ版』図5-7

GET や POST メソッドを利用してウェブ API からデータを受け取り、HTML を動的に更新します


CSR (1/3)

概要

  • Client Side Rendering の略
  • SPA (Single Page Application) の始まり
  • React、Vue.js、Angular といったライブラリ・フレームワークが開発される
  • AJAX 環境よりも充実したライブラリ・エコシステムがある
  • コンポーネント指向
    • 単一責任の原則:「ひとつのコンポーネントは理想的にはひとつのことだけをするべきだ」
    • ロジックを分離してカプセル化し保守性を向上
    • コードの再利用性を高める

参考:React の流儀


CSR (2/3)

gen3rd.png

出典:渋川よしき『Real World HTTP ミニ版』図5-7

  • すべてのロジック、データフェッチ、テンプレーティングやルーティングがクライアントで行われる
  • 最初にほぼ空の HTML を読みこみ、JavaScript から DOM を生成・操作する
  • 仮想 DOM 機能(React、Vue)で差分だけを高速で更新が可能
  • History API というブラウザ API をラップした Router ライブラリでページ遷移を擬似的に表現でき UX が向上

CSR (3/3)

デメリット

  • アプリが大きくなると JavaScript ソースコードも肥大化し、クライアントで JavaScript を読み込むためクライアントの処理負荷や通信量の増大
  • ほぼ白紙の HTML と JavaScript を受け取ってからページを生成するため、すべてのコンテンツが表示されるまでの待機時間(TTI)が長い
  • 上記を考慮した遅延ロード処理が必要
  • SEOに不向き

SSR (1/3)

概要

  • Server Side Rendering の略
  • Next.js や Nuxt.js といったフレームワークがある
  • この場合の SSR は厳密には CSR と SSR の組み合わせ

SSR (2/3)

gen35th.png

出典:渋川よしき『Real World HTTP ミニ版』図5-8

  • サーバー側で JavaScript を実行するため、ユーザー側の処理能力に依存しない
  • サーバーがリクエストを受けた時点で HTML を生成し、それをブラウザに返す
  • 上記以降は CSR で DOM を更新する
  • 生成済みの HTML を受け取るため高速なローディングが可能
  • SEO に対応

SSR (3/3)

デメリット

  • リクエストを受けてから HTML を生成し、送信するので初期表示が遅くなる
  • フレームワークに頼らない場合は実装が複雑になる

サーバーレンダリングを「正しく」行うためには、コンポーネントのキャッシュ、メモリ消費の管理、メモ化の適用、その他多くの懸念事項に対するソリューションの検索や構築が必要です
Rendering on the Web


SSG (1/3)

概要

  • Static Site Generation の略
  • Next.js、Gatsby.js、Hugo、Jekyll といったフレームワークがある
  • データベースやサーバサイドを使わず、ほぼクライアントサイドで実装が完結できるためシンプルな設計が可能
  • JAMStack で利用される

SSG (2/3)

ssg-host-flow.png

出典:https://www.netlify.com/blog/2020/04/14/what-is-a-static-site-generator-and-3-ways-to-find-the-best-one/

  • ビルド時にあらかじめ静的なファイルを生成する
  • また各 URL に対応する個別の HTML ファイルを前もって作成する
  • ホスティングサービス (Netlify や Vercel) で生成済みのファイルをホスティングするだけなので運用コストもかかりにくい
  • 初期表示時、クライアントは完成済みの HTML を受け取るだけのためパフォーマンスが高い
  • Next.js や Gatsby.js は SSG に加えて SSR や CSR を組み合わせて構築可能
  • SEO にも対応

SSG (3/3)

デメリット

静的レンダリングの欠点のひとつは、すべての有効なURLに対し、個々にHTMLファイルを生成しなければならないことです。 これらのURLが事前に、また多くの固有ページを持つサイトであるか予測できない場合、これは難題であり実行不可能になることもあります
Rendering on the Web


そして ISR へ (1/6)

  • Incremental Static Regeneration の略
  • 日本語で直訳すると「増分静的再生成」
  • ビルド後に静的生成されたページを追加したり、更新したりできる
  • Next.js 9.5 より正式な機能としてリリースされた

そして ISR へ (2/6)

whatisisr.png

https://arunoda.me/blog/what-is-nextjs-issg

図にある Regeneration Process にはページ追加/更新の2通りのパターンがあります(組み合わせも可能)。


そして ISR へ (3/6)

前提

  • getStaticProps()のなかに外部データをフェッチするための処理を書く。ビルドサーバー(Node.js環境)で実行される

  • getStaticPaths()データに基づいて、プリレンダリングするルート一覧を動的に返す


そして ISR へ (4/6)

動的に静的ページを追加

「無数にあるページを事前に生成しておくとビルドが遅くなるし、ページの情報を更新するには CSR や SSR での処理が必要なのでは?」
→ Incremental Static Regeneration で解決!

  • fallback: true:ビルド時にパスが生成されなかったページは、ユーザーの要求のタイミングでページを生成する
  • 次のアクセス以降は生成したページを返す
// pages/products/[id].js

export async function getStaticProps({ params }) {
  // ...
}

export async function getStaticPaths() {
  // ...

  // fallback: true means that the missing pages
  // will not 404, and instead can render a fallback.
  return { paths, fallback: true }
}

export default function Product({ product }) {
  const router = useRouter()

  if (router.isFallback) {
    return <div>Loading...</div>
  }

  // Render product...
}

そして ISR へ (5/6)

動的に静的ページを更新

「ページの情報を更新するには CSR や SSR での処理が必要なのでは?」
→ これも Incremental Static Regeneration で解決!

  • 取得したデータに変更があった場合はページを再生成する
  • 影響を受けるページのみ更新する
// pages/products/[id].js

export async function getStaticProps({ params }) {
  return {
    props: {
      product: await getProductFromDatabase(params.id)
    },
    // 秒数を指定
    revalidate: 60
  }
}

そして ISR へ (6/6)

デモ

次のふたつは動的に静的なページを追加・更新するデモです

  • 無数にあるツイートのうち一つのツイートを静的なページとして追加するデモ

static-tweet

  • GitHub のリアクションが更新されたら、静的ページに反映するデモ

reactions-demo


参考にした文献やサイト

『Real World HTTP ミニ版』
https://www.oreilly.co.jp/books/9784873118789/
Real World HTTP 第2版も!)

React の流儀
https://ja.reactjs.org/docs/thinking-in-react.html

Rendering on the Web - Web上のレンダリング
https://developers.google.com/web/updates/2019/02/rendering-on-the-web?hl=ja#csr

AJAX
https://developer.mozilla.org/ja/docs/Web/Guide/AJAX

Next.js: Server-side Rendering vs. Static Generation
https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation


以上です。
ありがとうございました。

kimizuy
Webフロントエンド開発やってます。 好き: React, Redux, TypeScript, Next.js https://github.com/kimizuy
https://kimizuy.dev
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
    コメント
    この記事にコメントはありません。
    あなたもコメントしてみませんか :)
    すでにアカウントを持っている方は