Nuxt3→Nuxt4 移行ガイド：破壊的変更と移行の注意点

## 概要

Nuxt4 は、Nuxt.js の最新バージョンであり、パフォーマンス、開発者エクスペリエンス、機能性の向上など、多くの新機能と改善が盛り込まれています。Nuxt3 から Nuxt4 への移行は、一応の後方互換性はありますが、いくつかの破壊的変更を含むため、注意が必要です。本記事では、Nuxt4 の新機能、破壊的変更、そしてスムーズな移行方法について詳しく解説します。

## Nuxt4 の新機能と改善

Nuxt4 は、パフォーマンスや開発効率、機能性などの面で、多くの改善が入りました。主な新機能は以下の通りです。

* **Nitro エンジンの完全統合:**  
Nuxt4 は、サーバーサイドレンダリング (SSR) と静的サイト生成 (SSG) を高速化する Nitro エンジンを採用しています。Nuxt3 でも Nitro エンジンは採用されていましたが、Nuxt4 ではより洗練され、統合され、より強力になっています。主な違いは以下です。

  * **Nuxt3 の Nitro エンジン**

    * **サーバーサイドレンダリング (SSR) と静的サイト生成 (SSG) のための基盤:**  
     Nuxt3 は、Nitro エンジンを使用してサーバーサイドレンダリング (SSR) と静的サイト生成 (SSG) を実行していました。しかし、これは主にサーバーサイドレンダリングに焦点を当て、静的サイト生成はセカンドクラスの機能でした。
    * **`serverMiddleware` ディレクトリの使用:**  
    サーバーサイドのミドルウェアや API エンドポイントを定義するために、`serverMiddleware` ディレクトリが使用されていて、アプリケーションの構造を複雑にする可能性がありました。
    * **API ルーティングの制限:**  
    API ルーティング機能はありましたが、`serverMiddleware` に大きく依存しており、複雑な API を構築するには不十分な場合がありました。
    * **Nitro パッケージの依存:**  
    Nitro は Nuxt3 のパッケージとして別々に使用されていました。

  * **Nuxt4 の Nitro エンジン**

    * **完全統合:**  
    Nuxt4 では、Nitro エンジンが完全に統合され、アプリケーションのすべての側面を強化するコア機能として設計されています。
    * **サーバーサイドレンダリングと静的サイト生成の最適化:**  
    Nitro エンジンは、サーバーサイドレンダリングと静的サイト生成の両方を効率的に処理するように最適化されています。特に静的サイト生成はより高速で効率的になりました。
    * **`server` ディレクトリの導入:**  
    サーバーサイドコードを管理するための新しい `server` ディレクトリが導入されました。これにより、サーバーサイドコードの構成がより明確になりました。
    * **強力な API ルーティング:**   
    Nuxt4 は、より強力な API ルーティングシステムを提供し、複雑な API を簡単に構築できます。
    * **Nitro モジュールの導入:**  
    Nitro エンジンの機能を拡張するための Nitro モジュールが導入されました。

* **Vue3 への完全移行:**  
Nuxt4 は、Vue3 をベースに構築されており、Vue3 の最新機能とパフォーマンスの向上を享受できます。
* **TypeScript の強化:**  
Nuxt4 は、TypeScript のサポートを強化し、開発中の型安全性をより高めています。
* **ユニバーサルなルーティング:**  
Nuxt4 では、サーバーサイドとクライアントサイドの両方に共通のルーティングシステムが採用されています。
* **モジュールシステムの進化:**  
Nuxt4 では、モジュールシステムが進化し、より柔軟性が高くなりました。
* **新しい API ルーティング:**  
Nuxt4 は、API ルーティングの新しい仕組みを提供し、API の開発を容易にします。
* **Composition API の活用:**  
Nuxt4 は、Vue3 の Composition API を全面的に採用しています。

## Nuxt3 との破壊的変更

Nuxt4 は、Nuxt3 と比較していくつかの破壊的変更を導入しています。移行前に、これらの変更点を理解しておくことが重要です。

### 1. Nitro エンジンによるファイル構造の変更
**影響レベル**: 重要 

Nuxt4 は Nitro エンジンの統合を強化したことで、ファイル構造が大きく変わりました。以前の `pages` ディレクトリは `app` ディレクトリに置き換えられ、サーバーサイドコードや API エンドポイントを管理する新しい `server` ディレクトリが導入されました。
Nuxt3では各ディレクトリがルートレベルに配置されていたのに対し、Nuxt4では、`app` ディレクトリがアプリケーションの主要なコンポーネントをまとめ、`server` ディレクトリがサーバーサイドコードを管理します。

