Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Deep dive into Nuxt Server Components
Search
wattanx
October 19, 2024
Technology
1
2k
Deep dive into Nuxt Server Components
Vue Fes Japan 2024
wattanx
October 19, 2024
Tweet
Share
More Decks by wattanx
See All by wattanx
Unlocking the potential of Nuxt Server Components
wattanx
2
310
Nuxt Test Utils で始める効率的な Nuxt アプリケーションのテスト
wattanx
4
2.9k
Demystifying Nuxt Bridge
wattanx
3
5.4k
小さく進める Nuxt 3 移行
wattanx
0
1.8k
プロダクト開発を止めずに Composition API と TypeScript に 最速で移行するための戦い
wattanx
0
2k
Other Decks in Technology
See All in Technology
SREによる隣接領域への越境とその先の信頼性
shonansurvivors
1
390
フロントエンド メタフレームワーク 選定の際に考えたこと
yuppeeng
0
590
データの信頼性を支える仕組みと技術
chanyou0311
5
1.6k
Platform Engineering ことはじめ
oracle4engineer
PRO
8
800
いざ、BSC討伐の旅
nikinusu
1
590
マイベストのデータ基盤の現在と未来 / mybest-data-infra-asis-tobe
mybestinc
2
1.9k
State of Open Source Web Mapping Libraries
dayjournal
0
200
Microsoft Fabric OneLake の実体について
ryomaru0825
0
190
Forget efficiency – Become more productive without the stress
ufried
0
240
Spring Frameworkの新標準!? ~ RestClientとHTTPインターフェース入門 ~
ogiwarat
2
250
OCI Data Integration技術情報 / ocidi_technical_jp
oracle4engineer
PRO
1
2.6k
AI機能の開発運用のリアルと今後のリアル
akiroom
0
250
Featured
See All Featured
Testing 201, or: Great Expectations
jmmastey
38
7.1k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.2k
Faster Mobile Websites
deanohume
305
30k
How To Stay Up To Date on Web Technology
chriscoyier
788
250k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
131
33k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
How to Ace a Technical Interview
jacobian
276
23k
Code Reviewing Like a Champion
maltzj
520
39k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5k
Producing Creativity
orderedlist
PRO
341
39k
Transcript
STORES 株式会社 wattanx Deep dive into Nuxt Server Components
Ryota Watanabe(wattanx) ・STORES 株式会社 ソフトウェアエンジニア。 ・猫が好き。大阪在住。 ・Nuxt コミッター、Nuxt Bridge のメンテナ。
自己紹介
Agenda 3 Nuxt のレンダリングモードと課題 Nuxt Server Components について Nuxt Server
Components の活用方法 作って学ぶ Nuxt Server Components 他の似たような技術との違い 01 02 03 04 05
はじめに ちょっとアンケート
本セッションの狙い • どんなことができるのか • どんな課題を解決するのか • どんな仕組みなのか • 他の技術との違いは何なのか Nuxt
Server Components について知ってもらう
Nuxt のレンダリングモードについて
Nuxt のレンダリングモードについて • Client-Side Rendering • Server-Side Rendering Nuxt がサポートしているレンダリングモード
Nuxt のレンダリングモードについて • 動的にデータを取得する • 取得したデータを JavaScript を使って画面に表示する • JavaScript
で画面遷移を実現 Client-Side Rendering
Nuxt のレンダリングモードについて (Client-Side Rendering) Browser Server GET / GET /bundle.js
Render JS をダウンロードする レンダリングされる 空の HTML を ダウンロードする HTML JS
Nuxt のレンダリングモードについて (Client-Side Rendering) • パフォーマンス • 検索エンジンの最適化 Client-Side Rendering
の課題
Nuxt のレンダリングモードについて (Client-Side Rendering) • パフォーマンス ◦ ブラウザが JavaScript をダウンロードし、解析・実行するのを待
たなければならない ◦ そのため、コンテンツが表示されるまで遅い • 検索エンジンの最適化 ◦ クローラーとの相性が悪い ◦ JavaScript を解釈できるクローラーもあるが...
Nuxt のレンダリングモードについて Server-Side Rendering が課題を解決する
Nuxt のレンダリングモードについて (Server-Side Rendering) • Client-Side Rendering の課題を解決する • Server
は完全にレンダリングされた HTML をブラウザに返す Server-Side Rendering(Universal Rendering)
Nuxt のレンダリングモードについて (Server-Side Rendering) Browser Server GET / GET /bundle.js
Hydration HTML JS レンダリング済みの HTML をダウンロードする JS をダウンロードする Hydration される Render
Nuxt のレンダリングモードについて (Server-Side Rendering) • Server から受け取った HTML を Interactive
にする ◦ Server から受け取った HTML はイベントリスナがセット されていない ◦ イベントリスナをセットする作業が Hydration Hydration とは
Nuxt のレンダリングモードについて まだ課題が残っている
Nuxt のレンダリングモードについて • bundle size の増大 残っている課題
Nuxt のレンダリングモードについて markdown で書いたコンテンツを HTML に変換して表示する例 以下のソースコードは Server, Client 両方で実行される
(Server-Side Rendering を想定)
Nuxt のレンダリングモードについて Q: なぜ Server, Client 両方で実行する必要があるのか A: 両方実行して同じ DOM
構造にならないと Hydration できないから
Nuxt のレンダリングモードについて Server, Client 両方で実行されるため 以下のライブラリは Client の bundle にも含まれる
sanitize-html: 194.8Kb (80.9Kb gzipped) marked: 35.9Kb (11.2Kb gzipped) でかい...減らしたい...
Nuxt のレンダリングモードについて fs などは Server でしか使えないので、 API Routes を使っている
Nuxt のレンダリングモードについて 本当はこう書きたいし、bundle size も減らしたい Server でしか使えないけど、 Server でだけ実行できれば... Hydration
が必要ないので、 Server でだけ実行できれば...
Nuxt のレンダリングモードについて Server でだけレンダリングされる コンポーネントがあれば解決する
Nuxt のレンダリングモードについて そんな都合のいい仕組みがあるんですか?
Nuxt Server Components
Nuxt Server Components • Nuxt 3 から導入された機能 ◦ まだ experimental
• Server でだけレンダリングされるコンポーネントをつくることが できる Nuxt Server Components
Nuxt Server Components • Server でだけ実行されて、Hydration されない ◦ Client bundle
に不要な JS も含まれない • Server が必須ではない。 ◦ ビルド時にアプリケーションで使用される Server Component を プリレンダリングする ◦ そのため、完全に静的なサイトであっても動作する
Nuxt Server Components Server Component 使わない場合 Server Component 使う場合 約
66.4 % 減 詳しいソースコード https://github.com/wattanx/mini-nuxt-sc/pull/1
Nuxt Server Components • 拡張子を .server.vue にする • NuxtIsland コンポーネントを使う
Nuxt Server Components の使い方
Nuxt Server Components experimental.componentIslands を 有効化する
Nuxt Server Components 拡張子を .server.vue にすると Server Component になる 書きたかったコードが書ける!
Nuxt Server Components 使う側は import なしで使用する もしくは #components からの import
(実際のパスから import するのはまだサポートできていない)
Nuxt Server Components • Server Component の基盤 ◦ .server.vue は
NuxtIsland コンポーネントを使ったコー ドに変換される • components/islands にコンポーネントを作ると、Server で だけレンダリングできるコンポーネントになる NuxtIsland コンポーネント
Nuxt Server Components NuxtIsland コンポーネントの使い方
Nuxt Server Components 静的な部分を島(Island)としている NuxtIsland は動的な部分に静的なコンテンツを埋め込むアーキテクチャ 海: 動的(JS で Interactive
になっている) 島: 静的(Interactive ではない)
Nuxt Server Components • Async Component が使える • Server Component
と Client Component を入れ子にできる • Server Component のうち、一部だけ Hydration できる Nuxt Server Components でできること(一部抜粋)
Nuxt Server Components Async Component が書ける
Nuxt Server Components Slot を使うことで Server Component と Client Component
を入れ子 にする
Nuxt Server Components nuxt-client ディレクティブを使うことで Server Component の一部を Hydration することができる
Nuxt Server Components の活用方法
Nuxt Server Components の活用方法 • ブログ ◦ ほとんどの場合インタラクションが必要ないため • 時限式のコンポーネント
Nuxt Server Components を活かせるもの
Nuxt Server Components の活用方法 • 時限式のコンポーネント ◦ https://www.mizdra.net/entry/2024/08/27/190853 ◦ ある特定の日に表示するようなコンポーネント
◦ Client Component だと Client bundle にその日まで出したくな い情報が含まれてしまう ◦ これは Nuxt Server Components においても効果的
Nuxt Server Components の活用方法 • 頻繁に props が変更されるコンポーネント ◦ props
が変わるたびに Server へのリクエストが発生するため Nuxt Server Components を活かせないもの
Nuxt Server Components の活用方法 • Server Component 同士の入れ子 ◦ Server
Component のレンダリングには Server へのリクエ スト が必要 ◦ なので、入れ子にするとオーバーヘッドが増える ◦ 理由は仕組みを理解するとわかる (このあと解説予定) 気をつけた方がいいところ
作って学ぶ Nuxt Server Components
作って学ぶ Nuxt Server Components Nuxt Server Components を作って仕組みを解説します
作って学ぶ Nuxt Server Components • Server Component の基盤である NuxtIsland •
コンポーネントを Server でだけレンダリングする仕組み 最終的にできあがるもの
作って学ぶ Nuxt Server Components • Vue で Server-Side Rendering できる環境
• npm create vite-extra@latest app -- --template ssr-vue-ts 準備するもの
作って学ぶ Nuxt Server Components Nuxt Server Components の流れ (Server-Side Rendering
の場合)
作って学ぶ Nuxt Server Components Browser Server GET / GET /bundle.js
Hydration HTML JS Render GET /__nuxt_island Render component HTML Not Hydrated
作って学ぶ Nuxt Server Components Browser Server GET / GET /bundle.js
Hydration HTML JS Render GET /__nuxt_island Render component HTML Not Hydrated 従来のレンダリングとの差分
作って学ぶ Nuxt Server Components Nuxt Server Components の構成要素 • Vue
コンポーネントをレンダリングするエンドポイント • Server で Vue コンポーネントをレンダリングする処理 • Vue コンポーネントをレンダリングするエンドポイントへリクエストを投げる コンポーネント
作って学ぶ Nuxt Server Components Nuxt Server Components の構成要素 • Vue
コンポーネントをレンダリングするエンドポイント 👈 まずはここ • Server で Vue コンポーネントをレンダリングする処理 • Vue コンポーネントをレンダリングするエンドポイントへリクエストを投げる コンポーネント
作って学ぶ Nuxt Server Components Browser Server GET / GET /bundle.js
Hydration HTML JS Render GET /__nuxt_island Render component HTML Not Hydrated ここ
作って学ぶ Nuxt Server Components URL からコンポーネント名や props を抽出する処理をつくる 実際のURL /__nuxt_island/CodeExample_XdPPUtbPQW.json?props={"count":4}
URL からコンポーネント名: CodeExample が抽出 クエリパラメータから props: { count: 4 } が抽出
作って学ぶ Nuxt Server Components エンドポイントを作る コンポーネント名や props を抽出して context に詰め込む
render 関数はあとで説明
作って学ぶ Nuxt Server Components • Server-Side Rendering 中に利用したいデータを追加できる ◦ Nuxt
では Request Event を詰めたりしている ◦ useSSRContext を使うことでコンポーネント内からアクセ スできる • https://ja.vuejs.org/api/ssr.html#ssr-context SSR Context
作って学ぶ Nuxt Server Components Nuxt Server Components の構成要素 • Vue
コンポーネントをレンダリングするエンドポイント • Server で Vue コンポーネントをレンダリングする処理👈 次はここ • Vue コンポーネントをレンダリングするエンドポイントへリクエストを投げる コンポーネント
作って学ぶ Nuxt Server Components Browser Server GET / GET /bundle.js
Hydration HTML JS Render GET /__nuxt_island Render component HTML Not Hydrated ここ
作って学ぶ Nuxt Server Components コンポーネント名とコンポーネントのマッピングをつくる
作って学ぶ Nuxt Server Components 動的にコンポーネントをレンダリングするコンポーネントをつくる レンダリングしたいコンポーネントを取得 動的にコンポーネントをレンダリングできる
作って学ぶ Nuxt Server Components Server で Vue コンポーネントをレンダリングするには
作って学ぶ Nuxt Server Components createSSRApp と renderToString を使う https://ja.vuejs.org/guide/scaling-up/ssr.html
作って学ぶ Nuxt Server Components createSSRApp と renderToString、 動的にコンポーネントをレンダリングする処理を組み合わせる Server で
Vue コンポーネントをレンダリングする 動的にコンポーネントをレンダリングする
作って学ぶ Nuxt Server Components この render 関数は /__nuxt_island で実行される
作って学ぶ Nuxt Server Components Nuxt Server Components の構成要素 • Vue
コンポーネントをレンダリングするエンドポイント • Server で Vue コンポーネントをレンダリングする処理 • Vue コンポーネントをレンダリングするエンドポイントへリクエストを投げる コンポーネント 👈 次はここ
作って学ぶ Nuxt Server Components Browser Server GET / GET /bundle.js
Hydration HTML JS Render GET /__nuxt_island Render component HTML Not Hydrated ここ
作って学ぶ Nuxt Server Components だいぶ簡略化したコード /__nuxt_island へリクエストを投げる Server でレンダリングされているので Client-Side
ではprops が変わったらリクエストを投げる HTML 文字列 レンダリングする Hydration されない
作って学ぶ Nuxt Server Components これが NuxtIsland コンポーネントです
作って学ぶ Nuxt Server Components NuxtIsland は /__nuxt_island へリクエストを投げて レスポンスの HTML
文字列をレンダリングする
作って学ぶ Nuxt Server Components コンポーネント単位でレンダリングする仕組みが完成 🎉
作って学ぶ Nuxt Server Components このままでは Server Component の子に interactive なコンポーネントをもつことができない
作って学ぶ Nuxt Server Components Slot を使うことで Server Component と Client
Component を入れ子に できる
作って学ぶ Nuxt Server Components Q: Slot を含めてレンダリングするとどうなりますか? A: ただのHTML 文字列になるので、
Hydration されません (イベントハンドラなどの情報がない)
作って学ぶ Nuxt Server Components どうやって完全にレンダリングされた HTML 文字列に Slot を差し込むのか
作って学ぶ Nuxt Server Components Teleport が活躍する
作って学ぶ Nuxt Server Components Client Component を入れ子にするために必要なこと • <slot />
をビルド時に独自の placeholder に変換する • Slot のコンテンツを Teleport で囲んでレンダリングする • placeholder 部分に Slot のコンテンツを差し込む
作って学ぶ Nuxt Server Components Slot の部分がコンテンツに置き換わった状態で レンダリングされるのを目指す
作って学ぶ Nuxt Server Components Client Component を入れ子にするために必要なこと • <slot />
をビルド時に独自の placeholder に変換する 👈 まずはここ • Slot のコンテンツを Teleport で囲んでレンダリングする • placeholder 部分に Slot のコンテンツを差し込む
作って学ぶ Nuxt Server Components ビルド時に独自の placeholder に変換する
作って学ぶ Nuxt Server Components Client Component を入れ子にするために必要なこと • <slot />
をビルド時に独自の placeholder に変換する • Slot のコンテンツを Teleport で囲んでレンダリングする 👈 次はここ • placeholder 部分に Slot のコンテンツを差し込む
作って学ぶ Nuxt Server Components こんな感じに書き換える
作って学ぶ Nuxt Server Components Client-Side Rendering 時 Server-Side Rendering 時
Teleport 部分をわかりやすいように書くと以下のようなコードになる
作って学ぶ Nuxt Server Components Teleport 部分をわかりやすいように書くと以下のようなコードになる これを Server Side でレンダリングするとどうなるかが重要
作って学ぶ Nuxt Server Components • コンポーネントにあるテンプレートの一部を、そのコンポー ネントの DOM 階層の外側に存在する DOM
ノードに「テレ ポート」できる組み込みコンポーネント • https://ja.vuejs.org/guide/built-ins/teleport.html Teleport
作って学ぶ Nuxt Server Components v-if が true になったとき body 要素に挿入される
作って学ぶ Nuxt Server Components Server-Side でレンダリングしたとき、SSR Context の teleports に
Teleport 内のコンテンツが公開される (SSR Context は renderToString の第二引数に渡すオブジェクト) https://ja.vuejs.org/guide/scaling-up/ssr.html#teleports
作って学ぶ Nuxt Server Components
作って学ぶ Nuxt Server Components Teleport を含む NuxtIsland コンポーネントを Server-Side Rendering
すると以下のように Teleport 内のコンテンツが手に入る
作って学ぶ Nuxt Server Components Client Component を入れ子にするために必要なこと • <slot />
をビルド時に独自の placeholder に変換する • Slot のコンテンツを Teleport で囲んでレンダリングする • placeholder 部分に Slot のコンテンツを差し込む 👈 次はここ
作って学ぶ Nuxt Server Components ビルド時に独自の placeholder に変換した
作って学ぶ Nuxt Server Components NuxtIsland がレンダリングされると data-island-uid がセットされる
作って学ぶ Nuxt Server Components uid=xxx,slot=default を見るとどこに差し込むべきかわかる 一致
作って学ぶ Nuxt Server Components 差し込む場所がわかったので Teleport のコンテンツを差し込む (Server でレンダリングするときに正規表現で置換している) ここに差し込んで
こうなる
作って学ぶ Nuxt Server Components Server で出来上がった HTML
作って学ぶ Nuxt Server Components Client-Side Rendering 時
作って学ぶ Nuxt Server Components to に指定した attribute が一致するので Teleport される
作って学ぶ Nuxt Server Components Teleport されるとこうなる
Nuxt のレンダリングモードについて Q: なぜ Server, Client 両方で実行する必要があるのか A: 両方実行して同じ DOM
構造にならないと Hydration できないから
作って学ぶ Nuxt Server Components Server で出来上がった HTML と比較すると Server Client
作って学ぶ Nuxt Server Components Server で出来上がった HTML と比較すると Server Client
完全に一致
作って学ぶ Nuxt Server Components Hydration できる 🎉
作って学ぶ Nuxt Server Components Nuxt Server Components 完全に理解した 🎉
作って学ぶ Nuxt Server Components • Minimal Nuxt Server Components •
Nuxt に依存しないように作った • Vue を使えば作れる https://github.com/wattanx/mini-nuxt-sc
他の似たような技術との違い
他の似たような技術との違い • バンドル前に事前にレンダーされるコンポーネント • Server がなくても実行できる (Nuxt と同じ) • RSC
Payload と呼ばれる特別なデータ形式にレンダリングされる ◦ Nuxt Server Components は HTML にレンダリングされる React Server Components
他の似たような技術との違い • 静的な部分に動的(JS で Interactive)な部分を埋め込むアプローチ • Nuxt Server Components とは逆
◦ Nuxt は動的な部分に静的なコンテンツを埋め込むというアプローチ Island Architecture
まとめ
• Nuxt Server Components は動的な部分に静的なコンテンツを埋め込 む技術 • Nuxt Server Components
を使うことで client bundle を減らすこと ができる • Nuxt Server Components は Teleport の使い方がおもしろい まとめ
まとめ • Remote Source もレンダリングできる • Server Page を作ることができる •
Lazy Server Component を作ることができる 話せていないことがいっぱいある
まとめ まだ experimental なので使ってフィードバックしよう