アップグレードガイド
最新の 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/
ディレクトリなどの古い構造を使用していると検出した場合、この新しい構造は適用されません。
変更点
- 新しい Nuxt のデフォルト
srcDir
はデフォルトでapp/
であり、ほとんどのものはそこから解決されます。 serverDir
は<srcDir>/server
ではなく<rootDir>/server
をデフォルトとします。layers/
、modules/
、public/
はデフォルトで<rootDir>
を基準に解決されます。- Nuxt Content v2.13+ を使用している場合、
content/
は<rootDir>
を基準に解決されます。 - 新しい
dir.app
が追加され、router.options.ts
とspa-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
)を指します。つまり、~/components
は app/components/
に、~/pages
は app/pages/
に解決されます。
👉 この変更を実装した PR を参照。
変更の理由
- パフォーマンス - リポジトリのルートにすべてのコードを配置すると、
.git/
やnode_modules/
フォルダが FS ウォッチャーによってスキャン/含まれる問題が発生し、非 Mac OS での起動が大幅に遅れる可能性があります。 - IDE の型安全性 -
server/
とアプリの残りの部分は、異なるグローバルインポートが利用可能な全く異なるコンテキストで実行されており、server/
がアプリの残りの部分と同じフォルダ内にないことを確認することは、IDE での自動補完を確保するための大きな第一歩です。
移行手順
app/
という新しいディレクトリを作成します。assets/
、components/
、composables/
、app/layouts/
、app/middleware/
、app/pages/
、app/plugins/
、utils/
フォルダをその下に移動し、app.vue
、error.vue
、app.config.ts
も移動します。app/router-options.ts
やapp/spa-loading-template.html
がある場合、これらのパスはそのままです。nuxt.config.ts
、content/
、layers/
、modules/
、public/
、server/
フォルダがapp/
フォルダの外、プロジェクトのルートに残っていることを確認します。tailwindcss
やeslint
の設定など、サードパーティの設定ファイルを新しいディレクトリ構造に合わせて更新することを忘れないでください(必要な場合 -@nuxtjs/tailwindcss
はtailwindcss
を正しく自動設定するはずです)。
この移行は npx codemod@latest nuxt/4/file-structure
を実行することで自動化できます。
ただし、移行は必須ではありません。現在のフォルダ構造を維持したい場合、Nuxt はそれを自動検出するはずです。(もしそうでない場合は、問題を報告してください。)唯一の例外は、すでにカスタム srcDir
を持っている場合です。この場合、modules/
、public/
、server/
フォルダはカスタム srcDir
ではなく rootDir
から解決されることを知っておく必要があります。必要に応じて dir.modules
、dir.public
、serverDir
を設定することでこれを上書きできます。
次の設定を使用して v3 フォルダ構造を強制することもできます:
export default defineNuxtConfig({
// 新しい srcDir のデフォルトを `app` からルートディレクトリに戻します
srcDir: '.',
// `router.options.ts` と `spa-loading-template.html` のディレクトリプレフィックスを指定します
dir: {
app: 'app'
}
})
シングルトンデータフェッチレイヤー
🚦 影響レベル: 中程度
変更点
Nuxt のデータフェッチシステム(useAsyncData
と useFetch
)は、パフォーマンスと一貫性を向上させるために大幅に再編成されました:
-
同じキーの共有リファレンス: 同じキーで
useAsyncData
またはuseFetch
を呼び出すすべての呼び出しは、同じdata
、error
、status
リファレンスを共有します。これにより、明示的なキーを持つすべての呼び出しは、deep
、transform
、pick
、getCachedData
、default
オプションが競合しないようにすることが重要です。 -
getCachedData
のより多くの制御:getCachedData
関数は、データがフェッチされるたびに呼び出されます。これは、ウォッチャーやrefreshNuxtData
の呼び出しによって引き起こされる場合でも同様です。(以前は、新しいデータが常にフェッチされ、この関数はこれらの場合には呼び出されませんでした。)キャッシュされたデータを使用するタイミングと再フェッチするタイミングをより制御できるようにするために、この関数はリクエストの原因を含むコンテキストオブジェクトを受け取ります。 -
リアクティブキーのサポート: 計算されたリファレンス、プレーンリファレンス、またはゲッタ関数をキーとして使用できるようになり、自動データ再フェッチが可能になります(データは別々に保存されます)。
-
データのクリーンアップ:
useAsyncData
でフェッチされたデータを使用する最後のコンポーネントがアンマウントされると、Nuxt はそのデータを削除してメモリ使用量の増加を防ぎます。
変更の理由
これらの変更は、メモリ使用量を改善し、useAsyncData
の呼び出し間でのロード状態の一貫性を向上させるために行われました。
移行手順
-
不一致のオプションを確認する: 同じキーを使用して異なるオプションやフェッチ関数を使用しているコンポーネントを確認します。
// これにより警告が発生します const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false }) const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
明示的なキーを共有する
useAsyncData
の呼び出し(カスタムオプションを持つ)を独自のコンポーザブルに抽出することが有益です:app/composables/useUserData.tsexport function useUserData(userId: string) { return useAsyncData( `user-${userId}`, () => fetchUser(userId), { deep: true, transform: (user) => ({ ...user, lastAccessed: new Date() }) } ) }
-
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] + } })
または、現在のところ、この動作を無効にすることができます:
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
purgeCachedData: false
}
})
レイヤー内のモジュール読み込み順序の修正
🚦 影響レベル: 最小
変更点
Nuxt レイヤー を使用する際のモジュールの読み込み順序が修正されました。以前は、プロジェクトルートのモジュールが拡張レイヤーのモジュールよりも先に読み込まれていましたが、これは期待される動作の逆でした。
現在、モジュールは正しい順序で読み込まれます:
- レイヤーモジュールが最初(拡張順序で - より深いレイヤーが最初)
- プロジェクトモジュールが最後(最優先)
これは以下の両方に影響します:
nuxt.config.ts
のmodules
配列で定義されたモジュールmodules/
ディレクトリから自動検出されたモジュール
変更の理由
この変更により:
- 拡張レイヤーが消費プロジェクトよりも優先度が低くなる
- モジュールの実行順序が直感的なレイヤー継承パターンに一致する
- モジュールの設定とフックがマルチレイヤーセットアップで期待通りに動作する
移行手順
ほとんどのプロジェクトは変更を必要としません。これは、期待される動作に一致するように読み込み順序を修正するものです。
ただし、以前の誤った順序に依存していたプロジェクトの場合は、以下を行う必要があるかもしれません:
- モジュールの依存関係を確認する: 特定の読み込み順序に依存するモジュールがあるかどうかを確認します。
- モジュール設定を調整する: 誤った順序に対応するために設定されたモジュールがある場合
- 徹底的にテストする: 修正された順序で期待通りにすべての機能が動作することを確認します。
新しい正しい順序の例:
// レイヤー: 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 #31507 と issue #25719 を参照してください。
ルートメタデータの重複排除
🚦 影響レベル: 最小
変更点
definePageMeta
を使用して、name
や path
などのルートメタデータを設定することが可能です。以前は、これらはルートとルートメタデータの両方で利用可能でした(例えば、route.name
と route.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-utils
の findComponent
を使用するテストや、コンポーネントの名前に依存する <KeepAlive>
で更新された名前を使用することを確認してください。
または、現在のところ、この動作を無効にすることができます:
export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false
}
})
Unhead v2
🚦 影響レベル: 最小
変更点
<head>
タグを生成するために使用される Unhead がバージョン2に更新されました。ほとんど互換性がありますが、低レベルの API にいくつかの破壊的変更が含まれています。
- 削除されたプロパティ:
vmid
、hid
、children
、body
。 - 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.spaLoaderTag
と app.spaLoaderAttrs
設定オプションを使用できます。
または、以前の動作に戻すことができます:
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
を設定して以前の動作に戻すことができます。
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'
}
}
})
または、以前の動作に戻すことができます:
export default defineNuxtConfig({
experimental: {
scanPageMeta: true
}
})
共有プリレンダーデータ
🚦 影響レベル: 中程度
変更点
useAsyncData
と useFetch
の呼び出しからのデータを異なるページ間で共有する以前の実験的機能を有効にしました。詳細は元の PRを参照してください。
変更の理由
この機能は、プリレンダリングされたページ間でペイロードデータを自動的に共有します。これにより、useAsyncData
や useFetch
を使用して異なるページで同じデータをフェッチするサイトのプリレンダリング時に大幅なパフォーマンス向上が得られます。
例えば、サイトがすべてのページで useFetch
呼び出しを必要とする場合(例えば、メニューのナビゲーションデータを取得するため、または CMS からのサイト設定を取得するため)、このデータはそれを使用する最初のページをプリレンダリングする際に一度だけフェッチされ、その後他のページをプリレンダリングする際に使用するためにキャッシュされます。
移行手順
データの一意のキーが常に同じデータに解決可能であることを確認してください。例えば、特定のページに関連するデータをフェッチするために useAsyncData
を使用している場合、そのデータに一意に一致するキーを提供する必要があります。(useFetch
はこれを自動的に行うはずです。)
// 動的ページ(例: `[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}`)
})
または、この機能を無効にすることができます:
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
を実行することで自動化できます。
問題が発生した場合は、次の設定で以前の動作に戻すことができます:
// @errors: 2353
export default defineNuxtConfig({
experimental: {
defaults: {
useAsyncData: {
value: 'null',
errorValue: 'null'
}
}
}
})
これを行っている場合は問題を報告してください。これを設定可能にする予定はありません。
useAsyncData
と useFetch
での refresh
呼び出し時の dedupe
オプションの廃止された boolean
値の削除
🚦 影響レベル: 最小
変更点
以前は、refresh
に dedupe: boolean
を渡すことが可能でした。これらは cancel
(true
)と defer
(false
)のエイリアスでした。
// @errors: 2322
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
変更の理由
これらのエイリアスは、より明確にするために削除されました。
問題は、useAsyncData
に dedupe
をオプションとして追加する際に発生しました。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
を実行することで自動化できます。
useAsyncData
と useFetch
での data
クリア時のデフォルトの尊重
🚦 影響レベル: 最小
変更点
useAsyncData
にカスタム default
値を提供した場合、clear
または clearNuxtData
を呼び出すときにこれが使用され、デフォルト値にリセットされます。
変更の理由
ユーザーはしばしば、反復時に null
/undefined
をチェックする必要を避けるために、空の配列などの適切な空の値を設定します。データをリセット/クリアする際にこれを尊重する必要があります。
useAsyncData
と useFetch
での pending
値の整合性
🚦 影響レベル: 中程度
useAsyncData
、useFetch
、useLazyAsyncData
、useLazyFetch
から返される pending
オブジェクトは、status
が保留中のときにのみ true
になる計算プロパティになりました。
変更点
現在、immediate: false
が渡された場合、最初のリクエストが行われるまで pending
は false
になります。これは、以前の動作からの変更であり、最初のリクエストが行われるまで pending
は常に true
でした。
変更の理由
これは、status
プロパティと一致するように pending
の意味を整合させるためです。status
もリクエストが進行中のときに保留中です。
移行手順
pending
プロパティに依存している場合、新しい動作に合わせてロジックを調整し、pending
が status
が保留中のときにのみ 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>
または、次の設定で以前の動作に一時的に戻すことができます:
export default defineNuxtConfig({
experimental: {
pendingWhenIdle: true
}
})
useAsyncData
と useFetch
でのキー変更動作
🚦 影響レベル: 中程度
変更点
useAsyncData
または useFetch
でリアクティブキーを使用する場合、キーが変更されると Nuxt は自動的にデータを再フェッチします。immediate: false
が設定されている場合、useAsyncData
はデータが一度フェッチされた場合にのみキーが変更されたときにデータをフェッチします。
以前は、useFetch
はわずかに異なる動作をしていました。キーが変更されると常にデータをフェッチしていました。
現在、useFetch
と useAsyncData
は一貫して動作し、データが一度フェッチされた場合にのみキーが変更されたときにデータをフェッチします。
変更の理由
これにより、useAsyncData
と useFetch
の間で一貫した動作が確保され、予期しないフェッチを防ぎます。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
}
})
useAsyncData
と useFetch
での浅いデータリアクティビティ
🚦 影響レベル: 最小
useAsyncData
、useFetch
、useLazyAsyncData
、useLazyFetch
から返される data
オブジェクトは、現在 shallowRef
であり、ref
ではありません。
変更点
新しいデータがフェッチされると、data
に依存するものは依然としてリアクティブです。なぜなら、オブジェクト全体が置き換えられるからです。しかし、コードがそのデータ構造内のプロパティを変更した場合、これはアプリ内でのリアクティビティをトリガーしません。
変更の理由
これにより、深くネストされたオブジェクトや配列に対して Vue がすべてのプロパティ/配列を監視する必要がなくなるため、大幅なパフォーマンス向上が得られます。ほとんどの場合、data
は不変であるべきです。
移行手順
ほとんどの場合、移行手順は必要ありませんが、データオブジェクトのリアクティビティに依存している場合、次の2つのオプションがあります:
- コンポーザブルごとに深いリアクティビティを選択的にオプトインできます:
- const { data } = useFetch('/api/test') + const { data } = useFetch('/api/test', { deep: true })
- プロジェクト全体でデフォルトの動作を変更できます(推奨されません):
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
を使用していました。
さらに、これらのテンプレート内でコード生成に使用できるテンプレートユーティリティ(serialize
、importName
、importSources
)を提供していましたが、これらは削除されます。
変更の理由
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 })
+ },
})
最後に、テンプレートユーティリティ(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
を実行することで自動化できます。
デフォルト TypeScript 設定の変更
🚦 影響レベル: 最小
変更点
compilerOptions.noUncheckedIndexedAccess
が false
から true
に変更されました。
変更の理由
この変更は、以前の 3.12 設定更新 に続くもので、主に TotalTypeScript の推奨事項 に従っています。
移行手順
2つのアプローチがあります:
-
アプリで型チェックを実行し、新しいエラーを修正する(推奨)。
-
nuxt.config.ts
で新しいデフォルトを上書きする:export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedIndexedAccess: false } } } })
TypeScript 設定の分割
🚦 影響レベル: 最小
変更点
Nuxt は、異なるコンテキストに対してより良い型チェック体験を提供するために、別々の TypeScript 設定を生成するようになりました:
-
新しい 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
- 後方互換性のためのレガシー設定
-
後方互換性:
.nuxt/tsconfig.json
を拡張する既存のプロジェクトは、以前と同じように動作します。 -
プロジェクト参照のオプトイン: 新しいプロジェクトやより良い型チェックを望むプロジェクトは、TypeScript のプロジェクト参照機能を採用できます。
-
コンテキスト固有の型チェック: 各コンテキストには、その特定の環境に適したコンパイラオプションとインクルード/エクスクルードがあります。
-
新しい
typescript.nodeTsConfig
オプション: ビルド時コード用の TypeScript 設定をカスタマイズできるようになりました。
変更の理由
この変更は、いくつかの利点を提供します:
- より良い型安全性: 各コンテキスト(アプリ、サーバー、ビルド時)は、コンテキスト固有のグローバルと API を使用して適切な型チェックを受けます。
- 改善された IDE 体験: コードベースの異なる部分に対するより良いインテリセンスとエラーレポート。
- クリーンな分離: サーバーコードがクライアントサイド API を誤って提案しないようにし、逆もまた然り。
- パフォーマンス: 適切にスコープされた設定で TypeScript がより効率的にコードをチェックできます。
例えば、nuxt.config.ts
では自動インポートが利用できません(以前は TypeScript によってフラグが立てられませんでした)。また、IDE は server/
ディレクトリ内でヒントされた別のコンテキストを認識していましたが、これは型チェックには反映されていませんでした(別のステップが必要でした)。
移行手順
移行は必要ありません - 既存のプロジェクトは以前と同じように動作します。
ただし、型チェックを改善するために、新しいプロジェクト参照アプローチをオプトインすることができます:
-
ルート
tsconfig.json
を更新してプロジェクト参照を使用する:{ "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] }
-
手動のサーバー
tsconfig.json
ファイルを削除する(例えば、.nuxt/tsconfig.server.json
を拡張しているserver/tsconfig.json
)。 -
型チェックスクリプトを更新してプロジェクト参照のビルドフラグを使用する:
- "typecheck": "nuxt prepare && vue-tsc --noEmit" + "typecheck": "nuxt prepare && vue-tsc -b --noEmit"
-
すべての型拡張を適切なコンテキストに移動する:
- アプリコンテキストの型を拡張している場合、ファイルを
app/
ディレクトリに移動します。 - サーバーコンテキストの型を拡張している場合、ファイルを
server/
ディレクトリに移動します。 - アプリとサーバー間で共有される型を拡張している場合、ファイルを
shared/
ディレクトリに移動します。
app/
、server/
、またはshared/
ディレクトリの外部から型を拡張することは、新しいプロジェクト参照セットアップでは機能しません。 - アプリコンテキストの型を拡張している場合、ファイルを
-
必要に応じて Node.js TypeScript オプションを設定する:
export default defineNuxtConfig({ typescript: { // アプリ/サーバー TypeScript 設定をカスタマイズ tsConfig: { compilerOptions: { strict: true } }, // ビルド時 TypeScript 設定をカスタマイズ nodeTsConfig: { compilerOptions: { strict: true } } } })
-
TypeScript チェックを実行する CI/ビルドスクリプトを更新して、新しいプロジェクト参照アプローチを使用することを確認する。
新しい設定は、オプトインしたプロジェクトに対してより良い型安全性とインテリセンスを提供し、既存のセットアップに対して完全な後方互換性を維持します。
実験的機能の削除
🚦 影響レベル: 最小
変更点
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
を使用します
変更の理由
これらのオプションはしばらくの間現在の値に設定されており、設定可能である必要がある理由はありません。
移行手順
-
polyfillVueUseHead
は このプラグイン を使用してユーザーランドで実装可能です。 -
respectNoSSRHeader
は サーバーミドルウェア を使用してユーザーランドで実装可能です。
トップレベル 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 2 | Nuxt Bridge | Nuxt 3+ |
---|---|---|---|
Vue | 2 | 2 | 3 |
安定性 | 😊 安定 | 😊 安定 | 😊 安定 |
パフォーマンス | 🏎 速い | ✈️ もっと速い | 🚀 最速 |
Nitro エンジン | ❌ | ✅ | ✅ |
ESM サポート | 🌙 部分的 | 👍 より良い | ✅ |
TypeScript | ☑️ オプトイン | 🚧 部分的 | ✅ |
Composition API | ❌ | 🚧 部分的 | ✅ |
Options API | ✅ | ✅ | ✅ |
コンポーネント自動インポート | ✅ | ✅ | ✅ |
<script setup> 構文 | ❌ | 🚧 部分的 | ✅ |
自動インポート | ❌ | ✅ | ✅ |
webpack | 4 | 4 | 5 |
Vite | ⚠️ 部分的 | 🚧 部分的 | ✅ |
Nuxt CLI | ❌ 古い | ✅ nuxt | ✅ nuxt |
静的サイト | ✅ | ✅ | ✅ |
Nuxt 2 から Nuxt 3+ への移行
移行ガイドは、Nuxt 2 の機能を Nuxt 3+ の機能に比較し、現在のアプリケーションを適応させるためのステップバイステップのガイダンスを提供します。
こちらも参照 migration > overviewNuxt 2 から Nuxt Bridge への移行
Nuxt 2 アプリケーションを Nuxt 3 に段階的に移行したい場合は、Nuxt Bridge を使用できます。Nuxt Bridge は、Nuxt 2 で Nuxt 3+ の機能をオプトインメカニズムで使用できる互換レイヤーです。
こちらも参照 bridge > overview※このページは Nuxt.js 公式ドキュメントの翻訳ページ(非公式)です。
公式ドキュメントの該当ページはこちら:
https://nuxt.com/docs/4.x/getting-started/upgrade