**変更の理由**  

- パフォーマンス - すべてのコードをリポジトリのルートに配置すると、.git/とnode_modules/フォルダがFSウォッチャーによってスキャン/含まれる問題が発生し、Mac OS以外のOSでの起動が大幅に遅延する可能性があります。
- IDEの型安全性 - server/とアプリの残りの部分は、利用可能な異なるグローバルインポートを持つ全く異なるコンテキストで実行されているため、server/がアプリの残りの部分と同じフォルダ内にないようにすることで、IDEで自動補完が競合しないように改善されています。

**Nuxt3とNuxt4のディレクトリ構造比較**

```
// Nuxt3
├── components
│   ├── MyComponent.vue
│   └── ...
├── pages
│   ├── index.vue
│   ├── about.vue
│   └── ...
├── store
│   └── ...
├── plugins
│   └── ...
├── static
│   └── ...
├── assets
│   └── ...
└── nuxt.config.js
```

```
// Nuxt4
├── app
│   ├── app.vue
│   ├── components
│   │   ├── MyComponent.vue
│   │   └── ...
│   ├── pages
│   │   ├── index.vue
│   │   ├── about.vue
│   │   └── ...
│   └── layouts
│       └── default.vue
├── server
│   └── api
│       └── users.js
└── nuxt.config.ts
```

**主な違い**

* **app.vueの移動:** Nuxt3 では `app.vue`ファイルはルートレベルにありましたが、Nuxt4 では `app` ディレクトリ内に移動しています。
* **各ディレクトリの移動:** Nuxt3 では `pages`、`components`、`composables`、`assets`、`layouts`、`utils`ディレクトリはルートレベルにありましたが、Nuxt4 では `app` ディレクトリ内に移動しています。`middleware`は、クライアントサイドで使う場合は`app` ディレクトリ内に、サーバーサイドで使う場合は`server` ディレクトリ内に置くことができます
* **`server` ディレクトリの追加:** Nuxt4 では、サーバーサイドコードや API エンドポイントを管理するための `server` ディレクトリが追加されました。
* **`nuxt.config.js` の変更:** Nuxt4 では、`nuxt.config.js` ファイルが `nuxt.config.ts` ファイルに置き換えられています。


**補足**

* Nuxt4 では、`app` ディレクトリ内に `assets` ディレクトリを作成することができます。 `public` ディレクトリは、従来通りルートレベルにしか置けません。`public` ディレクトリと `assets` ディレクトリの使い分けは従来通り、ビルドに含めずに利用したいファイルは `public` ディレクトリに入れます。
* `server` ディレクトリは、API エンドポイントやサーバーサイドレンダリング機能などを実装するための場所となります。
* Nuxt4 のディレクトリ構造は、アプリケーションの規模や複雑さに合わせて調整することができます。例えば、中規模以上のアプリケーションで、複数の機能を持つときは下記のようにフォルダ構成を変更することも可能です。
```
// Nuxt4 中規模アプリケーションの例
├── app
│   ├── features
│   │   ├── blog
│   │   │   ├── components
│   │   │   └── pages
│   │   └── auth
│   │       ├── components
│   │       └── pages
│   ├── components
│   │   └── MyComponent.vue
│   ├── layouts
│   │   └── default.vue
│   └─── utils
│       └── default.vue
├── server
│   ├── api
│   │   ├── users.js
│   │   └── articles.js
│   └── middlewares
│       └── auth.js
└── nuxt.config.ts
```


### 2. ルーティングシステムの変更
**影響レベル**: 重要 

Nuxt4 では、ルーティングシステムが変更され、`pages` ディレクトリ内のファイルが、サーバーサイドとクライアントサイドで共有されるようになりました。

```javascript
// Nuxt3
export default defineNuxtConfig({
  // ...
  router: {
    // ...
  },
})

// Nuxt4
export default defineNuxtConfig({
  // ...
  app: {
    head: {
      // ...
    },
  },
})
```

### 3. Composition APIの推奨とデフォルト設定
**影響レベル**: 小程度 

Nuxt4 では、Options APIではなく、Composition API を使用することが推奨されています。Nuxt3でもComposition APIは使えましたが、Nuxt4ではデフォルトで `<script setup>` が有効になります。

```vue
// Options API
<script>
import { ref, defineComponent } from 'vue'

export default defineComponent({
  setup() {
    const count = ref(0)

    function increment() {
      count.value++
    }

    return {
      count,
      increment,
    }
  },
})
</script>

<template>
  <div>
    <h1>{{ count }}</h1>
    <button @click="increment">+</button>
  </div>
</template>
```
```vue
// Composition API
<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <div>
    <h1>{{ count }}</h1>
    <button @click="increment">+</button>
  </div>
</template>

```

### 4. Nuxt.js モジュールの廃止
**影響レベル**: 小程度 

Nuxt4 では、以前の Nuxt.js モジュールは廃止され、代わりに Nitro モジュールが導入されました。Nitro モジュールは、Nuxt.js モジュールより効率的で柔軟性が高く、高速に実行され、アプリケーションの起動時間を短縮できるというメリットがあります。


### 5. 共有プリレンダリングデータ

**影響レベル**: 中程度

**変更点**:

* `useAsyncData` と `useFetch` の呼び出し結果を異なるページ間で共有する機能が有効化されました。

**変更理由**:

* 複数のページで同じデータを取得する際に、プリレンダリング段階で一度だけデータを取得することでパフォーマンスを大幅に向上させることができます。
* 例えば、サイト全体で共通のメニューデータやサイト設定データを取得する場合、この機能により、ページのプリレンダリング時に一度だけデータを取得し、他のページでキャッシュされたデータを使用できるようになります。

**移行手順**:

* データの一意のキーが常に同じデータに紐づくことを確認します。`useAsyncData` でデータを取得する場合は、データを一意に識別するキーを提供する必要があります。`useFetch` は自動的にキーを生成します。
* 必要に応じて、`nuxt.config.ts` で `experimental.sharedPrerenderData` オプションを `false` に設定することで、この機能を無効にすることができます。

**例**:

```vue
// app/pages/test/[slug].vue
<script setup>
const route = useRoute()
// これは動的ページでは安全ではありません。
// Nuxt はキーにスラッグを反映しないため、データの一致が保証されません。
const { data } = await useAsyncData(async () => {
  return await $fetch(`/api/my-page/${route.params.slug}`)
})

// 代わりに、データを一意に識別するキーを使用します。
const { data } = await useAsyncData(route.params.slug, async () => {
  return await $fetch(`/api/my-page/${route.params.slug}`)
})
</script>
```

### 6. `useAsyncData` と `useFetch` のデフォルト値

**影響レベル**: 最小

**変更点**:

* `useAsyncData` から返される `data` と `error` オブジェクトは、デフォルトで `undefined` になります。

**変更理由**:

* 以前は `data` は `null` で初期化され、`error` は `null` で初期化されていました。この変更により、より一貫性のある挙動を実現しています。

**移行手順**:

* 必要に応じて、`nuxt.config.ts` で `experimental.defaults.useAsyncData` オプションを使用することで、以前の挙動に戻すことができます。

### 7. `useAsyncData` と `useFetch` の `refresh` オプション

**影響レベル**: 最小

**変更点**:

* `refresh` オプションの `dedupe` オプションのブール値エイリアス (`true` は `cancel`、`false` は `defer`) が削除されました。

**変更理由**:

* ブール値エイリアスはわかりにくく、混乱を招く可能性があったため、削除されました。

**移行手順**:

* `refresh` オプションに `cancel` または `defer` を指定するようにコードを変更します。

### 8. `useAsyncData` と `useFetch` のデータクリア

**影響レベル**: 最小

**変更点**:

* `useAsyncData` にカスタムのデフォルト値が設定されている場合、`clear` または `clearNuxtData` を呼び出す際に、デフォルト値が使用されるようになりました。

**変更理由**:

* データをリセット/クリアする際に、カスタムのデフォルト値を尊重することで、より適切な挙動を実現しています。

**移行手順**:

* 必要に応じて、`nuxt.config.ts` で `experimental.resetAsyncDataToUndefined` オプションを使用することで、以前の挙動に戻すことができます。

### 9. `useAsyncData` と `useFetch` のリアクティビティ

**影響レベル**: 最小

**変更点**:

* `useAsyncData`、`useFetch`、`useLazyAsyncData`、`useLazyFetch` から返される `data` オブジェクトは、`shallowRef` になりました。

**変更理由**:

* データオブジェクトのリアクティビティを浅くすることで、パフォーマンスを向上させることができます。

**移行手順**:

