nuxt logo

ドキュメント翻訳(非公式)

アップグレードガイド

最新の Nuxt バージョンへのアップグレード方法を学びましょう。

Nuxt のアップグレード

最新リリース

Nuxt を最新リリースにアップグレードするには、nuxt upgrade コマンドを使用します。

npx nuxt upgrade

ナイトリリースチャンネル

最新の Nuxt ビルドを使用してリリース前の機能をテストするには、ナイトリリースチャンネルガイドを参照してください。

Nuxt 4 への移行

Nuxt 4 には大幅な改善と変更が含まれています。このガイドは、既存の Nuxt 3 アプリケーションを Nuxt 4 に移行するのに役立ちます。

まず、Nuxt 4 にアップグレードします:

npm install nuxt@^4.0.0

アップグレード後、ほとんどの Nuxt 4 の動作はデフォルトになります。ただし、移行中に後方互換性を維持する必要がある場合は、一部の機能を構成することができます。

以下のセクションでは、Nuxt 4 へのアップグレード時に必要な主要な変更と移行について詳しく説明します。

重大または重要な変更は、移行手順と利用可能な構成オプションと共に以下に記載されています。

Codemods を使用した移行

アップグレードプロセスを容易にするために、Codemod チームと協力して、多くの移行ステップをオープンソースの codemods で自動化しました。

問題が発生した場合は、npx codemod feedback を使用して Codemod チームに報告してください 🙏

Nuxt 4 codemods の完全なリスト、各詳細情報、ソース、およびそれらを実行するさまざまな方法については、Codemod Registry を訪問してください。

このガイドで言及されているすべての codemods を次の codemod レシピを使用して実行できます:

npx codemod@latest nuxt/4/migration-recipe

このコマンドは、実行したくないものを選択解除するオプションと共に、すべての codemods を順番に実行します。各 codemod は、対応する変更と共に以下にリストされており、独立して実行することもできます。

新しいディレクトリ構造

🚦 影響レベル: 重要

Nuxt は現在、新しいディレクトリ構造をデフォルトとしています。後方互換性があるため、Nuxt がトップレベルの app/pages/ ディレクトリなどの古い構造を使用していると検出した場合、この新しい構造は適用されません。

👉 完全な RFC を参照

変更点

  • 新しい Nuxt のデフォルト srcDir はデフォルトで app/ であり、ほとんどのものはそこから解決されます。
  • serverDir<srcDir>/server ではなく <rootDir>/server をデフォルトとします。
  • layers/modules/public/ はデフォルトで <rootDir> を基準に解決されます。
  • Nuxt Content v2.13+ を使用している場合、content/<rootDir> を基準に解決されます。
  • 新しい dir.app が追加され、router.options.tsspa-loading-template.html を探すディレクトリで、デフォルトは <srcDir>/ です。
v4 フォルダ構造の例。
.output/
.nuxt/
app/
  assets/
  components/
  composables/
  layouts/
  middleware/
  pages/
  plugins/
  utils/
  app.config.ts
  app.vue
  router.options.ts
content/
layers/
modules/
node_modules/
public/
shared/
server/
  api/
  middleware/
  plugins/
  routes/
  utils/
nuxt.config.ts

この新しい構造では、~ エイリアスはデフォルトで app/ ディレクトリ(あなたの srcDir)を指します。つまり、~/componentsapp/components/ に、~/pagesapp/pages/ に解決されます。

👉 この変更を実装した PR を参照

変更の理由

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

移行手順

  1. app/ という新しいディレクトリを作成します。
  2. assets/components/composables/app/layouts/app/middleware/app/pages/app/plugins/utils/ フォルダをその下に移動し、app.vueerror.vueapp.config.ts も移動します。app/router-options.tsapp/spa-loading-template.html がある場合、これらのパスはそのままです。
  3. nuxt.config.tscontent/layers/modules/public/server/ フォルダが app/ フォルダの外、プロジェクトのルートに残っていることを確認します。
  4. tailwindcsseslint の設定など、サードパーティの設定ファイルを新しいディレクトリ構造に合わせて更新することを忘れないでください(必要な場合 - @nuxtjs/tailwindcsstailwindcss を正しく自動設定するはずです)。

この移行は npx codemod@latest nuxt/4/file-structure を実行することで自動化できます。

ただし、移行は必須ではありません。現在のフォルダ構造を維持したい場合、Nuxt はそれを自動検出するはずです。(もしそうでない場合は、問題を報告してください。)唯一の例外は、すでにカスタム srcDir を持っている場合です。この場合、modules/public/server/ フォルダはカスタム srcDir ではなく rootDir から解決されることを知っておく必要があります。必要に応じて dir.modulesdir.publicserverDir を設定することでこれを上書きできます。

次の設定を使用して v3 フォルダ構造を強制することもできます:

