Nuxtとは
Nuxtとは、一言で言うと「Vueを便利にしたヤツ」です。
コンポーネント内のルールは基本的にVue.jsと同様です。
なので、Nuxtの学習をする際は、「プレーンなVue.jsと比較して何が違うのか」という点を理解することが重要です。
新規アプリケーションの作成
以下コマンドを実行することで、Nuxt3の新規アプリケーションが作成されます。
npx nuxi@latest init アプリケーション名
作成されてディレクトリに移動し、「npm run dev」コマンドを実行することで、開発サーバーが起動します。
cd アプリケーション名
npm run dev -- -o
開発サーバーが起動されていると、以下のようなNuxt3のウェルカムページが表示されます。Nuxtアプリケーションの作成ができました👏
ディレクトリ構成
./
├── .git
├── .gitignore
├── .nuxt
├── README.md
├── app.vue
├── node_modules
├── nuxt.config.ts
├── package-lock.json
├── package.json
├── public
├── server
└── tsconfig.json
新規でアプリケーションを作成すると、👆のようなファイル・フォルダが作成されます。その中でも重要なものについて以下で紹介します。
app.vue
Vueで言うところのApp.vue
で、Nuxtアプリケーションのルートコンポーネントです。
このファイルは、アプリケーション全体のレイアウトを定義するために使用されます。すべてのページやコンポーネントはこのファイル内でレンダリングされます
nuxt.config.ts
Nuxtアプリケーションの設定ファイルで、アプリケーションの全体的な設定、プラグインの追加、モジュールの設定、環境変数の定義などを行うことができます。
このファイルを使用して、Nuxtアプリケーションの挙動をカスタマイズします。
ルーティング
Vue.jsを使用したアプリケーション開発を行う際には、別途VueRouterをインストールすることで、ルーティングを実装しますが、Nuxtでは追加でライブラリのインストールをせずにルーティングを実装することができます。
Nuxtでは、「ファイルシステムルーティング」と呼ばれるシステムにより、ディレクトリ構造を元に自動的にルーティングを設定することができます。この機能を使用すると、手動でルートを設定する必要がなくなり、プロジェクトの構造がより直感的になります
基本
ファイルシステムルーティングを使用するには、app.vue
ファイルに<NuxtePage />
を追加してください。
<NuxtePage />
とはVueRouterで言うところの<router-view />
で、この<NuxtePage />
の部分に、アクセスされたURLに該当するコンポーネントが表示されます。
<template>
<div>
<NuxtPage />
</div>
</template>
次に、プロジェクトルートにpages
ディレクトリを作成してください。
ファイルシステムルーティングは、このpages
ディレクトリ配下で定義されたコンポーネントを元にルーティングを行います。
例えば、pages
ディレクトリ配下にabout.vue
を追加します。
<template>
<div>
<h1>About page</h1>
</div>
</template>
ブラウザで「/about」にアクセスすると、上記で定義したコンポーネントpages/about.vue
が表示されます。
このように、アクセスさえたURLに対し、pages/
配下から該当するコンポーネントを表示します。
「/」のようにルートにアクセスがあった場合はpages/index.vue
が表示されます。
「/about」の場合でも、上記で紹介したpages/about.vue
でもいいですが、pages/about/index.vue
でも定義することが可能です。ですが、pages/about.vue
とpages/about/index.vue
両方が定義されている場合は、pages/about.vue
が優先的に表示されます。
ダイナミックルーティング
「/users/1」のように、パスパラメーターを定義したい場合には、/pages/users/[id].vue
のようにコンポーネントを定義します。
<template>
<div>
<h1>User: {{ $route.params.id }}</h1>
</div>
</template>
<template>
内からパスパラメータにアクセスする際には、$route.params
からアクセスすることができます。
<script>
内で、パスパラメーターにアクセスする際には、useRoute
メソッドを使用してルートの状態を取得し、params
から該当するパラメータにアクセスします。
<script lang="ts" setup>
const route = useRoute();
console.log(route.params.id); // 1
</script>
パラメータ名は自由に指定することができます。例えば/pages/users/[user_id].vue
のように指定した場合は、$route.params.user_id
のようにアクセスする必要があります。
また、パラメータはディレクトリ名で表現することも可能です。「/users/1/likes」のようなパスに対するコンポーネントを作成する際には、/pages/users/[id]/likes.vue
のように定義することができます。
アクセスされたURL | 表示されるコンポーネント |
---|---|
/ | pages/index.vue |
/about | pages/about.vue または pages/about/index.vue |
/users | pages/users.vue または pages/users/index.vue |
/users/1 | pages/users/[id].vue または pages/users/[id]/index.vue |
/users/1/likes | pages/users/[id]/likes.vue または pages/users/[id]/likes/index.vue |
また、pages
ディレクトリから該当するページが見つからない場合は、以下のようにNuxtで用意された404ページが表示されます。
画面遷移
template
内では、NuxtLink
を使用して画面遷移リンクを作成することができます。propsのto
には、遷移先のURLを指定します。
<NuxtLink to="/about">About</NuxtLink>
<NuxtLink to="/">Home</NuxtLink>
script
内で画面遷移を実装する場合は、navigateTo
メソッドを使用します。
navigateTo("/about");
エラーページ
Nuxtでは、コンポーネントのレンダリング時に何かしらのエラーが発生した場合や、存在しないURLに対してユーザーがアクセスを行った場合に表示するカスタムエラーページを作成することができます。
アプリケーションルートにerror.vue
という名前でコンポーネントを作成します。propsとしてエラーオブジェクトを受け取り、エラーの内容を画面に表示するようなものです。
<template>
<div>
<h1>{{ error.statusCode }}</h1>
<NuxtLink to="/">Go back home</NuxtLink>
</div>
</template>
<script setup lang="ts">
import type { NuxtError } from "#app";
const props = defineProps({
error: Object as () => NuxtError,
});
</script>
試しに、存在しないURLに対してアクセスを行ったり、コンポーネントのレンダリング時に何かエラーが発生すると、以下のようにerror.vue
の内容が表示されます。
middleware
Nuxtでは、特定のルートへアクセスする際に処理を挟み込むことができる機能を提供しています。
ユーザーの認証、リダイレクト、ログインチェックなど、ルートに関連するロジックを実行するために使用されることが多いです。
ミドルウェアはmiddleware
ディレクトリで定義しましょう。defineNuxtRouteMiddleware
を使用することでミドルウェアを定義することができます。navigateTo
で、遷移先を指定できて、abortNavigation
を使用することで遷移を中断できます。
export default defineNuxtRouteMiddleware((to, from) => {
const user = getUser();
if (!user.isLoggedIn) {
return navigateTo('/login'); // ログイン画面に遷移
}
if (!user.isValid) {
return abortNavigation(); // 遷移を中断
}
});
ミドルウェアの適用は、各ページコンポーネントで行います。definePageMeta
のmiddleware
オプションを使用します。適用するミドルウェアは配列形式で渡します。その為、1つのページに対して複数のミドルウェアを適用することも可能です。
<template>
<div>
<h1>About page</h1>
</div>
</template>
<script lang="ts" setup>
definePageMeta({
middleware: ["auth"],
});
</script>
また、ミドルウェアを定義したファイル名に.global
を付与することで、全てのページに対して適用されるミドルウェアを設定することもできます。
例えば今回作成したmiddleware/auth.ts
を、middleware/auth.global.ts
にすることで、全てのコンポーネントに対してミドルウェアが適用されます。
layouts
Nuxtでは、Layoutという仕組みを提供しています。
レイアウトでは、アプリケーション全体また特定の画面グループで共通のテンプレートを定義するための仕組みです。
これにより、各ページで共通する部分(ヘッダー、フッター、ナビゲーションバーなど)を一箇所で管理できます。
アプリケーションルートに、layouts
という名前でディレクトリを作成してください。ルールとして、レイアウト定義ファイルはlayouts
ディレクトリの配下に置く必要があります。
layouts
ディレクトリ配下にdefault.vue
という名前で以下のようなコンポーネントを作成してください。
<slot />
の位置に、画面毎のコンポーネントが表示されます。
<template>
<div>
<nav class="navigation_bar">
My awesome app
</nav>
<slot />
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.navigation_bar {
width: 100%;
height: 50px;
background-color: rgb(246, 150, 24);
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style>
次に、app.vue
の記述を以下のように変更してください。NuxtLayout
を追加することでLayoutsシステムを使用することができます。
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
これでレイアウトの適用が完了しました。ブラウザで色々な画面に遷移しても、常にlayouts/default.vue
で定義した内容が表示されるようになります。
また、definePageMeta
というメソッドのlayout
オプションを各コンポーネントで指定することで、デフォルトのレイアウトを適用したくない。または他のレイアウトを使用することもできます。
layout
でfalse
を指定することで、レイアウトの適用を無効化することができます。
<template>
<div>
<h1>About page</h1>
</div>
</template>
<script lang="ts" setup>
definePageMeta({
layout: false,
});
</script>
layout
で、名前を指定することで、layouts
配下の同名のレイアウトが適用されます。
<template>
<div>
<nav class="custom_navigation_bar">
costom
</nav>
<slot />
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
.custom_navigation_bar {
width: 100%;
height: 50px;
background-color: rgb(24, 183, 246);
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: bold;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
</style>
<template>
<div>
<h1>About page</h1>
</div>
</template>
<script lang="ts" setup>
definePageMeta({
layout: "custom",
});
</script>
Auto Imports
Nuxt3では「Auto Imports」という機能があり、特定のディレクトリ配下のコンポーネントはimport文を記述せずにインポートすることができます。
<template>
<div>
<Card />
</div>
</template>
<script lang="ts" setup>
</script>
デフォルトでAuto Importsが有効化されているのは、components/
、composables/
、utils/
です。
これらはnuxt.config.ts
にて、無効化・カスタマイズが可能です。
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
devtools: { enabled: true },
imports: {
autoImport: false // 無効化
}
})
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
devtools: { enabled: true },
imports: {
dirs: ["some_dir/**"], // some_dir配下をAuto importの対象に追加
}
})
server
Nuxt3では、server/
ディレクトリを利用して、サーバーサイドで実行される処理を定義することができます。
これを利用して、APIエンドポイントを実装することができます。
早速APIを作成してみましょう。以下のようにserver/api/hello.ts
を定義してください。サーバー側の処理を定義する際には、defineEventHandler
というメソッドを使用します。
export default defineEventHandler((event) => {
return {
hello: "world",
};
});
定義したAPIを、クライアントサイドから実行してみましょう。
Nuxtでは、データフェッチを行う際にはuseFetch
というメソッドを使用します。今回はserver/api/hello.ts
でAPIを作成したので、エンドポイントは/api/hello
となります。
<template>
<div>
<h1>About page</h1>
<pre>{{ data }}</pre>
</div>
</template>
<script lang="ts" setup>
const { data } = await useFetch("/api/hello");
</script>
以下のように、正常にデータフェッチができていることが確認できます。
また、HTTPメソッド毎に処理を分けたい場合には、ファイル名を変えてあげるだけで可能です。.get
、.post
、.put
、.delete
を用いて定義したAPI Routeが対応するHTTPメソッドを指定することができます。
例えば以下のように、/api/hello
というエンドポイントでGET、POSTを作成してみます。
export default defineEventHandler((event) => {
return {
message: "HTTP method is GET!",
};
});
export default defineEventHandler((event) => {
return {
message: "HTTP method is POST!",
};
});
GETでリクエストを送った際には、server/api/hello.get.ts
で定義したサーバーアクションが実行されます。
<template>
<div>
<h1>About page</h1>
<pre>{{ data }}</pre>
</div>
</template>
<script lang="ts" setup>
const { data } = await useFetch("/api/hello");
</script>
POSTでリクエストを送った際には、server/api/hello.post.ts
で定義したサーバーアクションが実行されます。
<template>
<div>
<h1>About page</h1>
<pre>{{ data }}</pre>
</div>
</template>
<script lang="ts" setup>
const { data } = await useFetch("/api/hello", {
method: "post",
});
</script>
上記では単純に文字列を返却するAPI Routeを作成しましたが、Prisma等を使用してデータベースアクセスを行右ことも可能なので、本格的なAPIを実装することも可能です。
レンダリング手法の選択
Nuxtでは、ページのレンダリング方法を選択することができます。こちらは少し長くなるので、また別の記事でご紹介しようと思います。