
こんにちは。よっしーです(^^)
今日は、SvelteKitのリファレンスについて解説しています。
背景
SvelteKitのリファレンスについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。
$app/state
SvelteKit は $app/state
モジュールを通じて3つの読み取り専用の状態オブジェクト — page
、navigating
、updated
— を利用可能にしています。 このモジュールはバージョン 2.12 で追加されました。それより前のバージョンの SvelteKit を使用している場合は、代わりに $app/stores
を使用してください。
import { navigating, page, updated } from '$app/state';
$app/state
モジュールは SvelteKit アプリケーションでナビゲーションや更新状態に関する情報にアクセスするための重要なユーティリティを提供します。このモジュールには以下の3つの主要なエクスポートが含まれています:
- page – 現在のページに関する情報(URL、パラメータ、ロードデータなど)を含むオブジェクトです。
- navigating – ページ間のナビゲーションが進行中の場合に情報を提供し、ナビゲーションがない場合は
null
となります。ローディングインジケータやトランジションの実装に役立ちます。 - updated – アプリケーションの新しいバージョンが利用可能になった場合に
true
となるプロパティです。これを使用して、ユーザーにアップデートを通知できます。
これらはすべて読み取り専用の状態オブジェクトであり、アプリケーション全体で現在の状態に関する一貫した情報を提供します。
バージョン 2.12 より前の SvelteKit では、同様の機能が $app/stores
モジュールを通じて提供されていましたが、現在は $app/state
の使用が推奨されています。
次のセクションで、各状態オブジェクトの詳細な説明を行います。
navigating
進行中のナビゲーションを表す読み取り専用オブジェクトで、from
、to
、type
、および(type === 'popstate'
の場合)delta
プロパティを持ちます。ナビゲーションが発生していない場合やサーバーレンダリング中は値が null
になります。
const navigating:
| import('@sveltejs/kit').Navigation
| {
from: null;
to: null;
type: null;
willUnload: null;
delta: null;
complete: null;
};
解説
navigating
は SvelteKit の $app/state
モジュールが提供する状態オブジェクトで、以下のような特徴があります:
- ナビゲーション状態の追跡 – アプリケーション内でのナビゲーションの進行状況を追跡します。
- プロパティ:
from
– ナビゲーション元のページに関する情報(URL、パラメータなど)to
– ナビゲーション先のページに関する情報type
– ナビゲーションのタイプ(link
、popstate
、goto
など)delta
–type === 'popstate'
(ブラウザの戻る/進むボタンによるナビゲーション)の場合の履歴スタックの変化量willUnload
– ナビゲーションがページのアンロードを引き起こすかどうかを示すブール値complete
– ナビゲーションの完了を示す Promise
- null 状態 – ナビゲーションが進行中でない場合や、サーバーサイドレンダリング中は、すべてのプロパティが
null
になります。
使用例
<script>
import { navigating } from '$app/state';
// ナビゲーション中かどうかを表す計算プロパティ
$: isNavigating = $navigating !== null;
// ナビゲーションタイプに基づく条件付きロジック
$: {
if ($navigating) {
console.log(`ナビゲーションタイプ: ${$navigating.type}`);
console.log(`移動元: ${$navigating.from.url.pathname}`);
console.log(`移動先: ${$navigating.to.url.pathname}`);
if ($navigating.type === 'popstate') {
console.log(`履歴の移動量: ${$navigating.delta}`);
}
}
}
</script>
<!-- ナビゲーション中にローディングインジケータを表示 -->
{#if isNavigating}
<div class="loading-indicator">
<svg class="spinner" viewBox="0 0 50 50">
<circle class="path" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
</svg>
<p>ページ読み込み中...</p>
<p>
{$navigating.from.url.pathname} から {$navigating.to.url.pathname} へ移動しています
</p>
</div>
{/if}
<!-- ナビゲーションタイプに基づいたトランジション -->
<div class={$navigating ? `transition-${$navigating.type}` : ''}>
<!-- ページコンテンツ -->
<slot />
</div>
<style>
.loading-indicator {
position: fixed;
top: 0;
left: 0;
right: 0;
background: rgba(255, 255, 255, 0.8);
padding: 1rem;
text-align: center;
z-index: 1000;
}
.spinner {
width: 50px;
height: 50px;
animation: rotate 2s linear infinite;
}
.path {
stroke: #007bff;
stroke-linecap: round;
animation: dash 1.5s ease-in-out infinite;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
}
}
/* ナビゲーションタイプに基づいたトランジションスタイル */
.transition-link {
animation: fade 0.3s;
}
.transition-popstate {
animation: slide 0.3s;
}
@keyframes fade {
from { opacity: 0.5; }
to { opacity: 1; }
}
@keyframes slide {
from { transform: translateX(10px); }
to { transform: translateX(0); }
}
</style>
navigating
オブジェクトは、以下のようなシナリオで特に役立ちます:
- ローディングインジケータ – ページナビゲーション中にローダーやプログレスバーを表示する。
- トランジションアニメーション – ナビゲーションのタイプ(リンククリック、履歴ナビゲーションなど)に基づいて異なるトランジションを適用する。
- フォーム送信の防止 – ナビゲーション中に追加のフォーム送信を防止する。
- ナビゲーション追跡 – アナリティクスのためにナビゲーションを追跡する。
- 条件付きレンダリング – ナビゲーション中に特定のUI要素を表示または非表示にする。
navigating
オブジェクトを使用することで、よりスムーズで洗練されたユーザー体験を提供するインタラクションを実装できます。
page
現在のページに関する情報を持つ読み取り専用のリアクティブオブジェクトで、以下のようなユースケースに役立ちます:
- コンポーネントツリーのどこからでも、すべてのページ/レイアウトの組み合わされた
data
を取得する(データの読み込みも参照) - コンポーネントツリーのどこからでも、
form
プロパティの現在の値を取得する(フォームアクションも参照) goto
、pushState
、またはreplaceState
を通じて設定されたページ状態を取得する(goto とシャロールーティングも参照)- 現在いる URL、現在のルートとそのパラメータ、エラーが発生したかどうかなどのメタデータを取得する
+layout の例
<script lang="ts">
import { page } from '$app/state';
</script>
<p>現在 {page.url.pathname} にいます</p>
{#if page.error}
<span class="red">問題が検出されました</span>
{:else}
<span class="small">すべてのシステムは正常に動作しています</span>
{/if}
page
の変更は、ルーンを使用した場合にのみ利用可能です。(レガシーなリアクティビティ構文では変更が反映されません)
+page の例
<script lang="ts">
import { page } from '$app/state';
const id = $derived(page.params.id); // これはこのページで使用する id を正しく更新します
$: badId = page.params.id; // 使用しないでください。初期ロード後に更新されません
</script>
サーバー上では、レンダリング中にのみ値を読み取ることができます(つまり、load
関数などでは読み取れません)。ブラウザでは、いつでも値を読み取ることができます。
const page: import('@sveltejs/kit').Page;
解説
page
は SvelteKit の $app/state
モジュールが提供する状態オブジェクトで、以下のような特徴があります:
- 現在のページ情報 – URL、パラメータ、データ、エラー状態などの現在のページに関する情報を提供します。
- リアクティブな値 –
page
の値はリアクティブであり、ナビゲーションに応じて自動的に更新されます。 - 主なプロパティ:
page.url
– 現在のページの URL 情報(pathname
、search
、hash
など)page.params
– ルートパラメータ(例:/blog/[slug]
のslug
値)page.route
– 現在のルート IDpage.status
– HTTP ステータスコードpage.error
– エラーが発生した場合、そのエラーオブジェクトpage.data
– すべてのページ/レイアウトload
関数から返されたデータの組み合わせpage.form
– フォームアクションから返されたデータpage.state
–goto
、pushState
、またはreplaceState
を通じて設定された状態
- ルーンとの互換性 – SvelteKit 2 では、
page
の変更はルーン構文($derived
など)を使用した場合にのみ正しく反映されます。従来の Svelte のリアクティビティ構文($:
)では、初期値以降の変更が反映されません。 - サーバーサイドの制限 – サーバーサイドでは、レンダリング中(コンポーネント内)でのみ値にアクセスでき、
load
関数などでは利用できません。
使用例
<script>
import { page } from '$app/state';
// ルーンを使ったリアクティブな値の取得
const pathname = $derived(page.url.pathname);
const slug = $derived(page.params.slug);
const userData = $derived(page.data.user);
const formData = $derived(page.form);
// 現在のルートに基づいた条件付きロジック
const isHomePage = $derived(page.url.pathname === '/');
const isBlogPost = $derived(page.route.id?.startsWith('/blog/'));
// エラーハンドリング
const hasError = $derived(page.error !== null);
const errorMessage = $derived(page.error?.message ?? '');
</script>
<!-- 現在のページ情報の表示 -->
<header>
<h1>現在のページ: {pathname}</h1>
{#if page.params.slug}
<h2>スラグ: {page.params.slug}</h2>
{/if}
</header>
<!-- データの使用 -->
{#if userData}
<div class="user-profile">
<img src={userData.avatar} alt="プロフィール画像" />
<h3>{userData.name}</h3>
<p>{userData.bio}</p>
</div>
{/if}
<!-- ナビゲーション状態に基づいたUI -->
<nav>
<ul>
<li class:active={isHomePage}><a href="/">ホーム</a></li>
<li class:active={pathname === '/about'}><a href="/about">会社概要</a></li>
<li class:active={pathname === '/contact'}><a href="/contact">お問い合わせ</a></li>
<li class:active={isBlogPost}><a href="/blog">ブログ</a></li>
</ul>
</nav>
<!-- エラー表示 -->
{#if hasError}
<div class="error-container">
<h2>エラーが発生しました</h2>
<p>{errorMessage}</p>
<p>ステータスコード: {page.status}</p>
</div>
{/if}
<!-- フォームデータの表示 -->
{#if formData}
<div class="form-results">
<h3>送信結果:</h3>
<pre>{JSON.stringify(formData, null, 2)}</pre>
</div>
{/if}
<style>
.active {
font-weight: bold;
text-decoration: underline;
}
.error-container {
border: 2px solid red;
padding: 1rem;
margin: 1rem 0;
background-color: #ffeeee;
}
.user-profile {
border: 1px solid #ccc;
padding: 1rem;
margin: 1rem 0;
}
</style>
page
オブジェクトは、以下のようなシナリオで特に役立ちます:
- 条件付きレンダリング – 現在のルートやパラメータに基づいて UI を条件付きでレンダリングする。
- ナビゲーション状態の反映 – 現在のパスに基づいてナビゲーションメニューでアクティブなアイテムをハイライト表示する。
- データアクセス – コンポーネントツリーのどこからでも、
load
関数から返されたデータにアクセスする。 - フォームフィードバック – フォームアクションの結果を表示する。
- エラー処理 – カスタムエラー UI を表示する。
- 動的メタデータ – 現在のページに基づいてタイトルやメタタグを設定する。
SvelteKit 2 を使用している場合は、page
オブジェクトの変更を正しく追跡するために、ルーン構文($derived
など)を使用することが重要です。
updated
初期値が false
の読み取り専用リアクティブ値です。version.pollInterval
が非ゼロ値の場合、SvelteKit はアプリケーションの新しいバージョンをポーリングで確認し、新バージョンを検出すると current
を true
に更新します。updated.check()
はポーリングに関係なく、即時チェックを強制します。
const updated: {
get current(): boolean;
check(): Promise<boolean>;
};
解説
updated
は SvelteKit の $app/state
モジュールが提供する状態オブジェクトで、以下のような特徴があります:
- アプリケーション更新の検出 – アプリケーションの新しいバージョンが利用可能になったかどうかを追跡します。
- プロパティとメソッド:
current
– 新しいバージョンが利用可能な場合にtrue
となる読み取り専用のブール値check()
– 新しいバージョンを即時にチェックするメソッド。新しいバージョンが利用可能な場合はtrue
を解決する Promise を返します
- 設定との関連 – この機能は
version.pollInterval
が設定されている場合にのみ機能します。これはsvelte.config.js
で設定できます。 - ユースケース – ユーザーに新しいバージョンが利用可能であることを通知し、アプリケーションを更新するオプションを提供するために使用されます。
使用例
<script>
import { updated } from '$app/state';
// 更新が利用可能かどうかをチェックする関数
async function checkForUpdates() {
const hasUpdate = await updated.check();
if (hasUpdate) {
console.log('新しいバージョンが利用可能です');
} else {
console.log('アプリケーションは最新です');
}
}
// コンポーネントがマウントされたときに更新をチェック
import { onMount } from 'svelte';
onMount(() => {
// 初回チェック
checkForUpdates();
});
</script>
<!-- 更新通知バナー -->
{#if $updated.current}
<div class="update-banner">
<p>新しいバージョンが利用可能です!</p>
<button on:click={() => location.reload()}>
更新する
</button>
</div>
{/if}
<!-- 手動更新チェックボタン -->
<button on:click={checkForUpdates}>
更新を確認
</button>
<style>
.update-banner {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #4caf50;
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 1000;
}
button {
background: white;
color: #4caf50;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
button:hover {
background: #f0f0f0;
}
</style>
設定例(svelte.config.js
):
// svelte.config.js
import adapter from '@sveltejs/adapter-auto';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter(),
version: {
// 1分(60,000ミリ秒)ごとに更新をチェック
pollInterval: 60000
}
}
};
export default config;
アプリケーション全体での使用例(+layout.svelte
):
<script>
import { updated } from '$app/state';
import { fade } from 'svelte/transition';
let dismissedUpdate = false;
function dismissUpdate() {
dismissedUpdate = true;
}
function refreshApp() {
location.reload();
}
</script>
<slot />
<!-- 更新通知 -->
{#if $updated.current && !dismissedUpdate}
<div class="update-notification" transition:fade={{ duration: 300 }}>
<div class="content">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M23 12l-3.36-.83L21 8l-3.2-1.6L17 3l-3.22 1.61L10.56 3 8.5 7l-3.2 1.6 1.36 3.17L3 12l3.36.83L5 16l3.2 1.6L10 22l3.22-1.61L16.44 22l2.06-4 3.2-1.6-1.36-3.17L23 12z"/>
</svg>
<p>アプリケーションの新しいバージョンが利用可能です</p>
</div>
<div class="actions">
<button class="dismiss" on:click={dismissUpdate}>
後で
</button>
<button class="update" on:click={refreshApp}>
今すぐ更新
</button>
</div>
</div>
{/if}
<style>
.update-notification {
position: fixed;
bottom: 20px;
right: 20px;
background: white;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: 8px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
max-width: 320px;
z-index: 1000;
}
.content {
display: flex;
align-items: center;
gap: 12px;
}
.content svg {
color: #4caf50;
flex-shrink: 0;
}
.actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
button {
padding: 8px 16px;
border-radius: 4px;
font-weight: 500;
cursor: pointer;
border: none;
}
.dismiss {
background: transparent;
color: #666;
}
.update {
background: #4caf50;
color: white;
}
.dismiss:hover {
background: #f0f0f0;
}
.update:hover {
background: #43a047;
}
</style>
updated
オブジェクトは、以下のようなシナリオで特に役立ちます:
- アプリケーション更新通知 – ユーザーに新しいバージョンが利用可能であることを通知し、更新オプションを提供する。
- 強制更新 – セキュリティ修正など、重要な更新がある場合に、ユーザーに更新を促す。
- バックグラウンド更新 – ユーザーの邪魔をせずに、バックグラウンドでアプリケーションを更新する。
- 更新スケジュール – 特定の条件(例:アイドル時間中)に基づいて更新を提案する。
SvelteKit のこの機能を使用することで、ユーザーに常に最新バージョンのアプリケーションを使用してもらうことができ、バグ修正やセキュリティ更新が確実にすべてのユーザーに届くようになります。
おわりに
今日は、 SvelteKitのリファレンスについて解説しました。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント