私は+page.svelteにコードを書いています。書いたコードがapp.htmlに反映されます。レンダリングはどの部分で行われているかイメージがつきません。
SvelteKitのレンダリングの流れが掴みづらいということですね!
ここでは、SvelteKitがどのように+page.svelte
のコードを処理し、app.html
に反映するのか を詳しく説明します。
SvelteKitでは、+page.svelte
のコードがどのように処理され、ブラウザに表示されるのかを分解すると、次のような流れになります。
https://example.com/
にアクセスしたとします。+page.svelte
のコードが実行されます。+page.svelte
を解析し、HTMLを生成onMount
は実行されないapp.html
に組み込まれ、クライアント(ブラウザ)に送信される📌 この処理のイメージ
ユーザーがURLにアクセス → サーバーが `+page.svelte` をレンダリング → HTMLを生成しクライアントに送信
✅ サーバー側の出力
<!DOCTYPE html>
<html lang="ja">
<head>
<title>My App</title>
</head>
<body>
<div id="svelte"> <!-- ここにSSRされたHTMLが挿入される -->
<h1>こんにちは、世界!</h1>
</div>
</body>
</html>
これは SSRによってサーバー側で生成されたHTML です。
+page.svelte
のSvelteコンポーネントを有効化します。onMount
やクライアント側のコードが実行される📌 この処理のイメージ
サーバーからHTMLを受け取る → クライアントでSvelteのJSが実行される → `onMount` やインタラクティブな処理が動く
✅ この時点でのブラウザの動作
<script>
import { onMount } from 'svelte';
let message = "こんにちは、世界!";
onMount(() => {
console.log("このコードはブラウザでのみ実行される");
});
</script>
<h1>{message}</h1>
onMount
が動き、ブラウザコンソールに "このコードはブラウザでのみ実行される"
と表示される。✅ 例えば、ボタンを押すとカウントが増えるコード
<script>
let count = 0;
</script>
<button on:click={() => count++}>カウント: {count}</button>
ステップ | 説明 | どこで実行されるか |
---|---|---|
1. ユーザーがURLにアクセス | +page.svelte を処理 |
サーバー |
2. SSRがHTMLを生成 | app.html に組み込まれ、送信される |
サーバー |
3. クライアントでハイドレーション | onMount などが実行される |
ブラウザ |
4. ユーザー操作による再レンダリング | 状態の変化によってUIが更新される | ブラウザ |
app.html
の役割app.html
は SvelteKitがSSRで生成したHTMLを挿入するテンプレート<div id="svelte">
の部分に +page.svelte
のレンダリング結果が埋め込まれる📌 app.html のサンプル
<!DOCTYPE html>
<html lang="ja">
<head>
<title>SvelteKit App</title>
</head>
<body>
<div id="svelte"><!-- ここに `+page.svelte` のHTMLが入る --></div>
<script type="module" src="/_app/entry.js"></script> <!-- クライアント用JS -->
</body>
</html>
+page.svelte
の内容が <div id="svelte">
に差し込まれる。<script type="module" src="/_app/entry.js">
によってクライアント側のSvelteアプリが実行される。📌 SvelteKitのレンダリングのイメージ
+page.svelte
のHTMLを生成し、app.html
に埋め込む✔ SSR時にはサーバーでHTMLが生成される
✔ クライアントサイドでは onMount
などの処理が実行される
✔ ユーザー操作によるUIの変更はブラウザ上でレンダリングされる
これで SvelteKitのレンダリングの流れ がイメージしやすくなると思います! 🚀
ハイドレーションが分かりません。混乱するので分かりやすく教えてください。
簡単に言うと、「サーバーが生成した静的なHTMLを、クライアント(ブラウザ)でインタラクティブにするプロセス」 です。
ハイドレーションを レゴブロックに例えてみましょう。
SSR(サーバーサイドレンダリング)
ハイドレーション
SvelteKitでは、次のようなステップで SSRとハイドレーションが行われます。
ユーザーがページにアクセスすると、SvelteKitのサーバーは +page.svelte
を処理し、HTMLを生成 します。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>My App</title>
</head>
<body>
<div id="svelte">
<button>カウント: 0</button> <!-- ただの静的HTML -->
</div>
</body>
</html>
🔹 この時点では、ボタンを押しても何も起こりません。
🔹 なぜなら、まだ JavaScript が動いていないから!
entry.js
を実行(ハイドレーション開始)app.html
に含まれる <script>
を実行<script>
let count = 0;
</script>
<button on:click={() => count++}>カウント: {count}</button>
➡ この時点で、ボタンを押すとカウントが増えるようになる!
📌 サーバーが生成した静的なHTMLに、クライアントサイドでSvelteの機能を適用するプロセス。
📌 これにより、ブラウザ上でボタンが動くようになる。
もし ハイドレーションが行われなかったら どうなるでしょう?
on:click
が無効📌 つまり、ハイドレーションは「静的なHTMLをインタラクティブにする魔法」 なのです! ✨
✅ SSRによる高速な初回表示(最初からHTMLがあるので、画面がすぐ見える)
✅ クライアントサイドの動作も可能(ボタンなどが動くようになる)
✅ SEOやパフォーマンスの向上(検索エンジンがページの内容を読み取れる)
【SSRの段階】 サーバーからブラウザへ
┌──────────┐
│ <button>カウント: 0</button> │ ← ただのHTML
└──────────┘
【ハイドレーション】 JavaScriptが動く
┌──────────┐
│ <button onClick="動作">カウント: 0</button> │ ← JSが適用される
└──────────┘
【インタラクティブ】 ユーザーが操作
┌──────────┐
│ <button>カウント: 1</button> │ ← ボタンを押すと更新される
└──────────┘
❓「ハイドレーションって何?」
💡 サーバーが生成したHTMLを、クライアントでインタラクティブにする処理のこと!
❓「なぜ必要なの?」
💡 SSRだけだとボタンが動かないから、JSを使ってインタラクティブにするため!
❓「どうやって行われるの?」
💡 SvelteKitの entry.js
(クライアントサイドのJS)がロードされることで実行される!
これで、ハイドレーションの仕組みがスッキリ理解できたはず! 🚀
ハイドレーションの具体例を教えてください。
ハイドレーションの仕組みを コードと動作の違い を通して、もっと明確に理解できるようにしよう!
ここでは SSR(サーバーサイドレンダリング)だけの状態 と ハイドレーションが完了した後の状態 を比較するよ。
カウンターのボタンを押すと、数値が増えるシンプルな例
ユーザーが https://example.com
にアクセスした瞬間、サーバーが +page.svelte
を処理して、HTMLを生成 する。
この時点でのHTML(ただの静的HTML)
<!DOCTYPE html>
<html lang="ja">
<head>
<title>My App</title>
</head>
<body>
<div id="svelte">
<button>カウント: 0</button> <!-- ただのHTML、クリックしても何も起きない -->
</div>
</body>
</html>
📌 この時点では…
ページのHTMLがブラウザに表示された後、SvelteKitのクライアントJSが読み込まれて、ハイドレーションが行われる!
📌 この時点で何が起こる?
+page.svelte
のロジックをブラウザ上で適用するonMount
などが動作し始める実際の +page.svelte
のコード
<script>
let count = 0;
</script>
<button on:click={() => count++}>カウント: {count}</button>
✅ ハイドレーションが完了すると…
count
の値が Svelte によって管理されるようになるon:click
イベントが動くようになる次に、ユーザーが入力できるフォーム を使った例を見てみよう!
ページを開いたとき、サーバーが次のHTMLを生成する。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>My App</title>
</head>
<body>
<div id="svelte">
<input type="text" placeholder="名前を入力" />
</div>
</body>
</html>
📌 この時点では…
SvelteのJSが動き始めて、インタラクティブな動作が可能になる。
実際の +page.svelte
のコード
<script>
let name = "";
</script>
<input type="text" bind:value={name} placeholder="名前を入力" />
<p>あなたの名前: {name}</p>
✅ ハイドレーション後にできること
name
変数にバインドされる<p>
に入力した文字が反映される! 📝次は、APIからデータを取得する場合のハイドレーションの動き を見てみよう。
ページを開いた瞬間に、サーバーがデータを取得してHTMLを生成する場合:
<!DOCTYPE html>
<html lang="ja">
<head>
<title>My App</title>
</head>
<body>
<div id="svelte">
<ul>
<li>Loading...</li> <!-- まだデータがない -->
</ul>
</div>
</body>
</html>
📌 この時点では…
fetch
は onMount
の中で実行されるため、SSR時にはデータが取得されていないLoading...
しか表示されない+page.svelte
のコード:
<script>
import { onMount } from "svelte";
let items = [];
onMount(async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/todos?_limit=5");
items = await res.json();
});
</script>
<ul>
{#each items as item}
<li>{item.title}</li>
{/each}
</ul>
✅ ハイドレーション後の動作
onMount
が動き、データ取得が始まるitems
にデータが入る状態 | SSR時の動作 | ハイドレーション後 |
---|---|---|
カウンター | ボタンは表示されるが、押しても何も起こらない | count が更新され、ボタンが動く |
フォーム | 入力欄はあるが、入力した内容がリアルタイムで反映されない | bind:value によって入力値が動的に変わる |
APIデータ | Loading... のまま |
onMount でデータを取得し、リストが更新される |
💡 ハイドレーションとは?
➡ サーバーが生成した静的なHTMLを、ブラウザ側で動くようにする処理!
💡 なぜ必要?
➡ SSRだけではページは「見える」けど「動かない」から!
💡 どんな動作が変わる?
✅ ボタンが押せるようになる
✅ 入力フォームがリアルタイムで更新される
✅ APIデータが表示される
これで ハイドレーションの実例 が掴めたんじゃないかな?💡
「もうちょっと詳しく知りたい!」とか、「他の例も見たい!」があれば教えてね!🚀
どこかにクリックしたことや入力内容が保存されるのですか?分かりやすく簡潔に教えてください。
データが保存される場所は 「どう扱うか」 によって違うよ!
<script>
let count = 0;
</script>
<button on:click={() => count++}>カウント: {count}</button>
📌 どこに保存? → ブラウザのメモリだけ(リロードすると 0
に戻る)
<script>
import { onMount } from "svelte";
let count = 0;
onMount(() => {
count = Number(localStorage.getItem("count")) || 0;
});
function increment() {
count++;
localStorage.setItem("count", count);
}
</script>
<button on:click={increment}>カウント: {count}</button>
📌 どこに保存? → ブラウザのlocalStorage
(リロードしても残る)
store
(ページ移動してもデータが保持される)// stores.js
import { writable } from "svelte/store";
export const count = writable(0);
// +page.svelte
<script>
import { count } from "../stores.js";
</script>
<button on:click={() => count.update(n => n + 1)}>カウント: {$count}</button>
📌 どこに保存? → Svelteの store
(リロードすると消えるが、ページを移動しても保持される)
// +page.server.js
export function load({ cookies }) {
return { count: Number(cookies.get("count") || 0) };
}
export const actions = {
increment: async ({ cookies }) => {
let count = Number(cookies.get("count") || 0);
count++;
cookies.set("count", count.toString());
},
};
// +page.svelte
<script>
export let count;
</script>
<form method="POST" action="?/increment">
<button type="submit">カウント: {count}</button>
</form>
📌 どこに保存? → サーバーの cookies
(リロードしてもデータが保持される!)
方法 | リロード後のデータ | ページ移動後のデータ | 使う場面 |
---|---|---|---|
コンポーネントの変数 | 消える | 消える | 一時的なデータ |
localStorage | 保持される | 保持される | リロード後も残したいデータ |
store (writable ) |
消える | 保持される | アプリ全体で共有したいデータ |
サーバーセッション | 保持される | 保持される | ユーザーごとの情報(ログインなど) |
📌 まとめ
✅ ただの変数はリロードで 消える
✅ localStorage
に保存すれば リロードしても保持される
✅ store
を使うと ページ移動してもデータが保持される
✅ サーバー側で cookies
を使えば ユーザーごとにデータを管理できる
「この場合はどうする?」みたいな具体的な例があれば教えてね!🚀