升級指南
升級 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 的許多重大變更。
選擇加入 Nuxt 4
首先,將 Nuxt 升級到最新版本。
然後,您可以設定您的 compatibilityVersion
以符合 Nuxt 4 的行為
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,
// spaLoadingTemplateLocation: 'within',
// defaults: {
// useAsyncData: {
// deep: true
// }
// }
// },
// features: {
// inlineStyles: true
// },
// unhead: {
// renderSSRHeadOptions: {
// omitLineBreaks: false
// }
// }
})
當您將 compatibilityVersion
設定為 4
時,您的 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
配方執行本指南中提及的所有 codemod
npx codemod@latest nuxt/4/migration-recipe
此命令會依序執行所有 codemod,您可以選擇取消選取任何您不想執行的 codemod。每個 codemod 也會在下方列出,以及其各自的變更,且可以獨立執行。
新的目錄結構
🚦 影響程度:重大
Nuxt 現在預設為新的目錄結構,具有向後相容性 (因此,如果 Nuxt 偵測到您正在使用舊結構,例如頂層的 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/
server/
api/
middleware/
plugins/
routes/
utils/
nuxt.config.ts
👉 如需更多詳細資訊,請參閱實作此變更的 PR。
變更原因
- 效能 - 將所有程式碼放置在儲存庫的根目錄中,會導致
.git/
和node_modules/
資料夾被檔案系統監看工具掃描/包含,這可能會大幅延遲非 Mac 作業系統上的啟動時間。 - IDE 類型安全 -
server/
和應用程式的其餘部分在兩個完全不同的內容中執行,其中可用的全域匯入不同,而且確保server/
不在與應用程式其餘部分相同的資料夾內是確保您在 IDE 中獲得良好自動完成功能的第一步。
移轉步驟
- 建立一個名為
app/
的新目錄。 - 將您的
assets/
、components/
、composables/
、layouts/
、middleware/
、pages/
、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 `app/router.options.ts` and `app/spa-loading-template.html`
dir: {
app: 'app'
}
})
路由中繼資料的重複資料刪除
🚦 影響程度:最小
變更內容
可以使用 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
}
})
SPA 載入畫面的新 DOM 位置
🚦 影響程度:最小
變更內容
當呈現僅限於用戶端的頁面時 (使用 ssr: false
),我們會選擇性地在 Nuxt 應用程式根目錄中呈現載入畫面 (來自 app/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',
}
})
更細緻的內嵌樣式
🚦 影響程度:中等
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。
變更原因
此功能會自動在預先渲染的頁面之間共享酬載資料。當預先渲染使用 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
來自動執行此步驟如果您遇到任何問題,可以使用以下方式回復到先前的行為
export default defineNuxtConfig({
experimental: {
defaults: {
useAsyncData: {
value: 'null',
errorValue: 'null'
}
}
}
})
如果您正在執行此操作,請回報問題,因為我們不打算將其保留為可配置的項目。
移除在 useAsyncData
和 useFetch
中呼叫 refresh
時 dedupe
選項的已棄用 boolean
值
🚦 影響程度:最小
變更內容
先前可以將 dedupe: boolean
傳遞給 refresh
。這些是 cancel
(true
) 和 defer
(false
) 的別名。
const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' }))
async function refreshData () {
await refresh({ dedupe: true })
}
變更原因
為了更清楚起見,已移除這些別名。
在將 dedupe
作為 useAsyncData
的選項新增時出現了問題,並且我們移除了 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
。在重設/清除資料時應遵守此原則。
移轉步驟
如果您遇到任何問題,可以暫時使用以下方式回復到先前的行為
export default defineNuxtConfig({
experimental: {
resetAsyncDataToUndefined: 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 模組。請參閱 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 之類的專案,這些專案可以是您專案的相依性,並且可以在其中直接回報/解決安全性問題,而無需升級 Nuxt 本身。
移轉步驟
我們提出了 PR 來更新使用 EJS 語法的模組,但是如果您需要自行執行此操作,則您有三個向後/向前相容的替代方案
- 將您的字串內插邏輯直接移到
getContents()
中。 - 使用自訂函數來處理替換,例如在 https://github.com/nuxt-modules/color-mode/pull/240 中。
- 繼續使用
lodash
,作為您專案而不是 Nuxt 的相依性
+ 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 中不再可配置四個實驗性功能
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+
下表提供了 3 個 Nuxt 版本的快速比較
功能/版本 | Nuxt 2 | Nuxt Bridge | Nuxt 3+ |
---|---|---|---|
Vue | 2 | 2 | 3 |
穩定性 | 😊 穩定 | 😊 穩定 | 😊 穩定 |
效能 | 🏎 快 | ✈️ 更快 | 🚀 最快 |
Nitro 引擎 | ❌ | ✅ | ✅ |
ESM 支援 | 🌙 部分 | 👍 更好 | ✅ |
TypeScript | ☑️ 選擇加入 | 🚧 部分 | ✅ |
組合 API | ❌ | 🚧 部分 | ✅ |
選項 API | ✅ | ✅ | ✅ |
元件自動匯入 | ✅ | ✅ | ✅ |
<script setup> 語法 | ❌ | 🚧 部分 | ✅ |
自動匯入 | ❌ | ✅ | ✅ |
webpack | 4 | 4 | 5 |
Vite | ⚠️ 部分 | 🚧 部分 | ✅ |
Nuxi CLI | ❌ 舊 | ✅ nuxi | ✅ nuxi |
靜態網站 | ✅ | ✅ | ✅ |
Nuxt 2 至 Nuxt 3+
遷移指南提供了 Nuxt 2 功能與 Nuxt 3+ 功能的逐步比較,以及調整目前應用程式的指南。
Nuxt 2 到 Nuxt Bridge
如果您偏好逐步將您的 Nuxt 2 應用程式遷移到 Nuxt 3,您可以使用 Nuxt Bridge。Nuxt Bridge 是一個相容性層,讓您可以在 Nuxt 2 中使用 Nuxt 3+ 的功能,並採用選擇加入機制。