Nuxt Nation カンファレンスが開催されます。11月12日~13日にご参加ください。

アップグレードガイド

最新のNuxtバージョンにアップグレードする方法を学びます。

Nuxtのアップグレード

最新リリース

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

npx nuxi upgrade

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

リリース前に最新のNuxtビルドとテスト機能を使用するには、ナイトリーリリースチャネルガイドをお読みください。

ナイトリーリリースチャネルのlatestタグは現在、Nuxt v4ブランチを追跡しています。つまり、現時点では破壊的な変更が発生する可能性が特に高いため、注意が必要です。"nuxt": "npm:nuxt-nightly@3x"を使用して、3.xブランチのナイトリーリリースを選択できます。

Nuxt 4のテスト

Nuxt 4のリリース日は**未定**です。Nitroのメジャーリリース後、コミュニティで適切にテストされる十分な時間があるかどうかに依存します。このPRでNitroのリリースに向けた進捗状況を確認できます。

リリースまで、Nuxtバージョン3.12+からNuxt 4の破壊的な変更の多くをテストすることが可能です。

Alexander Lichter氏のビデオで、Nuxt 4の破壊的な変更をオプトインする方法をご覧ください。

Nuxt 4のオプトイン

まず、Nuxtを最新リリースにアップグレードします。

次に、compatibilityVersionをNuxt 4の動作に合わせて設定できます。

nuxt.config.ts
export default 
defineNuxtConfig
({
future
: {
compatibilityVersion
: 4,
}, // To re-enable _all_ Nuxt v3 behavior, set the following options: // srcDir: '.', // dir: { // app: 'app' // }, // experimental: { // scanPageMeta: 'after-resolve', // sharedPrerenderData: false, // compileTemplate: true, // resetAsyncDataToUndefined: true, // templateUtils: true, // relativeWatchPaths: true, // normalizeComponentNames: false // defaults: { // useAsyncData: { // deep: true // } // } // }, // unhead: { // renderSSRHeadOptions: { // omitLineBreaks: false // } // } })

compatibilityVersion4に設定すると、Nuxt設定全体のデフォルトがNuxt v4の動作にオプトインするように変更されますが、上記のコメントアウトされた行に従って、テスト時にNuxt v3の動作を個別に再び有効にすることができます。その場合は、Nuxtまたはエコシステムで対処できるように、問題を報告してください。

Nuxt 4への移行

破壊的な変更または重要な変更は、後方/前方互換性のための移行手順とともにここに記載されます。

このセクションは、最終リリースまで変更される可能性があるため、compatibilityVersion: 4を使用してNuxt 4をテストする場合は、定期的にここで確認してください。

Codemodを使用した移行

アップグレードプロセスを容易にするために、Codemodチームと協力して、いくつかのオープンソースのcodemodを使用して多くの移行手順を自動化しました。

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

Nuxt 4 codemodの完全なリスト、それぞれの詳細情報、ソース、および実行するさまざまな方法については、Codemodレジストリにアクセスしてください。

このガイドで説明されているすべてのcodemodは、次のcodemodレシピを使用して実行できます。

npx codemod@latest nuxt/4/migration-recipe

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

新しいディレクトリ構造

🚦 **影響レベル**: 重大

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

👉 RFC全文を参照

変更点
  • 新しいNuxtのデフォルトのsrcDirはデフォルトでapp/であり、ほとんどのものがそこから解決されます。
  • serverDirは désormais、<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/
server/
  api/
  middleware/
  plugins/
  routes/
  utils/
nuxt.config.ts

👉 詳細については、この変更を実装するPRを参照してください。

変更理由
  1. **パフォーマンス** - リポジトリのルートにすべてのコードを配置すると、.git/およびnode_modules/フォルダがFSウォッチャーによってスキャン/インクルードされるという問題が発生し、Mac OS以外では起動が大幅に遅れる可能性があります。
  2. **IDEのタイプセーフティ** - server/とアプリの残りの部分は、利用可能なグローバルインポートが異なる2つのまったく異なるコンテキストで実行されており、server/がアプリの残りの部分と同じフォルダの*内側*にないことを確認することは、IDEで適切な自動補完を取得するための大きな第一歩です。
移行手順
  1. app/という新しいディレクトリを作成します。
  2. assets/components/composables/layouts/middleware/pages/plugins/utils/フォルダをその下に移動します。app.vueerror.vueapp.config.tsも同様です。app/router-options.tsまたはapp/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が自動的に検出する必要があります。(そうでない場合は、問題を提起してください。)1つの例外は、*すでに*カスタムsrcDirがある場合です。この場合、modules/public/server/フォルダは、カスタムsrcDirではなくrootDirから解決されることに注意してください。必要に応じて、dir.modulesdir.publicserverDirを設定することで、これをオーバーライドできます。

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

nuxt.config.ts
export default defineNuxtConfig({
  // This reverts the new srcDir default from `app` back to your root directory
  srcDir: '.',
  // This specifies the directory prefix for `app/router.options.ts` and `app/spa-loading-template.html`
  dir: {
    app: 'app'
  }
})

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

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

変更点

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

désormais、ルートオブジェクトでのみアクセスできます。

変更理由

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

移行手順

移行は簡単です。

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

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

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

Vueは désormais、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
} })

解決後にページメタデータをスキャンする

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

変更点

désormais、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
} })

共有事前レンダリングデータ

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

変更点

これまで実験的な機能だった、異なるページ間で`useAsyncData`および`useFetch`呼び出しからのデータを共有する機能を有効にしました。 オリジナルのPRをご覧ください。

