Vue Academy · レッスン

renderToWebStreamによるストリーミングSSR

renderToWebStream()とrenderToString()の比較、HTTPストリーミング、TTFBの改善、チャンクのフラッシュ

レッスン 3/413 ステップ

「renderToWebStreamによるストリーミングSSR」はCoddyKit上の無料Vue Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはVue Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Vue Academyコースには全4レッスンが含まれています。

renderToStringからストリーミングへ

従来のSSRではrenderToStringを使い、1バイトも送信する前にHTML全体をメモリ上に構築します。ブラウザはページ全体の準備が整うまで待機したままになります。

ストリーミングSSRでは、アプリの描画に合わせてHTMLをチャンク単位で送信するため、ブラウザはより早く解析を開始できます。

renderToWebStreamの基本

Vueのサーバーレンダラーにはストリーミング用の関数があります。renderToWebStreamはReadableStream(Web Streams API)を返し、renderToNodeStream/pipeToNodeWritableはNodeのストリームインターフェースを対象とします。

コンポーネントツリーの解決に合わせて、各チャンクがフラッシュされます。

import { renderToWebStream } from 'vue/server-renderer'
import { createSSRApp } from 'vue'
import App from './App.vue'

const app = createSSRApp(App)
const stream = renderToWebStream(app)

HTTPレスポンスへのパイプ

Nodeサーバーでは、ストリームをレスポンスへパイプします。pipeToNodeWritableを使うと、生成されたチャンクをフラッシュしながら、resの書き込み可能ストリームへ直接書き込めます。

import { pipeToNodeWritable } from 'vue/server-renderer'

server.get('*', (req, res) => {
  const app = createSSRApp(App)
  res.write('<!DOCTYPE html><html><body><div id="app">')
  pipeToNodeWritable(app, {}, res)
})

Web/Edgeランタイムでのストリーミング

Edgeランタイム(Workers、Deno、Bun)では、Webストリームから直接構築したResponseを返します。Nodeストリームは関与しません。

import { renderToWebStream } from 'vue/server-renderer'

export default async function handler(request) {
  const app = createSSRApp(App)
  const stream = renderToWebStream(app)
  return new Response(stream, {
    headers: { 'Content-Type': 'text/html' }
  })
}

チャンクがブラウザに届く仕組み

Vueはノードを描画しながら、シリアライズされたHTML文字列をストリームへ送り込みます。HTTP層はそれらのバイトをすぐにフラッシュします。ブラウザのインクリメンタルHTMLパーサーは、レスポンスが完了する前に表示可能なコンテンツを描画します。

そのため、ページ本文がまだストリーミング中でも、ユーザーにはヘッダーとレイアウトが表示されます。

TTFB:重要な指標

TTFB(Time To First Byte)は、最初のレスポンスバイトが到着するまでの時間を測定します。

renderToStringでは、TTFBにレンダリング全体の時間が含まれます。ストリーミングでは、最初のチャンクがほぼすぐにサーバーから送信されるため、TTFBが大幅に短縮され、体感速度が向上します。

// renderToString: client waits for full HTML
const html = await renderToString(app) // blocks
res.end(fullPage(html))

// streaming: first bytes flush right away
pipeToNodeWritable(app, {}, res) // non-blocking chunks

レイアウトHTMLでストリームをラップする

通常は、アプリのストリームの前にドキュメントシェル(<head>や開始タグ)を送信し、後に終了タグを送信する必要があります。プレフィックスを書き込み、アプリをパイプし、ストリームの終了時にサフィックスを書き込みます。

res.write('<!DOCTYPE html><head><title>App</title></head>')
res.write('<body><div id="app">')

pipeToNodeWritable(app, ctx, {
  write: (chunk) => res.write(chunk),
  end: () => res.end('</div></body></html>')
})

ストリーム途中でのエラー処理

一度バイトをフラッシュすると、HTTPステータスコードは変更できません。onErrorオプション(または書き込み可能ストリームのエラーパス)でレンダリングエラーを処理します。早い段階で検出できる重大なエラーには、まだ500を送信できるよう、非ストリーミングのレンダリングを優先してください。

pipeToNodeWritable(app, ctx, {
  write: (c) => res.write(c),
  end: () => res.end(suffix),
  destroy: (err) => {
    console.error('Stream failed:', err)
    res.end() // status already sent
  }
})

ストリーミング後のハイドレーション

ストリーミングされたHTMLも、クライアント側でcreateSSRApp().mount()を使ってハイドレーションされます。VueはDOMを再生成するのではなく、既存のDOMにリスナーをアタッチします。ストリーミングが変えるのはマークアップの配信方法だけで、ハイドレーションの仕組みは変わりません。

// client entry
import { createSSRApp } from 'vue'
import App from './App.vue'

createSSRApp(App).mount('#app') // hydrates streamed markup

ストリーミングと非同期データ

データに依存するコンポーネントでは、ストリーミングの前または最中に重要なデータを解決します。ツリーの各部分が独立している場合にストリーミングの効果を発揮します。シェルはすぐにストリーミングされ、遅い部分はデータの準備に合わせて描画されます。

// fetch critical data, then stream the rest
const app = createSSRApp(App, { initialData })
const stream = renderToWebStream(app)
return new Response(stream, {
  headers: { 'Content-Type': 'text/html' }
})

ストリーミングを選ぶタイミング

TTFBと体感速度が重要で、安定したシェルを先に送信できるコンテンツ量の多いページには、ストリーミングを使います。小規模なページや、最終的なステータスコードとヘッダーを完全に制御する必要がある場合は、renderToStringを使い続けてください。

理解度チェック

ストリーミングSSRについての理解度を確認しましょう。

まとめ

ストリーミングSSRについて学びました。

  • renderToWebStreamはReadableStreamを返し、NodeではpipeToNodeWritableを使います
  • ツリーの描画に合わせてチャンクがフラッシュされるため、ブラウザは段階的に解析できます
  • ブロッキング方式のrenderToStringと比べて、TTFBが短縮されます
  • ストリームの前後をドキュメントシェルで囲みます。最初のフラッシュ後に発生したエラーでは、ステータスを変更できません
  • createSSRApp().mount()によるハイドレーションの仕組みは変わりません
無料で開始

AI チューターと学ぶ HTML — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
42
レッスン
156

よくある質問

「renderToWebStreamによるストリーミングSSR」レッスンは無料ですか?

はい。「renderToWebStreamによるストリーミングSSR」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Vue Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Vue Academyコースには全4レッスンが含まれています。

「renderToWebStreamによるストリーミングSSR」で何を学びますか?

renderToWebStream()とrenderToString()の比較、HTTPストリーミング、TTFBの改善、チャンクのフラッシュ ブラウザで直接実行するハンズオンコードでVue Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Vue Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのVue Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「renderToWebStreamによるストリーミングSSR」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このVue Academyレッスンでコードを書いて実行できますか?

はい。すべてのVue Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Vue Suspenseコンポーネント
  2. defineAsyncComponentによる非同期コンポーネント
  3. renderToWebStreamによるストリーミングSSR
  4. 遅延ハイドレーション戦略
← Vue Academyに戻る