nuxt.config.ts
export default defineNuxtConfig({
  // 新しい srcDir のデフォルトを `app` からルートディレクトリに戻します
  srcDir: '.',
  // `router.options.ts` と `spa-loading-template.html` のディレクトリプレフィックスを指定します
  dir: {
    app: 'app'
  }
})

シングルトンデータフェッチレイヤー

🚦 影響レベル: 中程度

変更点

Nuxt のデータフェッチシステム(useAsyncDatauseFetch)は、パフォーマンスと一貫性を向上させるために大幅に再編成されました:

  1. 同じキーの共有リファレンス: 同じキーで useAsyncData または useFetch を呼び出すすべての呼び出しは、同じ dataerrorstatus リファレンスを共有します。これにより、明示的なキーを持つすべての呼び出しは、deeptransformpickgetCachedDatadefault オプションが競合しないようにすることが重要です。

  2. getCachedData のより多くの制御: getCachedData 関数は、データがフェッチされるたびに呼び出されます。これは、ウォッチャーや refreshNuxtData の呼び出しによって引き起こされる場合でも同様です。(以前は、新しいデータが常にフェッチされ、この関数はこれらの場合には呼び出されませんでした。)キャッシュされたデータを使用するタイミングと再フェッチするタイミングをより制御できるようにするために、この関数はリクエストの原因を含むコンテキストオブジェクトを受け取ります。

  3. リアクティブキーのサポート: 計算されたリファレンス、プレーンリファレンス、またはゲッタ関数をキーとして使用できるようになり、自動データ再フェッチが可能になります(データは別々に保存されます)。

  4. データのクリーンアップ: useAsyncData でフェッチされたデータを使用する最後のコンポーネントがアンマウントされると、Nuxt はそのデータを削除してメモリ使用量の増加を防ぎます。

変更の理由

これらの変更は、メモリ使用量を改善し、useAsyncData の呼び出し間でのロード状態の一貫性を向上させるために行われました。

移行手順

  1. 不一致のオプションを確認する: 同じキーを使用して異なるオプションやフェッチ関数を使用しているコンポーネントを確認します。

    // これにより警告が発生します
    const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
    const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
    

    明示的なキーを共有する useAsyncData の呼び出し(カスタムオプションを持つ)を独自のコンポーザブルに抽出することが有益です:

    app/composables/useUserData.ts
    export function useUserData(userId: string) {
      return useAsyncData(
        `user-${userId}`,
        () => fetchUser(userId),
        { 
          deep: true,
          transform: (user) => ({ ...user, lastAccessed: new Date() })
        }
      )
    }
    
  2. getCachedData の実装を更新する:

    useAsyncData('key', fetchFunction, {
    -  getCachedData: (key, nuxtApp) => {
    -    return cachedData[key]
    -  }
    +  getCachedData: (key, nuxtApp, ctx) => {
    +    // ctx.cause - 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' のいずれか
    +    
    +    // 例: 手動リフレッシュ時にキャッシュを使用しない
    +    if (ctx.cause === 'refresh:manual') return undefined
    +    
    +    return cachedData[key]
    +  }
    })
    

または、現在のところ、この動作を無効にすることができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    granularCachedData: false,
    purgeCachedData: false
  }
})

レイヤー内のモジュール読み込み順序の修正

🚦 影響レベル: 最小

変更点

Nuxt レイヤー を使用する際のモジュールの読み込み順序が修正されました。以前は、プロジェクトルートのモジュールが拡張レイヤーのモジュールよりも先に読み込まれていましたが、これは期待される動作の逆でした。

現在、モジュールは正しい順序で読み込まれます:

  1. レイヤーモジュールが最初(拡張順序で - より深いレイヤーが最初)
  2. プロジェクトモジュールが最後(最優先)

これは以下の両方に影響します:

  • nuxt.config.tsmodules 配列で定義されたモジュール
  • modules/ ディレクトリから自動検出されたモジュール

変更の理由

この変更により:

  • 拡張レイヤーが消費プロジェクトよりも優先度が低くなる
  • モジュールの実行順序が直感的なレイヤー継承パターンに一致する
  • モジュールの設定とフックがマルチレイヤーセットアップで期待通りに動作する

移行手順

ほとんどのプロジェクトは変更を必要としません。これは、期待される動作に一致するように読み込み順序を修正するものです。

ただし、以前の誤った順序に依存していたプロジェクトの場合は、以下を行う必要があるかもしれません:

  1. モジュールの依存関係を確認する: 特定の読み込み順序に依存するモジュールがあるかどうかを確認します。
  2. モジュール設定を調整する: 誤った順序に対応するために設定されたモジュールがある場合
  3. 徹底的にテストする: 修正された順序で期待通りにすべての機能が動作することを確認します。

新しい正しい順序の例:

// レイヤー: my-layer/nuxt.config.ts
export default defineNuxtConfig({
  modules: ['layer-module-1', 'layer-module-2']
})

// プロジェクト: nuxt.config.ts
export default defineNuxtConfig({
  extends: ['./my-layer'],
  modules: ['project-module-1', 'project-module-2']
})

// 読み込み順序(修正済み):
// 1. layer-module-1
// 2. layer-module-2  
// 3. project-module-1(レイヤーモジュールを上書き可能)
// 4. project-module-2(レイヤーモジュールを上書き可能)

フックを登録する必要があるためにモジュール順序の依存関係に問題がある場合は、フックを呼び出す必要があるモジュールに対して modules:done フック を使用することを検討してください。これは他のすべてのモジュールが読み込まれた後に実行されるため、安全に使用できます。

👉 詳細については PR #31507issue #25719 を参照してください。

ルートメタデータの重複排除

🚦 影響レベル: 最小

変更点

definePageMeta を使用して、namepath などのルートメタデータを設定することが可能です。以前は、これらはルートとルートメタデータの両方で利用可能でした(例えば、route.nameroute.meta.name)。

現在、これらはルートオブジェクトでのみアクセス可能です。

変更の理由

これは experimental.scanPageMeta をデフォルトで有効にした結果であり、パフォーマンスの最適化です。

移行手順

移行は簡単です:

  const route = useRoute()
  
- console.log(route.meta.name)
+ console.log(route.name)

正規化されたコンポーネント名

🚦 影響レベル: 中程度

Vue は現在、コンポーネントの命名に関して Nuxt のパターンに一致するコンポーネント名を生成します。

変更点

デフォルトでは、手動で設定していない場合、Vue はコンポーネントのファイル名に一致するコンポーネント名を割り当てます。

ディレクトリ構造
├─ components/
├─── SomeFolder/
├───── MyComponent.vue

この場合、Vue にとってコンポーネント名は MyComponent になります。これを <KeepAlive> で使用したり、Vue DevTools で識別したりする場合、この名前を使用する必要があります。

しかし、これを自動インポートするためには SomeFolderMyComponent を使用する必要がありました。

この変更により、これらの2つの値が一致し、Vue はコンポーネントの命名に関して Nuxt のパターンに一致するコンポーネント名を生成します。

移行手順

@vue/test-utilsfindComponent を使用するテストや、コンポーネントの名前に依存する <KeepAlive> で更新された名前を使用することを確認してください。

または、現在のところ、この動作を無効にすることができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    normalizeComponentNames: false
  }
})

Unhead v2

🚦 影響レベル: 最小

変更点

<head> タグを生成するために使用される Unhead がバージョン2に更新されました。ほとんど互換性がありますが、低レベルの API にいくつかの破壊的変更が含まれています。

  • 削除されたプロパティ: vmidhidchildrenbody
  • Promise 入力はサポートされなくなりました。
  • タグはデフォルトで Capo.js を使用してソートされます。

移行手順

上記の変更はアプリに最小限の影響を与えるはずです。

問題がある場合は、以下を確認してください:

  • 削除されたプロパティを使用していないこと。
useHead({
  meta: [{ 
    name: 'description', 
    // メタタグには vmid や key は不要です    
-   vmid: 'description' 
-   hid: 'description'
  }]
})
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'

export default defineNuxtPlugin({
  setup() {
    const unhead = injectHead()
    unhead.use(TemplateParamsPlugin)
    unhead.use(AliasSortingPlugin)
  }
})

必須ではありませんが、@unhead/vue からのインポートを #imports または nuxt/app に更新することをお勧めします。

-import { useHead } from '@unhead/vue'
+import { useHead } from '#imports'

それでも問題がある場合は、head.legacy 設定を有効にして v1 の動作に戻すことができます。

export default defineNuxtConfig({
  unhead: {
    legacy: true,
  }
})

SPA ローディングスクリーンの新しい DOM 位置

🚦 影響レベル: 最小

変更点

クライアント専用ページ(ssr: false)をレンダリングする際、オプションでローディングスクリーンをレンダリングします(~/app/spa-loading-template.html から - Nuxt 4 ではこれも ~/spa-loading-template.html に変更されました)、Nuxt アプリのルート内で:

<div id="__nuxt">
  <!-- spa ローディングテンプレート -->
</div>

現在、デフォルトで Nuxt アプリのルートと並んでテンプレートをレンダリングします:

<div id="__nuxt"></div>
<!-- spa ローディングテンプレート -->

変更の理由

これにより、spa ローディングテンプレートが Vue アプリのサスペンスが解決されるまで DOM に残り、白いフラッシュを防ぎます。

移行手順

CSS や document.queryElement で spa ローディングテンプレートをターゲットにしていた場合、セレクタを更新する必要があります。この目的のために、新しい app.spaLoaderTagapp.spaLoaderAttrs 設定オプションを使用できます。