変更理由

この機能は、プリレンダリングされるページ間でペイロードの *データ* を自動的に共有します。 これにより、`useAsyncData`または`useFetch`を使用し、異なるページで同じデータを取得するサイトをプリレンダリングする際のパフォーマンスが大幅に向上する可能性があります。

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

移行手順

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

app/pages/test/[slug].vue
// This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
// to the data fetched, but Nuxt can't know that because it's not reflected in the key.
const route = useRoute()
const { data } = await useAsyncData(async () => {
  return await $fetch(`/api/my-page/${route.params.slug}`)
})
// Instead, you should use a key that uniquely identifies the data fetched.
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
} })

`useAsyncData`および`useFetch`におけるデフォルトの`data`および`error`値

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

変更点

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

変更理由

以前は`data`は`null`に初期化されていましたが、`clearNuxtData`で`undefined`にリセットされていました。 `error`は`null`に初期化されていました。 この変更は、より一貫性を持たせるためです。

移行手順

`data.value`または`error.value`が`null`かどうかを確認していた場合は、代わりに`undefined`かどうかを確認するように更新できます。

`npx codemod@latest nuxt/4/default-data-error-value`を実行することで、この手順を自動化できます。

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

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

この設定を行う場合は、問題を報告してください。この設定を今後も維持する予定はありません。

`useAsyncData`および`useFetch`で`refresh`を呼び出す際の、非推奨の`dedupe`オプションの`boolean`値の削除

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

変更点

以前は、`dedupe: boolean`を`refresh`に渡すことができました。 これらは`cancel`(`true`)と`defer`(`false`)のエイリアスでした。

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

async function refreshData () {
  await refresh({ dedupe: true })
}
変更理由

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

`dedupe`を`useAsyncData`のオプションとして追加した際に問題が発生し、最終的に *反対* の意味になってしまったため、ブール値を削除しました。

`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`を実行することで、この手順を自動化できます。

`useAsyncData`および`useFetch`で`data`をクリアする際のデフォルト値の尊重

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

変更点

`useAsyncData`にカスタム`default`値を提供する場合、`clear`または`clearNuxtData`を呼び出す際にこれが使用され、単に設定解除されるのではなく、デフォルト値にリセットされます。

変更理由

多くの場合、ユーザーは空の配列など、適切な空の値を設定して、反復処理時に`null` / `undefined`を確認する必要を回避します。 データをリセット/クリアする際には、これを尊重する必要があります。

移行手順

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

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

この設定を行う場合は、問題を報告してください。この設定を今後も維持する予定はありません。

`useAsyncData`および`useFetch`における浅いデータリアクティビティ

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

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

変更点

新しいデータがフェッチされると、`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)

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

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

変更点

`middleware/`フォルダの子フォルダも`index`ファイルのスキャン対象となり、プロジェクトのミドルウェアとして登録されるようになりました.

変更理由

Nuxtは`middleware/`や`plugins/`など、いくつかのフォルダを自動的にスキャンします。

`plugins/`フォルダの子フォルダは`index`ファイルのスキャン対象となっており、スキャンされるディレクトリ間でこの動作を統一したいと考えました。

移行手順

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

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

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

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

変更点

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

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

変更理由

Nuxt v3では、より柔軟でパフォーマンスの高い`getContents()`関数を使用した「仮想」構文に移行しました。

さらに、`lodash/template`には、一連のセキュリティ問題がありました。 これらは、実行時ではなくビルド時に信頼できるコードによって使用されているため、Nuxtプロジェクトには実際には適用されません。 しかし、セキュリティ監査では依然として表示されます。 また、`lodash`は重い依存関係であり、ほとんどのプロジェクトでは使用されていません。

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

移行手順

EJS構文を使用しているモジュールを更新するためのPRを作成しましたが、自分でこれを行う必要がある場合は、下位/上位互換性のある3つの代替手段があります。

  • 文字列補間ロジックを`getContents()`に直接移動します。
  • https://github.com/nuxt-modules/color-mode/pull/240のように、置換を処理するカスタム関数を使用します。
  • Nuxtではなく、 *プロジェクトの* 依存関係として`lodash`を引き続き使用します。
+ import { readFileSync } from 'node:fs'
+ import { template } from 'lodash-es'
  // ...
  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 })
+   },
  })

最後に、テンプレートユーティリティ(`serialize`、`importName`、`importSources`)を使用している場合は、`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`を実行することで、この手順を自動化できます。

実験的機能の削除

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

変更点

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

  • `experimental.treeshakeClientOnly`は`true`になります(v3.0以降のデフォルト)。
  • `experimental.configSchema`は`true`になります(v3.3以降のデフォルト)。
  • `experimental.polyfillVueUseHead`は`false`になります(v3.4以降のデフォルト)。
  • `experimental.respectNoSSRHeader`は`false`になります(v3.4以降のデフォルト)。
  • `vite.devBundler`は設定できなくなりました。デフォルトで`vite-node`を使用します。
変更理由

これらのオプションはしばらくの間現在の値に設定されており、設定可能な状態を維持する必要があると考える理由はありません。

移行手順

Nuxt 2とNuxt 3+の比較

以下の表は、Nuxtの3つのバージョンの簡単な比較です。

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

Nuxt 2からNuxt 3+への移行

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

**Nuxt 2からNuxt 3への移行ガイド**をご覧ください。

Nuxt 2からNuxt Bridgeへの移行

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

Nuxt 2からNuxt Bridgeに移行する