* 必要に応じて、`deep` オプションを使用して、データオブジェクトのリアクティビティを深くすることができます。

### 10. `builder:watch` フックの絶対パス

**影響レベル**: 最小

**変更点**:

* `builder:watch` フックは、プロジェクトの `srcDir` に対する相対パスではなく、絶対パスを発行するようになりました。

**変更理由**:

* これにより、`srcDir` 外のパスの監視をサポートし、より複雑なプロジェクト構造に対応できるようになりました。

**移行手順**:

* ほとんどの場合、移行手順は必要ありません。必要に応じて、コードを調整してください。

### 11. ディレクトリインデックススキャン

**影響レベル**: 中程度

**変更点**:

* `middleware` フォルダの子フォルダもインデックスファイルがスキャンされ、ミドルウェアとして登録されるようになりました。

**変更理由**:

* Nuxt は、`middleware` と `plugins` などのフォルダを自動的にスキャンします。この動作を他のフォルダにも拡張することで、より一貫性のある挙動を実現しています。

**移行手順**:

* 必要に応じて、フックを使用してミドルウェアをフィルタリングすることで、以前の挙動に戻すことができます。

### 12. テンプレートコンパイル

**影響レベル**: 最小

**変更点**:

* Nuxt は、`lodash/template` を使用してテンプレートをコンパイルする機能を廃止しました。

**変更理由**:

* `lodash/template` はセキュリティ問題を抱えており、重い依存関係でした。

**移行手順**:

* `getContents` 関数を使用するか、プロジェクトの依存関係として `lodash` を使用することで、テンプレートをコンパイルしてください。

### 13. 実験的機能の削除

**影響レベル**: 最小

**変更点**:

* 一部の設定可能な実験的機能が削除されました。

**変更理由**:

* これらのオプションは、デフォルトの値に設定されているため、設定可能なままにする必要はありません。

**移行手順**:

* 設定を削除するだけです。


### 14. その他の変更

* Nuxt4 では、`nuxt.config.js` ファイルが `nuxt.config.ts` に変更されています。
* `vuex` モジュールは廃止され、代わりに `pinia` を使用することが推奨されています。
* `axios` モジュールは、`@nuxtjs/axios` モジュールに置き換えられました。

## Nuxt3 から Nuxt4 への移行方法

Nuxt3 から Nuxt4 への移行は、以下の手順で行うことができます。

### 1. プロジェクトの更新

* Nuxt4 に対応した依存関係を更新します。
* `package.json` ファイルから `nuxt` のバージョンを `^4.0.0` に変更します。
* `npm install` または `yarn install` を実行して依存関係をインストールします。

### 2. ファイル構造の変更

* `pages` ディレクトリを `app` ディレクトリにリネームします。
* `server` ディレクトリを作成し、サーバーサイドコードや API エンドポイントを移動します。
* `nuxt.config.js` ファイルを `nuxt.config.ts` にリネームします。

### 3. コードの更新

* コンポーネントの書き方を Composition API に合わせて変更します。
* 廃止されたモジュールを新しいモジュールに置き換えます。
* `nuxt.config.ts` ファイルで、新しい設定項目を定義します。

### 4. テストとデバッグ

* `npm run dev` または `yarn dev` を実行してアプリケーションを起動し、すべての機能が正常に動作することを確認します。
* 必要に応じて、コードを更新して、エラーを修正します。

## Nuxt3→Nuxt4移行前の破壊的変更の影響テスト方法

Nuxt3からNuxt4 への移行時に破壊的変更の影響があるかは、Nuxt3.12 でテストすることができます。Nuxt3.12 は、Nuxt4 で導入される破壊的変更の一部をプレビューとして提供しています。

* **Nuxt3.12 をインストール:** `npm install --save-dev nuxt@3.12.0` または `yarn add --dev nuxt@3.12.0`
* **設定ファイルの更新:** `nuxt.config.js` ファイルで、`vueVersion` プロパティを `3.2` に設定します。
* **プロジェクトの実行:** `npm run dev` または `yarn dev` を実行してプロジェクトを実行し、破壊的変更の影響を確認します。

### まとめ

Nuxt4 は、パフォーマンスと開発者エクスペリエンスを大幅に向上させる多くの破壊的変更を導入しています。これから開発環境を選べるのであれば、Nuxt4を検討に入れても良いかもしれません。Nuxt3からNuxt4への移行も、アプリケーションの規模がまだ大きくなければ検討してみてください。