または、以前の動作に戻すことができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    spaLoadingTemplateLocation: 'within',
  }
})

解析された error.data

🚦 影響レベル: 最小

data プロパティを持つエラーをスローすることが可能でしたが、これは解析されませんでした。現在、これは解析され、error オブジェクトで利用可能です。修正ですが、以前の動作に依存して手動で解析していた場合、技術的には破壊的変更です。

移行手順

カスタム error.vue を更新して、error.data の追加解析を削除します:

  <script setup lang="ts">
  import type { NuxtError } from '#app'

  const props = defineProps({
    error: Object as () => NuxtError
  })

- const data = JSON.parse(error.data)
+ const data = error.data
  </script>

より細かいインラインスタイル

🚦 影響レベル: 中程度

Nuxt は現在、グローバル CSS ではなく Vue コンポーネントのスタイルのみをインライン化します。

変更点

以前は、Nuxt はすべての CSS をインライン化し、グローバルスタイルを含む <link> 要素を削除していました。現在、Nuxt は Vue コンポーネントのためにのみこれを行います(以前は個別の CSS チャンクを生成していました)。これは、個別のネットワークリクエストを削減する(以前と同様に、初期ロード時にページごとやコンポーネントごとの個別の .css ファイルのリクエストはありません)、単一のグローバル CSS ファイルのキャッシュを許可し、初期リクエストのドキュメントダウンロードサイズを削減するというバランスを取るためのものです。

移行手順

この機能は完全に構成可能であり、グローバル CSS とコンポーネントごとの CSS の両方をインライン化するために inlineStyles: true を設定して以前の動作に戻すことができます。

nuxt.config.ts
export default defineNuxtConfig({
  features: {
    inlineStyles: true
  }
})

解決後のページメタのスキャン

🚦 影響レベル: 最小

変更点

pages:extend フックを呼び出した後にページメタデータ(definePageMeta で定義された)をスキャンするようになりました。

変更の理由

これは、ユーザーが pages:extend で追加したいページのメタデータをスキャンできるようにするためです。ページメタデータを変更または上書きする機会は、新しい pages:resolved フックで提供されます。

移行手順

ページメタデータを上書きしたい場合は、pages:extend ではなく pages:resolved で行ってください。

  export default defineNuxtConfig({
    hooks: {
-     'pages:extend'(pages) {
+     'pages:resolved'(pages) {
        const myPage = pages.find(page => page.path === '/')
        myPage.meta ||= {}
        myPage.meta.layout = 'overridden-layout'
      }
    }
  })

または、以前の動作に戻すことができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    scanPageMeta: true
  }
})

共有プリレンダーデータ

🚦 影響レベル: 中程度

変更点

useAsyncDatauseFetch の呼び出しからのデータを異なるページ間で共有する以前の実験的機能を有効にしました。詳細は元の PRを参照してください。

変更の理由

この機能は、プリレンダリングされたページ間でペイロードデータを自動的に共有します。これにより、useAsyncDatauseFetch を使用して異なるページで同じデータをフェッチするサイトのプリレンダリング時に大幅なパフォーマンス向上が得られます。

例えば、サイトがすべてのページで useFetch 呼び出しを必要とする場合(例えば、メニューのナビゲーションデータを取得するため、または CMS からのサイト設定を取得するため)、このデータはそれを使用する最初のページをプリレンダリングする際に一度だけフェッチされ、その後他のページをプリレンダリングする際に使用するためにキャッシュされます。

移行手順

データの一意のキーが常に同じデータに解決可能であることを確認してください。例えば、特定のページに関連するデータをフェッチするために useAsyncData を使用している場合、そのデータに一意に一致するキーを提供する必要があります。(useFetch はこれを自動的に行うはずです。)

