升級指南
升級 Nuxt
最新版本
要將 Nuxt 升級到最新版本,請使用 nuxt upgrade
命令。
npx nuxt upgrade
yarn nuxt upgrade
pnpm nuxt upgrade
bun x nuxt upgrade
夜間釋出渠道
要在 Nuxt 功能釋出前使用最新構建版本並測試其功能,請閱讀夜間釋出通道指南。
遷移到 Nuxt 4
Nuxt 4 包含了顯著的改進和變更。本指南將幫助您將現有的 Nuxt 3 應用程式遷移到 Nuxt 4。
首先,升級到 Nuxt 4
npm install nuxt@^4.0.0
yarn add nuxt@^4.0.0
pnpm add nuxt@^4.0.0
bun add nuxt@^4.0.0
升級後,大多數 Nuxt 4 的行為現在都是預設的。但是,如果您的遷移需要保持向後相容性,某些功能仍然可以配置。
以下部分詳細介紹了升級到 Nuxt 4 時需要進行的關鍵變更和遷移。
突破性或重大變更已在下面記錄,並附有遷移步驟和可用的配置選項。
使用 Codemods 進行遷移
為了方便升級過程,我們與Codemod團隊合作,透過一些開源 codemods 自動化了許多遷移步驟。
npx codemod feedback
向 Codemod 團隊報告 🙏有關 Nuxt 4 codemods 的完整列表、詳細資訊、其來源以及執行它們的各種方式,請訪問Codemod 登錄檔.
您可以使用以下 codemod
配方執行本指南中提到的所有 codemods
npx codemod@latest nuxt/4/migration-recipe
yarn dlx codemod@latest nuxt/4/migration-recipe
pnpm dlx codemod@latest nuxt/4/migration-recipe
bun x codemod@latest nuxt/4/migration-recipe
此命令將按順序執行所有 codemods,您可以選擇取消選擇任何不想執行的 codemod。每個 codemod 及其各自的變更也列在下面,並且可以獨立執行。
新目錄結構
🚦 影響級別:重大
Nuxt 現在預設使用新的目錄結構,並向後相容(因此如果 Nuxt 檢測到您正在使用舊結構,例如頂層 app/pages/
目錄,則此新結構將不適用)。
變更內容
- 新的 Nuxt 預設
srcDir
預設為app/
,大多數內容都從那裡解析。 serverDir
現在預設為<rootDir>/server
,而不是<srcDir>/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 OSes 上的啟動。 - 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/
資料夾將從您的 rootDir
而不是您的自定義 srcDir
解析。如果需要,您可以透過配置 dir.modules
、dir.public
和 serverDir
來覆蓋此設定。
您還可以使用以下配置強制使用 v3 資料夾結構
export default defineNuxtConfig({
// This reverts the new srcDir default from `app` back to your root directory
srcDir: '.',
// This specifies the directory prefix for `router.options.ts` and `spa-loading-template.html`
dir: {
app: 'app',
},
})
單例資料獲取層
🚦 影響級別:中等
變更內容
Nuxt 的資料獲取系統(useAsyncData
和 useFetch
)已進行重大重組,以提高效能和一致性
- 相同鍵的共享引用:所有使用相同鍵呼叫
useAsyncData
或useFetch
的函式現在共享相同的data
、error
和status
引用。這意味著所有帶有顯式鍵的呼叫都不能有衝突的deep
、transform
、pick
、getCachedData
或default
選項。 - 對
getCachedData
的更多控制:getCachedData
函式現在每次獲取資料時都會被呼叫,即使這是由觀察器或呼叫refreshNuxtData
引起的。(以前,總是獲取新資料,並且在這種情況下不呼叫此函式。)為了更好地控制何時使用快取資料以及何時重新獲取,該函式現在接收一個包含請求原因的上下文物件。 - 響應式鍵支援:您現在可以使用計算引用、普通引用或 getter 函式作為鍵,這使得資料能夠自動重新獲取(並單獨儲存資料)。
- 資料清理:當使用
useAsyncData
獲取資料的最後一個元件被解除安裝時,Nuxt 將刪除該資料,以避免記憶體使用量不斷增長。
變更原因
這些更改旨在改善記憶體使用並提高 useAsyncData
呼叫之間的載入狀態一致性。
遷移步驟
- 檢查不一致的選項:檢查所有使用相同鍵但選項或獲取函式不同的元件。
// This will now trigger a warning 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 - can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' + + // Example: Don't use cache on manual refresh + if (ctx.cause === 'refresh:manual') return undefined + + return cachedData[key] + } })
或者,現在您可以停用此行為
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
purgeCachedData: false,
},
})
層中模組載入順序已更正
🚦 影響級別:最小
變更內容
使用Nuxt 層時,模組的載入順序已更正。以前,專案根目錄中的模組在擴充套件層中的模組之前載入,這與預期行為相反。
現在模組按正確順序載入
- 層模組優先(按擴充套件順序 - 較深層優先)
- 專案模組最後(最高優先順序)
這會影響
- 在
nuxt.config.ts
中的modules
陣列中定義的模組 - 從
modules/
目錄自動發現的模組
變更原因
此更改確保
- 擴充套件層的優先順序低於消費專案
- 模組執行順序與直觀的層繼承模式匹配
- 模組配置和鉤子在多層設定中按預期工作
遷移步驟
大多數專案不需要更改,因為這會更正載入順序以匹配預期行為。
但是,如果您的專案依賴於以前不正確的順序,您可能需要
- 審查模組依賴關係:檢查是否有任何模組依賴於特定的載入順序
- 調整模組配置:如果模組是為解決不正確的順序而配置的
- 徹底測試:確保所有功能在更正的順序下按預期工作
新正確順序的示例
// Layer: my-layer/nuxt.config.ts
export default defineNuxtConfig({
modules: ['layer-module-1', 'layer-module-2'],
})
// Project: nuxt.config.ts
export default defineNuxtConfig({
extends: ['./my-layer'],
modules: ['project-module-1', 'project-module-2'],
})
// Loading order (corrected):
// 1. layer-module-1
// 2. layer-module-2
// 3. project-module-1 (can override layer modules)
// 4. project-module-2 (can override layer modules)
如果您因需要註冊鉤子而遇到模組順序依賴問題,請考慮對需要呼叫鉤子的模組使用 modules:done
鉤子。此鉤子在所有其他模組載入後執行,這意味著它是安全使用的。
👉 參閱PR #31507等等問題 #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
在這種情況下,元件名稱將是 MyComponent
,就 Vue 而言。如果您想將其與 <KeepAlive>
一起使用,或者在 Vue DevTools 中識別它,您將需要使用此名稱。
但為了自動匯入它,您需要使用 SomeFolderMyComponent
。
透過此更改,這兩個值將匹配,Vue 將生成一個與 Nuxt 元件命名模式匹配的元件名稱。
遷移步驟
確保在任何使用 @vue/test-utils
中的 findComponent
的測試中以及任何依賴於元件名稱的 <KeepAlive>
中使用更新後的名稱。
或者,現在您可以停用此行為
export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false,
},
})
Unhead v2
🚦 影響級別:最小
變更內容
Unhead,用於生成 <head>
標籤,已更新到版本 2。雖然大部分相容,但它包含幾個對低階 API 的重大更改。
- 已刪除的 props:
vmid
、hid
、children
、body
。 - 不再支援 Promise 輸入。
- 標籤現在預設使用 Capo.js 排序。
遷移步驟
以上更改對您的應用程式影響極小。
如果您遇到問題,您應該驗證
- 您沒有使用任何已刪除的 props。
useHead({
meta: [{
name: 'description',
// meta tags don't need a vmid, or a key
- vmid: 'description'
- hid: 'description'
}]
})
import { AliasSortingPlugin, TemplateParamsPlugin } 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
)時,我們選擇性地在 Nuxt 應用程式根目錄下渲染一個載入螢幕(來自 ~/app/spa-loading-template.html
- 請注意,在 Nuxt 4 中這也已更改為 ~/spa-loading-template.html
)
<div id="__nuxt">
<!-- spa loading template -->
</div>
現在,我們預設在 Nuxt 應用根目錄旁邊渲染模板
<div id="__nuxt"></div>
<!-- spa loading template -->
變更原因
這允許 spa 載入模板保留在 DOM 中,直到 Vue 應用程式的 suspense 解決,從而防止閃白。
遷移步驟
如果您正在使用 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 現在將只內聯 Vue 元件的樣式,而不是全域性 CSS。
變更內容
以前,Nuxt 會內聯所有 CSS,包括全域性樣式,並刪除 <link>
元素以分離 CSS 檔案。現在,Nuxt 將只對 Vue 元件執行此操作(以前會生成單獨的 CSS 塊)。我們認為這更好地平衡了減少單獨的網路請求(就像以前一樣,初始載入時不會為每個頁面或每個元件的單獨 .css
檔案發出單獨的請求),以及允許快取單個全域性 CSS 檔案並減少初始請求的文件下載大小。
遷移步驟
此功能完全可配置,您可以透過將 inlineStyles: true
設定為內聯全域性 CSS 以及元件內 CSS 來恢復以前的行為。
export default defineNuxtConfig({
features: {
inlineStyles: true,
},
})
解析後掃描頁面元資料
🚦 影響級別:最小
變更內容
我們現在在呼叫 pages:extend
鉤子之後而不是之前掃描頁面元資料(在 definePageMeta
中定義)。
變更原因
這是為了允許掃描使用者希望在 pages:extend
中新增的頁面的元資料。我們仍然提供了一個在新 pages:resolved
鉤子中更改或覆蓋頁面元資料的機會。
遷移步驟
如果您想覆蓋頁面元資料,請在 pages:resolved
中進行,而不是在 pages:extend
中進行。
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.
變更原因
此功能自動在預渲染的頁面之間共享 payload 資料。這可以在預渲染使用 useAsyncData
或 useFetch
並在不同頁面中獲取相同資料的站點時顯著提高效能。
例如,如果您的站點需要為每個頁面呼叫 useFetch
(例如,從 CMS 獲取選單的導航資料或站點設定),則在預渲染第一個使用它的頁面時,此資料只會獲取一次,然後快取以供預渲染其他頁面時使用。
遷移步驟
確保您的資料的任何唯一鍵始終解析為相同的資料。例如,如果您使用 useAsyncData
獲取與特定頁面相關的資料,則應提供唯一匹配該資料的鍵。(useFetch
應該會自動為您執行此操作。)
// 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}`)
})
或者,您可以透過以下方式停用此功能
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
自動化此步驟useAsyncData
和 useFetch
中呼叫 refresh
時,移除了 dedupe
選項的已棄用 boolean
值 在
🚦 影響級別:最小
變更內容
以前可以將 dedupe: boolean
傳遞給 refresh
。這些是 cancel
(true
) 和 defer
(false
) 的別名。
const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
變更原因
為了提高畫質晰度,這些別名已被移除。
當在 useAsyncData
的選項中新增 dedupe
時,出現了問題,我們刪除了布林值,因為它們最終是相反的。
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
也處於 pending 狀態時才為 true
。
變更內容
現在,當傳遞 immediate: false
時,pending
將在首次請求之前為 false
。這與之前的行為不同,之前 pending
始終為 true
,直到首次請求。
變更原因
這使 pending
的含義與 status
屬性保持一致,後者在請求進行中時也處於 pending
狀態。
遷移步驟
如果您依賴 pending
屬性,請確保您的邏輯考慮了新行為,即 pending
僅當狀態也處於 pending 狀態時才為 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 })
要退出此行為
// Or globally in your Nuxt config
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true,
},
})
useAsyncData
和 useFetch
中的淺層資料響應性
🚦 影響級別:最小
從 useAsyncData
、useFetch
、useLazyAsyncData
和 useLazyFetch
返回的 data
物件現在是 shallowRef
而不是 ref
。
變更內容
當獲取新資料時,任何依賴於 data
的內容仍將是響應式的,因為整個物件被替換。但如果您的程式碼更改了該資料結構內部的屬性,這不會觸發應用程式中的任何響應性。
變更原因
這為深度巢狀的物件和陣列帶來了顯著的效能改進,因為 Vue 不需要監視每個屬性/陣列的修改。在大多數情況下,data
也應該是不可變的。
遷移步驟
在大多數情況下,不需要遷移步驟,但如果您依賴於資料物件的響應性,則有兩種選擇
- 您可以按組合函式粒度選擇性地啟用深度響應性
- 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 模組。請參閱問題 #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 使用 lodash/template
編譯位於檔案系統上使用 .ejs
檔案格式/語法的模板。
此外,我們提供了一些模板工具(serialize
、importName
、importSources
),這些工具可用於在這些模板中生成程式碼,現在這些工具已被移除。
變更原因
在 Nuxt v3 中,我們轉向了一種“虛擬”語法,其中包含一個 getContents()
函式,該函式更靈活、效能更高。
此外,lodash/template
曾出現過一系列安全問題。這些問題實際上不適用於 Nuxt 專案,因為它在構建時而非執行時使用,並且由受信任的程式碼使用。但是,它們仍然出現在安全審計中。此外,lodash
是一個龐大的依賴項,並且大多數專案未使用。
最後,直接在 Nuxt 中提供程式碼序列化函式並不理想。相反,我們維護像unjs/knitwork這樣的專案,它們可以是您專案的依賴項,並且可以在其中直接報告/解決安全問題,而無需升級 Nuxt 本身。
遷移步驟
我們已經提出了 PR 來更新使用 EJS 語法的模組,但如果您需要自己執行此操作,您有三種向後/向前相容的替代方案
- 將您的字串插值邏輯直接移入
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
現在是 true
而不是 false
。
變更原因
此更改是先前3.12 配置更新的後續,其中我們改進了預設值,主要遵循TotalTypeScript 的建議.
遷移步驟
有兩種方法
- 對您的應用程式執行型別檢查並修復任何新錯誤(推薦)。
- 在您的
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/server 目錄).nuxt/tsconfig.node.json
- 用於您的構建時程式碼(模組、nuxt.config.ts
等).nuxt/tsconfig.shared.json
- 用於應用程式和伺服器上下文之間共享的程式碼(如型別和非環境特定工具).nuxt/tsconfig.json
- 用於向後相容的舊配置
- 向後相容性:現有擴充套件
.nuxt/tsconfig.json
的專案將繼續按以前的方式工作。 - 選擇性專案引用:新專案或需要更好型別檢查的專案可以採用 TypeScript 的專案引用功能。
- 上下文特定的型別檢查:每個上下文現在都具有適合其特定環境的編譯器選項和包含/排除項。
- 新的
typescript.nodeTsConfig
選項:您現在可以自定義 Node.js 構建時程式碼的 TypeScript 配置。
變更原因
此更改提供了以下幾點優勢
- 更好的型別安全:每個上下文(應用程式、伺服器、構建時)都透過上下文特定的全域性變數和 API 獲得適當的型別檢查。
- 改進的 IDE 體驗:為程式碼庫的不同部分提供更好的智慧感知和錯誤報告。
- 更清晰的分離:伺服器程式碼不會錯誤地建議客戶端 API,反之亦然。
- 效能:TypeScript 可以使用適當範圍的配置更有效地檢查程式碼。
例如,在您的 nuxt.config.ts
中無法使用自動匯入(但以前 TypeScript 不會標記此問題)。雖然 IDE 識別出您的 server/
目錄中的 tsconfig.json
所暗示的獨立上下文,但這並未反映在型別檢查中(需要單獨的步驟)。
遷移步驟
無需遷移 - 現有專案將繼續按以前的方式工作。
但是,為了利用改進的型別檢查,您可以選擇加入新的專案引用方法
- 更新您的根
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
檔案(如server/tsconfig.json
),這些檔案擴充套件了.nuxt/tsconfig.server.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: { // Customize app/server TypeScript config tsConfig: { compilerOptions: { strict: true, }, }, // Customize build-time TypeScript config nodeTsConfig: { compilerOptions: { strict: true, }, }, }, })
- 更新任何執行 TypeScript 檢查的 CI/構建指令碼,以確保它們使用新的專案引用方法。
新配置為選擇加入的專案提供了更好的型別安全性和智慧感知,同時保持了現有設定的完全向後相容性。
移除實驗性功能
🚦 影響級別:最小
變更內容
Nuxt 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
變更原因
這些選項已設定為其當前值一段時間,我們沒有理由相信它們需要保持可配置。
遷移步驟
generate
配置 移除頂層
🚦 影響級別:最小
變更內容
Nuxt 4 中不再提供頂層 generate
配置選項。這包括其所有屬性
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']
+ }
+ }
})
Nuxt 2 與 Nuxt 3+
下表快速比較了 Nuxt 的 3 個版本
功能/版本 | Nuxt 2 | Nuxt Bridge | Nuxt 3+ |
---|---|---|---|
Vue | 2 | 2 | 3 |
穩定性 | 😊 穩定 | 😊 穩定 | 😊 穩定 |
效能 | 🏎 快速 | ✈️ 更快 | 🚀 最快 |
Nitro 引擎 | ❌ | ✅ | ✅ |
ESM 支援 | 🌙 部分 | 👍 更好 | ✅ |
TypeScript | ☑️ 選擇啟用 | 🚧 部分 | ✅ |
組合式 API | ❌ | 🚧 部分 | ✅ |
Options API | ✅ | ✅ | ✅ |
元件自動匯入 | ✅ | ✅ | ✅ |
<script setup> 語法 | ❌ | 🚧 部分 | ✅ |
自動匯入 | ❌ | ✅ | ✅ |
webpack | 4 | 4 | 5 |
Vite | ⚠️ 部分 | 🚧 部分 | ✅ |
Nuxt CLI | ❌ 舊版 | ✅ nuxt | ✅ nuxt |
靜態站點 | ✅ | ✅ | ✅ |
Nuxt 2 到 Nuxt 3+
遷移指南提供了 Nuxt 2 功能到 Nuxt 3+ 功能的逐步比較以及調整當前應用程式的指導。
Nuxt 2 到 Nuxt Bridge
如果您希望逐步將 Nuxt 2 應用程式遷移到 Nuxt 3,您可以使用 Nuxt Bridge。Nuxt Bridge 是一個相容層,允許您透過選擇性機制在 Nuxt 2 中使用 Nuxt 3+ 功能。