Nuxt vs SvelteKit。どちらが優れているか?
それが今週私が試したことです。同じアプリを2回構築しました。1回はNuxt(バージョン5の互換性プレビューを有効にして)、もう1回はSvelteKit(実験的なリモート関数を使用して)です。
基本的なタスクアプリを作成しました。タスクの追加や削除ができます。また、ネットワークリクエストとタイミングも記録しました。最大の違いは、新しいタスクを作成する際に、SvelteKitアプリは1回のリクエストで済むのに対し、Nuxtアプリは2回必要だったことです。
その1つの違いが比較全体で最も興味深い部分だったので、詳しく見ていきましょう。
セットアップ
どちらのアプリも、ブラウザ内メモリストアをバックエンドとするシンプルなタスクリストです。どちらも本番ビルドをローカルで実行し、初期タスクリストはサーバーでレンダリングします。
注意点として、Nuxt 5はまだリリースされていません。私のNuxtアプリは、互換性フラグを設定した安定版のNuxt 4.5です:
// nuxt.config.ts
export default defineNuxtConfig({
compatibilityDate: '2026-07-01',
future: {
compatibilityVersion: 5,
},
})
Enter fullscreen mode Exit fullscreen mode
SvelteKitのリモート関数もドキュメントでまだ実験的とされています。そのため、これは完成した製品ではなく、方向性の比較です。
数値
Nuxtアプリでタスクを追加すると、/api/tasks へのPOSTリクエスト(約690ms)が発生し、その後リストを更新するためのGETリクエスト(約450ms)が続きます。合計で1,100msを超え、タイムラインパネルには2つのブラウザリクエストが表示されます。
SvelteKitアプリでタスクを追加すると、リクエストは1回だけです。約1,100ms。サーバーはミューテーションと読み取りの両方の操作を行いますが、単一のレスポンスで返されます。
通常のリフレッシュはほぼ同じでした。Nuxtで447ms、SvelteKitで448ms。複数回実行しましたが、SvelteKitの方がわずかに高速に感じました。ただし、全体の合計値は非常に近く、これだけでフレームワークを選ぶ理由にはなりません。
それぞれのリクエストの仕組みについて説明します。
Nuxt版:明示的なAPIルート
Nuxtを使ったことがある人には馴染みのある方法です。server/api に2つのハンドラがあります:
// server/api/tasks.get.ts
import { defineEventHandler } from 'h3'
import { readTasks } from '../utils/task-store'
export default defineEventHandler(() => readTasks())
Enter fullscreen mode Exit fullscreen mode
POSTハンドラはタイトルを検証し、タスクを保存します。これらは通常のHTTPエンドポイントです。HTTPを話せるものはすべてこれらを呼び出すことができます。
ページでは、useFetch がSSR中に初期データを読み込むため、ハイドレーション時に再度フェッチすることはありません。タスクを追加する際は、$fetch でPOSTし、その後 refresh() を呼び出します:
const { data: snapshot, refresh } = await useFetch<TaskSnapshot>('/api/tasks', {
key: 'task-dashboard',
})
async function submitTask() {
await $fetch('/api/tasks', {
method: 'POST',
body: { requestId: crypto.randomUUID(), title },
})
await refresh()
}
Enter fullscreen mode Exit fullscreen mode
コードは明示的で、ネットワークタブはコードと完全に一致します。最初にPOST、次にGET。
2回目のリクエストを避けることは可能でしょうか? もちろん可能です。POSTが更新されたリストを返し、ローカル状態を自分でパッチすることもできます。このように書いたのは、無効化と再フェッチが私たちの多くが使うワークフローであり、それがまさにSvelteKitのリモート関数が改善しようとしているパターンだからです。また、GETリクエストを追加することで、POST後の正確な出力を検証できる点も気に入っています。
SvelteKit版:リモート関数
これは実験的な機能です。svelte.config.js で有効にします:
const config = {
kit: {
adapter: adapter(),
experimental: {
remoteFunctions: true,
},
},
compilerOptions: {
experimental: {
async: true,
},
},
}
Enter fullscreen mode Exit fullscreen mode
次に、.remote.ts で終わるファイルを作成し、サーバー関数をエクスポートします:
// tasks.remote.ts
import { command, query } from '$app/server'
import { addTask as addTaskToStore, readTasks } from '$lib/server/task-store'
import * as v from 'valibot'
const taskInput = v.object({
requestId: v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(100)),
title: v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(80)),
})
export const getTasks = query(async () => readTasks())
export const addTask = command(taskInput, async ({ requestId, title }) => {
const result = await addTaskToStore(title, requestId)
// This runs on the server, and the refreshed query value
// comes back in the same command response.
void getTasks().refresh()
return result
})
Enter fullscreen mode Exit fullscreen mode
関数本体は常にサーバーで実行されます。ブラウザでは、SvelteKitが自動生成するエンドポイントの型付きラッパーになります。公開エンドポイントが存在せず、隔離されている点が気に入っています。呼び出しのために作成されるため、環境変数やシークレットを意識せずに使用できます。
void getTasks().refresh() の行は、サーバー側でリフレッシュをトリガーするAPIです。ミューテーションの後、SvelteKitはサーバー上でクエリをリフレッシュし、新しい値をコマンドのレスポンスにパッケージングします。これがシングルフライトリクエストであり、ネットワークタブに2つではなく1つのリクエストが表示される理由です。
ページでは、単に関数をインポートして呼び出すだけです:
<script lang="ts">
import { addTask, getTasks } from './tasks.remote'
const tasks = getTasks()
async function submitTask(event: SubmitEvent) {
event.preventDefault()
await addTask({ requestId: crypto.randomUUID(), title })
}
</script>
{@render dashboard(await tasks)}
Enter fullscreen mode Exit fullscreen mode
下部の await tasks はサブスクリプションのように動作します。サーバー側のリフレッシュが発生すると、タスクリストが自動的に更新されます。サーバールートを気にする必要はありません。
このパターンを初めて見たとき、少し複雑に感じました。しかしすぐに理解でき、コマンド内でのクエリリフレッシュというアイデアは、ネットワークタブで見ると理にかなっています。NextやTanStack Startのサーバーアクションを使ったことがある人には、親しみやすいはずです。TanStack Startのサーバーアクションの方が少し好きですが、これも近いです。
注意: リモート関数はSvelteKit 2.27以降で利用可能ですが、まだ実験的です。APIは過去数ヶ月で何度か変更されています。早期に採用する場合は、バージョンを固定し、移行のための時間を確保してください。
Nuxt 5は何を提供するのか?
Nuxt 5にはリモート関数に相当するものはありません。確認されている作業のほとんどは基盤構造にあります。新しいバージョンのNitro、新しいVite統合、そしてフレームワークの内部です。アップグレードガイドでは何が期待できるかが説明されており、主にアプリケーション レベルの新しいAPIではなく、基盤の作業です。
私の結論
私はNuxtを使い続けます。APIルートのパターンが好きで、Vueも好きです。このデモでは既存のアプリを書き換える理由にはなりません。ミューテーションから更新されたデータを返し、2回目のリクエストを自分でスキップすることは今日でも可能です。
ただし、サーバーアクションは恋しいです。SvelteKit、Next、TanStack Startなどのフレームワークには、コンポーネントから呼び出せる型付きの非公開サーバー関数のバージョンがあります。Nuxtも、現在のサーバーコンポーネントを超えて、将来的に似たようなものを追加してくれることを願っています。
SvelteKitプロジェクトを始める場合で、実験的なAPIを許容できるなら、まずリモート関数を試してみてください。シングルフライトリクエストは素晴らしいものであり、境界を越える型が無料で得られるのは優れた開発者体験です。
明示的なAPIルートと、トランスポートを自動生成するリモート関数、どちらの側に立ちますか? 同意するにせよ、反対するにせよ、コメントで教えてください。
ちなみに、この投稿と動画のすべての調査に Kiro を使用しました! ぜひチェックしてみてください。素晴らしいハーネスです!



0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.