app/pages/test/[slug\
// 動的ページ(例: `[slug].vue`)では、ルートスラッグがデータフェッチに影響を与えるため、これは安全ではありませんが、Nuxt はそれを知ることができません。
const route = useRoute()
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}`)
})

または、この機能を無効にすることができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    sharedPrerenderData: false
  }
})

useAsyncDatauseFetch のデフォルト dataerror

🚦 影響レベル: 最小

変更点

useAsyncData から返される dataerror オブジェクトは、現在 undefined をデフォルトとします。

変更の理由

以前は datanull に初期化され、clearNuxtDataundefined にリセットされていました。errornull に初期化されていました。この変更は一貫性を高めるためのものです。

移行手順

data.value または error.valuenull であるかどうかを確認していた場合、これらのチェックを undefined に更新できます。

このステップは npx codemod@latest nuxt/4/default-data-error-value を実行することで自動化できます。

問題が発生した場合は、次の設定で以前の動作に戻すことができます:

nuxt.config.ts
// @errors: 2353
export default defineNuxtConfig({
  experimental: {
    defaults: {
      useAsyncData: {
        value: 'null',
        errorValue: 'null'
      }
    }
  }
})

これを行っている場合は問題を報告してください。これを設定可能にする予定はありません。

useAsyncDatauseFetch での refresh 呼び出し時の dedupe オプションの廃止された boolean 値の削除

🚦 影響レベル: 最小

変更点

以前は、refreshdedupe: boolean を渡すことが可能でした。これらは canceltrue)と deferfalse)のエイリアスでした。

app/app.vue
// @errors: 2322
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt!' }))

async function refreshData () {
  await refresh({ dedupe: true })
}

変更の理由

これらのエイリアスは、より明確にするために削除されました。

問題は、useAsyncDatadedupe をオプションとして追加する際に発生しました。dedupe の boolean 値は 反対 になっていました。

refresh({ dedupe: false })既存のリクエストをキャンセルせずに新しいリクエストを優先する ことを意味しました。しかし、useAsyncData のオプション内で dedupe: true を渡すことは 既存の保留中のリクエストがある場合、新しいリクエストを行わない ことを意味しました。(PR を参照。)

移行手順

移行は簡単です:

  const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
  
  async function refreshData () {
-   await refresh({ dedupe: true })
+   await refresh({ dedupe: 'cancel' })

-   await refresh({ dedupe: false })
+   await refresh({ dedupe: 'defer' })
  }

このステップは npx codemod@latest nuxt/4/deprecated-dedupe-value を実行することで自動化できます。

useAsyncDatauseFetch での data クリア時のデフォルトの尊重

🚦 影響レベル: 最小

変更点

useAsyncData にカスタム default 値を提供した場合、clear または clearNuxtData を呼び出すときにこれが使用され、デフォルト値にリセットされます。

変更の理由

ユーザーはしばしば、反復時に null/undefined をチェックする必要を避けるために、空の配列などの適切な空の値を設定します。データをリセット/クリアする際にこれを尊重する必要があります。

useAsyncDatauseFetch での pending 値の整合性

🚦 影響レベル: 中程度

useAsyncDatauseFetchuseLazyAsyncDatauseLazyFetch から返される pending オブジェクトは、status が保留中のときにのみ true になる計算プロパティになりました。

変更点

現在、immediate: false が渡された場合、最初のリクエストが行われるまで pendingfalse になります。これは、以前の動作からの変更であり、最初のリクエストが行われるまで pending は常に true でした。

変更の理由

これは、status プロパティと一致するように pending の意味を整合させるためです。status もリクエストが進行中のときに保留中です。

移行手順

pending プロパティに依存している場合、新しい動作に合わせてロジックを調整し、pendingstatus が保留中のときにのみ true になることを確認してください。

  <template>
-   <div v-if="!pending">
+   <div v-if="status === 'success'">
      <p>Data: {{ data }}</p>
    </div>
    <div v-else>
      <p>Loading...</p>
    </div>
  </template>
  <script setup lang="ts">
  const { data, pending, execute, status } = await useAsyncData(() => fetch('/api/data'), {
    immediate: false
  })
  onMounted(() => execute())
  </script>

または、次の設定で以前の動作に一時的に戻すことができます:

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    pendingWhenIdle: true
  }
})

useAsyncDatauseFetch でのキー変更動作

🚦 影響レベル: 中程度

変更点

useAsyncData または useFetch でリアクティブキーを使用する場合、キーが変更されると Nuxt は自動的にデータを再フェッチします。immediate: false が設定されている場合、useAsyncData はデータが一度フェッチされた場合にのみキーが変更されたときにデータをフェッチします。

以前は、useFetch はわずかに異なる動作をしていました。キーが変更されると常にデータをフェッチしていました。

現在、useFetchuseAsyncData は一貫して動作し、データが一度フェッチされた場合にのみキーが変更されたときにデータをフェッチします。

変更の理由

これにより、useAsyncDatauseFetch の間で一貫した動作が確保され、予期しないフェッチを防ぎます。immediate: false を設定している場合、データは refresh または execute を呼び出さない限り、useFetch または useAsyncData でフェッチされません。

移行手順

この変更は一般的に期待される動作を改善するはずですが、非即時の useFetch のキーやオプションを変更することを期待していた場合、最初に手動でトリガーする必要があります。

  const id = ref('123')
  const { data, execute } = await useFetch('/api/test', {
    query: { id },
    immediate: false
  )
+ watch(id, () => execute(), { once: true })

この動作をオプトアウトするには:

// または Nuxt 設定でグローバルに
export default defineNuxtConfig({
  experimental: {
    alwaysRunFetchOnKeyChange: true
  }
})

useAsyncDatauseFetch での浅いデータリアクティビティ

🚦 影響レベル: 最小

useAsyncDatauseFetchuseLazyAsyncDatauseLazyFetch から返される data オブジェクトは、現在 shallowRef であり、ref ではありません。

変更点

新しいデータがフェッチされると、data に依存するものは依然としてリアクティブです。なぜなら、オブジェクト全体が置き換えられるからです。しかし、コードがそのデータ構造内のプロパティを変更した場合、これはアプリ内でのリアクティビティをトリガーしません。

変更の理由

これにより、深くネストされたオブジェクトや配列に対して Vue がすべてのプロパティ/配列を監視する必要がなくなるため、大幅なパフォーマンス向上が得られます。ほとんどの場合、data は不変であるべきです。

移行手順

ほとんどの場合、移行手順は必要ありませんが、データオブジェクトのリアクティビティに依存している場合、次の2つのオプションがあります:

  1. コンポーザブルごとに深いリアクティビティを選択的にオプトインできます:
    - const { data } = useFetch('/api/test')
    + const { data } = useFetch('/api/test', { deep: true })
    
  2. プロジェクト全体でデフォルトの動作を変更できます(推奨されません):
    nuxt.config.ts
    export default defineNuxtConfig({
      experimental: {
        defaults: {
          useAsyncData: {
            deep: true
          }
        }
      }
    })
    

必要に応じて、このステップは npx codemod@latest nuxt/4/shallow-function-reactivity を実行することで自動化できます。

builder:watch での絶対ウォッチパス

🚦 影響レベル: 最小

変更点

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

変更の理由

これにより、srcDir の外部にあるパスの監視をサポートし、レイヤーや他のより複雑なパターンをより良くサポートできるようになります。

移行手順

このフックを使用することが知られている公開 Nuxt モジュールを事前に移行しました。issue #25339 を参照してください。

ただし、builder:watch フックを使用しているモジュールの作者であり、後方互換性を維持したい場合、次のコードを使用して Nuxt v3 と Nuxt v4 の両方で同じように動作するようにすることができます:

+ import { relative, resolve } from 'node:fs'
  // ...
  nuxt.hook('builder:watch', async (event, path) => {
+   path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path))
    // ...
  })

このステップは npx codemod@latest nuxt/4/absolute-watch-path を実行することで自動化できます。

window.__NUXT__ オブジェクトの削除

変更点

アプリがハイドレーションを終了した後、グローバル window.__NUXT__ オブジェクトを削除します。

変更の理由

これにより、マルチアプリパターン(#21635)への道が開かれ、Nuxt アプリデータにアクセスするための単一の方法である useNuxtApp() に集中することができます。

移行手順

データはまだ利用可能ですが、useNuxtApp().payload でアクセスできます:

- console.log(window.__NUXT__)
+ console.log(useNuxtApp().payload)

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

🚦 影響レベル: 中程度

変更点

app/middleware/ フォルダ内の子フォルダも index ファイルをスキャンし、これらもプロジェクト内でミドルウェアとして登録されるようになりました。

変更の理由

Nuxt は app/middleware/app/plugins/ を含む多くのフォルダを自動的にスキャンします。

app/plugins/ フォルダ内の子フォルダは index ファイルをスキャンし、この動作をスキャンされたディレクトリ間で一貫させたいと考えました。

移行手順

おそらく移行は必要ありませんが、以前の動作に戻したい場合は、これらのミドルウェアをフィルタリングするフックを追加できます:

export default defineNuxtConfig({
  hooks: {
    'app:resolve'(app) {
      app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path))
    }
  }
})

テンプレートコンパイルの変更

🚦 影響レベル: 最小

変更点

以前は、Nuxt はファイルシステム上のテンプレートを .ejs ファイル形式/構文を使用してコンパイルするために lodash/template を使用していました。

さらに、これらのテンプレート内でコード生成に使用できるテンプレートユーティリティ(serializeimportNameimportSources)を提供していましたが、これらは削除されます。

変更の理由

Nuxt v3 では、getContents() 関数を使用した「仮想」構文に移行しました。これははるかに柔軟でパフォーマンスが向上しています。

さらに、lodash/template は一連のセキュリティ問題を抱えています。これらはビルド時に使用されるため、Nuxt プロジェクトには実際には適用されませんが、セキュリティ監査に表示されます。さらに、lodash は大きな依存関係であり、ほとんどのプロジェクトでは使用されていません。

最後に、コードシリアル化関数を Nuxt 内で直接提供することは理想的ではありません。代わりに、プロジェクトの依存関係となる unjs/knitwork などのプロジェクトを維持し、セキュリティ問題を直接報告/解決できるようにします。

移行手順

EJS 構文を使用しているモジュールを更新する PR を提出しましたが、自分でこれを行う必要がある場合、次の3つの後方互換性のある代替手段があります:

  • 文字列補間ロジックを getContents() に直接移動する。
  • https://github.com/nuxt-modules/color-mode/pull/240 のように置換を処理するカスタム関数を使用する。
  • es-toolkit/compat(lodash テンプレートのドロップイン置換)を Nuxt ではなく あなたの プロジェクトの依存関係として使用する:
+ import { readFileSync } from 'node:fs'
+ import { template } from 'es-toolkit/compat'
  // ...
  addTemplate({
    fileName: 'appinsights-vue.js'
    options: { /* some options */ },
-   src: resolver.resolve('./runtime/plugin.ejs'),
+   getContents({ options }) {
+     const contents = readFileSync(resolver.resolve('./runtime/plugin.ejs'), 'utf-8')
+     return template(contents)({ options })
+   },
  })

最後に、テンプレートユーティリティ(serializeimportNameimportSources)を使用している場合、次のように knitwork のユーティリティで置き換えることができます:

import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'

const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"{(.+)}"(?=,?$)/gm, r => JSON.parse(r).replace(/^{(.*)}$/, '$1'))

const importSources = (sources: string | string[], { lazy = false } = {}) => {
  return toArray(sources).map((src) => {
    if (lazy) {
      return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}`
    }
    return genImport(src, genSafeVariableName(src))
  }).join('\n')
}

