Nuxt.js
Vue.jsエコシステムの標準的フルスタックフレームワーク。Composition APIとTypeScript統合により、大規模アプリケーション開発を強力にサポート。
GitHub概要
スター57,911
ウォッチ787
フォーク5,339
作成日:2016年10月26日
言語:TypeScript
ライセンス:MIT License
トピックス
csrframeworkfull-stackhacktoberfesthybridnodenuxtserver-renderingssgssrstatic-site-generatoruniversalvue
スター履歴
データ取得日時: 2025/8/13 01:43
フレームワーク
Nuxt.js
概要
Nuxt.jsは、Vue.jsをベースとした無料でオープンソースのフルスタックWebフレームワークです。型安全で高性能、プロダクション対応のWebアプリケーションやウェブサイトの構築を設計されています。開発者が機能に集中できるよう、規約と自動化を提供してWeb開発を簡素化することを目的としています。
詳細
主要な特徴
- 多様なレンダリングモード: サーバーサイドレンダリング(SSR)をデフォルトとし、静的サイト生成(SSG)、ハイブリッドレンダリング、エッジサイドレンダリングなど様々なレンダリング戦略をサポート
- ファイルベースルーティング:
pages/
ディレクトリの構造に基づいて自動的にルートが生成され、ルート設定を簡素化 - コード分割: 初期読み込み時間を短縮するため、自動的にコードを小さなチャンクに分割
- 自動インポート: Vue composables、コンポーネント、ユーティリティを明示的にインポートすることなく使用でき、ツリーシェイキングと最適化されたJSバンドルの恩恵を受けることができる
- データ取得ユーティリティ: SSR対応のデータ取得用composablesを提供
- ゼロ設定TypeScriptサポート: 自動生成される型を含む組み込みTypeScriptサポート
- 設定済みビルドツール: 開発時のホットモジュール置換(HMR)と本番向け最適化ビルドのためにViteをデフォルトで使用。Webpack、Rspackも代替バンドラーとしてサポート
- サーバーエンジン(Nitro): フルスタック機能、APIルート、サーバーレスサポート、クロスプラットフォームデプロイメントを可能にするサーバーエンジン
アーキテクチャ
Nuxt.jsは、モジュラーアーキテクチャを採用しており、必要な機能のみを選択して使用できます。フレームワークのコアには、Vue.js、Vue Router、Vite/Webpack、h3、Nitroなどの実績のあるツールが統合されています。
メリット・デメリット
メリット
- 優れたSEO: サーバーサイドレンダリングにより、検索エンジンがページをより適切にインデックス化可能
- 高速な初期ページ読み込み: SSRによりブラウザに完全にレンダリングされたHTMLページが送信され、体感読み込み時間が向上
- 優れた開発者体験: 自動インポート、ゼロ設定TypeScript、規約による設定で開発速度が向上
- 柔軟なレンダリング: ユニバーサルレンダリング(SSR)、CSR、ハイブリッドレンダリング、エッジサイドレンダリングなど、細かい制御が可能
- フルスタック対応:
server/
ディレクトリとNitroエンジンにより、単一フレームワーク内でフロントエンドとバックエンドの両方を構築可能 - パフォーマンス: 低性能デバイスでも優れたパフォーマンスを発揮
- アクセシビリティ: コンテンツが即座に利用可能で、支援技術を助ける
デメリット
- 開発の制約: サーバーとブラウザの両方の環境でシームレスに動作するコードを書くことは、APIの違いにより困難な場合がある
- 運用コスト: オンザフライレンダリング用のサーバー運用には月額費用が発生(エッジサイドレンダリングの活用により軽減可能)
- 学習コストの上昇: Vue.jsに加えてNuxt.js固有の概念や規約を学ぶ必要がある
- 過剰機能: シンプルなSPAには機能が多すぎる場合がある
主要リンク
書き方の例
Hello World
<!-- pages/index.vue -->
<template>
<div>
<h1>{{ title }}</h1>
<p>Welcome to Nuxt!</p>
</div>
</template>
<script setup>
// Composition API with auto-import
const title = 'Hello Nuxt!'
// Meta管理
useHead({
title: 'Home',
meta: [
{ name: 'description', content: 'My amazing site.' }
]
})
</script>
ページルーティングとナビゲーション
<!-- pages/about.vue -->
<template>
<div>
<h1>About Page</h1>
<NuxtLink to="/">ホームに戻る</NuxtLink>
<NuxtLink to="/products">商品一覧</NuxtLink>
</div>
</template>
<!-- pages/products/[id].vue - 動的ルート -->
<template>
<div>
<h1>Product: {{ $route.params.id }}</h1>
<button @click="$router.back()">戻る</button>
</div>
</template>
<script setup>
// パラメータの取得
const route = useRoute()
const productId = route.params.id
</script>
データフェッチング
<template>
<div>
<h1>ユーザー一覧</h1>
<div v-if="pending">読み込み中...</div>
<div v-else-if="error">エラー: {{ error }}</div>
<ul v-else>
<li v-for="user in data" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<button @click="refresh()">更新</button>
</div>
</template>
<script setup>
// useFetch - SSR対応データフェッチング
const { data, pending, error, refresh } = await useFetch('/api/users')
// useLazyFetch - 非同期フェッチング
const { data: posts } = await useLazyFetch('/api/posts')
// $fetch - 手動フェッチング
const submitForm = async (formData) => {
try {
const result = await $fetch('/api/submit', {
method: 'POST',
body: formData
})
console.log('送信成功:', result)
} catch (error) {
console.error('送信エラー:', error)
}
}
</script>
ステート管理(Pinia)
// stores/counter.js
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
function reset() {
count.value = 0
}
return { count, doubleCount, increment, reset }
})
<!-- pages/counter.vue -->
<template>
<div>
<h1>カウンター: {{ counter.count }}</h1>
<p>ダブル: {{ counter.doubleCount }}</p>
<button @click="counter.increment()">+1</button>
<button @click="counter.reset()">リセット</button>
</div>
</template>
<script setup>
const counter = useCounterStore()
</script>
サーバーAPI
// server/api/users.js
export default defineEventHandler(async (event) => {
const method = getMethod(event)
if (method === 'GET') {
// ユーザー一覧の取得
return await getUsersFromDatabase()
}
if (method === 'POST') {
// 新規ユーザーの作成
const body = await readBody(event)
return await createUser(body)
}
})
// server/api/users/[id].js
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
const method = getMethod(event)
if (method === 'GET') {
return await getUserById(id)
}
if (method === 'PUT') {
const body = await readBody(event)
return await updateUser(id, body)
}
if (method === 'DELETE') {
return await deleteUser(id)
}
})
ミドルウェアと認証
// middleware/auth.js
export default defineNuxtRouteMiddleware((to, from) => {
const user = useAuthUser()
if (!user.value) {
return navigateTo('/login')
}
})
// middleware/admin.global.js - グローバルミドルウェア
export default defineNuxtRouteMiddleware((to) => {
if (to.path.startsWith('/admin')) {
const user = useAuthUser()
if (!user.value?.isAdmin) {
throw createError({
statusCode: 403,
statusMessage: 'Access Denied'
})
}
}
})
<!-- pages/profile.vue -->
<script setup>
// ページレベルでミドルウェアを適用
definePageMeta({
middleware: 'auth'
})
</script>