const importName = genSafeVariableName

このステップは npx codemod@latest nuxt/4/template-compilation-changes を実行することで自動化できます。

デフォルト TypeScript 設定の変更

🚦 影響レベル: 最小

変更点

compilerOptions.noUncheckedIndexedAccessfalse から true に変更されました。

変更の理由

この変更は、以前の 3.12 設定更新 に続くもので、主に TotalTypeScript の推奨事項 に従っています。

移行手順

2つのアプローチがあります:

  1. アプリで型チェックを実行し、新しいエラーを修正する(推奨)。

  2. nuxt.config.ts で新しいデフォルトを上書きする:

    export default defineNuxtConfig({
      typescript: {
        tsConfig: {
          compilerOptions: {
            noUncheckedIndexedAccess: false
          }
        }
      }
    })
    

TypeScript 設定の分割

🚦 影響レベル: 最小

変更点

Nuxt は、異なるコンテキストに対してより良い型チェック体験を提供するために、別々の TypeScript 設定を生成するようになりました:

  1. 新しい TypeScript 設定ファイル: Nuxt は追加の TypeScript 設定を生成します:

    • .nuxt/tsconfig.app.json - アプリコード用(Vue コンポーネント、コンポーザブルなど)
    • .nuxt/tsconfig.server.json - サーバーサイドコード用(Nitro/サーバーディレクトリ)
    • .nuxt/tsconfig.node.json - ビルド時コード用(モジュール、nuxt.config.ts など)
    • .nuxt/tsconfig.shared.json - アプリとサーバーコンテキスト間で共有されるコード用(型や環境に依存しないユーティリティなど)
    • .nuxt/tsconfig.json - 後方互換性のためのレガシー設定
  2. 後方互換性: .nuxt/tsconfig.json を拡張する既存のプロジェクトは、以前と同じように動作します。

  3. プロジェクト参照のオプトイン: 新しいプロジェクトやより良い型チェックを望むプロジェクトは、TypeScript のプロジェクト参照機能を採用できます。

  4. コンテキスト固有の型チェック: 各コンテキストには、その特定の環境に適したコンパイラオプションとインクルード/エクスクルードがあります。

  5. 新しい typescript.nodeTsConfig オプション: ビルド時コード用の TypeScript 設定をカスタマイズできるようになりました。

変更の理由

この変更は、いくつかの利点を提供します:

  1. より良い型安全性: 各コンテキスト(アプリ、サーバー、ビルド時)は、コンテキスト固有のグローバルと API を使用して適切な型チェックを受けます。
  2. 改善された IDE 体験: コードベースの異なる部分に対するより良いインテリセンスとエラーレポート。
  3. クリーンな分離: サーバーコードがクライアントサイド API を誤って提案しないようにし、逆もまた然り。
  4. パフォーマンス: 適切にスコープされた設定で TypeScript がより効率的にコードをチェックできます。

例えば、nuxt.config.ts では自動インポートが利用できません(以前は TypeScript によってフラグが立てられませんでした)。また、IDE は server/ ディレクトリ内でヒントされた別のコンテキストを認識していましたが、これは型チェックには反映されていませんでした(別のステップが必要でした)。

移行手順

移行は必要ありません - 既存のプロジェクトは以前と同じように動作します。

ただし、型チェックを改善するために、新しいプロジェクト参照アプローチをオプトインすることができます:

  1. ルート tsconfig.json を更新してプロジェクト参照を使用する

    {
      "files": [],
      "references": [
        { "path": "./.nuxt/tsconfig.app.json" },
        { "path": "./.nuxt/tsconfig.server.json" },
        { "path": "./.nuxt/tsconfig.shared.json" },
        { "path": "./.nuxt/tsconfig.node.json" }
      ]
    }
    
  2. 手動のサーバー tsconfig.json ファイルを削除する(例えば、.nuxt/tsconfig.server.json を拡張している server/tsconfig.json)。

  3. 型チェックスクリプトを更新してプロジェクト参照のビルドフラグを使用する

    - "typecheck": "nuxt prepare && vue-tsc --noEmit"
    + "typecheck": "nuxt prepare && vue-tsc -b --noEmit"
    
  4. すべての型拡張を適切なコンテキストに移動する

    • アプリコンテキストの型を拡張している場合、ファイルを app/ ディレクトリに移動します。
    • サーバーコンテキストの型を拡張している場合、ファイルを server/ ディレクトリに移動します。
    • アプリとサーバー間で共有される型を拡張している場合、ファイルを shared/ ディレクトリに移動します。

    app/server/、または shared/ ディレクトリの外部から型を拡張することは、新しいプロジェクト参照セットアップでは機能しません。

  5. 必要に応じて Node.js TypeScript オプションを設定する

    export default defineNuxtConfig({
      typescript: {
        // アプリ/サーバー TypeScript 設定をカスタマイズ
        tsConfig: {
          compilerOptions: {
            strict: true
          }
        },
        // ビルド時 TypeScript 設定をカスタマイズ  
        nodeTsConfig: {
          compilerOptions: {
            strict: true
          }
        }
      }
    })
    
  6. TypeScript チェックを実行する CI/ビルドスクリプトを更新して、新しいプロジェクト参照アプローチを使用することを確認する

新しい設定は、オプトインしたプロジェクトに対してより良い型安全性とインテリセンスを提供し、既存のセットアップに対して完全な後方互換性を維持します。

実験的機能の削除

🚦 影響レベル: 最小

変更点

Nuxt 4 では、4つの実験的機能が設定可能ではなくなりました:

  • experimental.treeshakeClientOnlytrue になります(v3.0 以降のデフォルト)
  • experimental.configSchematrue になります(v3.3 以降のデフォルト)
  • experimental.polyfillVueUseHeadfalse になります(v3.4 以降のデフォルト)
  • experimental.respectNoSSRHeaderfalse になります(v3.4 以降のデフォルト)
  • vite.devBundler は設定可能ではなくなり、デフォルトで vite-node を使用します

変更の理由

これらのオプションはしばらくの間現在の値に設定されており、設定可能である必要がある理由はありません。

移行手順

トップレベル generate 設定の削除

🚦 影響レベル: 最小

変更点

トップレベルの generate 設定オプションは Nuxt 4 で利用できなくなりました。これにはすべてのプロパティが含まれます:

  • generate.exclude - プリレンダリングからルートを除外するため
  • generate.routes - プリレンダリングするルートを指定するため

変更の理由

トップレベルの generate 設定は Nuxt 2 からの名残でした。nitro.prerender をしばらくの間サポートしており、Nuxt 3+ でのプリレンダリングを設定するための推奨方法です。

移行手順

generate 設定を対応する nitro.prerender オプションに置き換えます:

export default defineNuxtConfig({
- generate: {
-   exclude: ['/admin', '/private'],
-   routes: ['/sitemap.xml', '/robots.txt']
- }
+ nitro: {
+   prerender: {
+     ignore: ['/admin', '/private'],
+     routes: ['/sitemap.xml', '/robots.txt']
+   }
+ }
})
こちらも参照 nitro.build > config

Nuxt 2 vs. Nuxt 3+

以下の表では、Nuxt の3つのバージョンの簡単な比較があります:

機能 / バージョンNuxt 2Nuxt BridgeNuxt 3+
Vue223
安定性😊 安定😊 安定😊 安定
パフォーマンス🏎 速い✈️ もっと速い🚀 最速
Nitro エンジン
ESM サポート🌙 部分的👍 より良い
TypeScript☑️ オプトイン🚧 部分的
Composition API🚧 部分的
Options API
コンポーネント自動インポート
<script setup> 構文🚧 部分的
自動インポート
webpack445
Vite⚠️ 部分的🚧 部分的
Nuxt CLI❌ 古い✅ nuxt✅ nuxt
静的サイト

Nuxt 2 から Nuxt 3+ への移行

移行ガイドは、Nuxt 2 の機能を Nuxt 3+ の機能に比較し、現在のアプリケーションを適応させるためのステップバイステップのガイダンスを提供します。

こちらも参照 migration > overview

Nuxt 2 から Nuxt Bridge への移行

Nuxt 2 アプリケーションを Nuxt 3 に段階的に移行したい場合は、Nuxt Bridge を使用できます。Nuxt Bridge は、Nuxt 2 で Nuxt 3+ の機能をオプトインメカニズムで使用できる互換レイヤーです。

こちらも参照 bridge > overview