Nuxt.js 詳解(三):遷移踩坑與最佳實(shí)踐
Nuxt.js 詳解三遷移踩坑與最佳實(shí)踐這是 Nuxt 系列的最后一篇。前兩篇講了 Nuxt 是什么、怎么用。這篇講實(shí)際項(xiàng)目里你會(huì)踩的坑——SSR 兼容性、數(shù)據(jù)水合、性能優(yōu)化、部署問(wèn)題以及怎么避開(kāi)它們。一、SSR 兼容性問(wèn)題最高頻踩坑問(wèn)題是什么Nuxt 開(kāi)啟 SSR 后組件會(huì)在服務(wù)端先執(zhí)行一次再到客戶(hù)端執(zhí)行一次。服務(wù)端環(huán)境里沒(méi)有window、document、localStorage、sessionStorage這些瀏覽器對(duì)象。只要你的代碼在服務(wù)端碰到了這些對(duì)象直接報(bào)錯(cuò)ReferenceError: window is not defined ReferenceError: document is not defined錯(cuò)誤寫(xiě)法script setup // ? setup 頂層直接用 windowSSR 階段會(huì)炸 const width window.innerWidth const token localStorage.getItem(token) /script正確寫(xiě)法一用 onMountedonMounted只在客戶(hù)端執(zhí)行服務(wù)端不跑script setup const width ref(0) onMounted(() { width.value window.innerWidth }) /script正確寫(xiě)法二用 process.client 判斷if(process.client){// 這段代碼只在客戶(hù)端執(zhí)行consttokenlocalStorage.getItem(token)}Nuxt 3 也支持import.meta.clientif(import.meta.client){consttokenlocalStorage.getItem(token)}正確寫(xiě)法三用 包裹有些組件只能在客戶(hù)端跑比如用到 canvas、地圖 SDK用ClientOnly包起來(lái)template ClientOnly MapComponent / template #fallback div地圖加載中.../div /template /ClientOnly /template#fallback是服務(wù)端渲染時(shí)的占位內(nèi)容避免白屏。二、第三方庫(kù) SSR 兼容處理問(wèn)題很多第三方庫(kù)圖表庫(kù)、編輯器、地圖默認(rèn)依賴(lài)瀏覽器環(huán)境在 SSR 階段會(huì)報(bào)錯(cuò)。方案一動(dòng)態(tài)導(dǎo)入 ssr:falsescript setup const MonacoEditor defineAsyncComponent(() import(guolao/vue-monaco-editor) ) /script template ClientOnly MonacoEditor / /ClientOnly /template方案二nuxt.config 配置// nuxt.config.tsexportdefaultdefineNuxtConfig({build:{transpile:[vue-monaco-editor]// 讓 Nuxt 處理這個(gè)庫(kù)的 SSR},vite:{ssr:{noExternal:[some-ssr-unfriendly-lib]// 不走外部化打包進(jìn) SSR bundle}}})方案三用插件按需加載// plugins/echarts.client.ts// 文件名帶 .client 后綴只在客戶(hù)端加載import{use}fromecharts/coreimport{CanvasRenderer}fromecharts/renderersimport{BarChart}fromecharts/chartsuse([CanvasRenderer,BarChart])exportdefaultdefineNuxtPlugin((){// 初始化邏輯})三、數(shù)據(jù)水合Hydration問(wèn)題問(wèn)題是什么SSR 時(shí)服務(wù)端渲染了一份 HTML客戶(hù)端拿到后會(huì)把這份 HTML 和 JS 狀態(tài)對(duì)齊hydration。如果服務(wù)端和客戶(hù)端渲染出來(lái)的內(nèi)容不一致就會(huì)報(bào) hydration mismatch 警告甚至頁(yè)面錯(cuò)亂。常見(jiàn)觸發(fā)場(chǎng)景時(shí)間不一致服務(wù)端渲染 12:00:00客戶(hù)端水合時(shí)已經(jīng) 12:00:01。!-- ? 會(huì)出問(wèn)題 -- template div{{ new Date().toLocaleTimeString() }}/div /template隨機(jī)數(shù)不一致!-- ? 服務(wù)端和客戶(hù)端隨機(jī)數(shù)不同 -- template div驗(yàn)證碼{{ Math.random() }}/div /template解決方案把不確定的內(nèi)容放到onMounted里生成script setup const timeStr ref() onMounted(() { timeStr.value new Date().toLocaleTimeString() }) /script template div{{ timeStr || --:--:-- }}/div /template四、useFetch vs useAsyncData 怎么選這是新手最容易困惑的點(diǎn)。特性u(píng)seFetchuseAsyncData定位封裝好的 HTTP 請(qǐng)求工具通用數(shù)據(jù)獲取數(shù)據(jù)來(lái)源$fetchHTTP任意異步操作參數(shù)URL optionskey handler適用調(diào)接口組合多數(shù)據(jù)源、非 HTTP 數(shù)據(jù)簡(jiǎn)單記法調(diào)接口用 useFetch其他場(chǎng)景用 useAsyncData。常見(jiàn)錯(cuò)誤不用 useFetch 直接 $fetch!-- ? 這樣不會(huì)做 SSR 預(yù)取還會(huì)在客戶(hù)端重復(fù)請(qǐng)求 -- script setup const data await $fetch(/api/users) /script正確用 useFetch 包一層script setup const { data } await useFetch(/api/users) // SSR 階段預(yù)取客戶(hù)端復(fù)用不重復(fù)請(qǐng)求 /script避免重復(fù)請(qǐng)求給 key多個(gè)組件用同一份數(shù)據(jù)時(shí)給相同的 keyNuxt 會(huì)復(fù)用緩存而不是重復(fù)請(qǐng)求// 組件 Aconst{data}awaituseFetch(/api/config,{key:app-config})// 組件 Bconst{data}awaituseFetch(/api/config,{key:app-config})// 只請(qǐng)求一次第二個(gè)復(fù)用第一個(gè)的結(jié)果五、狀態(tài)管理最佳實(shí)踐SSR 下 Pinia 狀態(tài)共享SSR 模式下每次請(qǐng)求是獨(dú)立的不能在模塊頂層創(chuàng)建全局單例否則狀態(tài)會(huì)串到其他用戶(hù)。錯(cuò)誤寫(xiě)法// ? 模塊頂層創(chuàng)建單例多用戶(hù)共享會(huì)串?dāng)?shù)據(jù)conststorecreatePinia()正確在setup里調(diào)用useXxxStore()Nuxt 會(huì)保證每次請(qǐng)求獨(dú)立。跨請(qǐng)求狀態(tài)用 useStateNuxt 內(nèi)置useState專(zhuān)門(mén)處理 SSR 下的共享狀態(tài)自動(dòng)處理服務(wù)端到客戶(hù)端的序列化// composables/useCart.tsexportconstuseCart(){returnuseState(cart,()({items:[],total:0,}))}不要用普通的全局變量存狀態(tài)——SSR 下會(huì)串用戶(hù)數(shù)據(jù)。六、SEO 優(yōu)化進(jìn)階基礎(chǔ)設(shè)置script setup useSeoMeta({ title: 商品詳情, ogTitle: 商品詳情, description: 商品描述, ogDescription: 商品描述, }) /script動(dòng)態(tài) SEO數(shù)據(jù)驅(qū)動(dòng)的 SEO等數(shù)據(jù)回來(lái)再設(shè)置script setup const { data: product } await useFetch(/api/products/${route.params.id}) useSeoMeta({ title: () ${product.value?.name} - 我的商城, description: () product.value?.description, }) /script站點(diǎn)全局默認(rèn)值// nuxt.config.tsexportdefaultdefineNuxtConfig({app:{head:{titleTemplate:%s - 我的商城,meta:[{name:viewport,content:widthdevice-width, initial-scale1},{name:description,content:我的商城默認(rèn)描述},],}}})sitemap 和 robotsnpx nuxi moduleinstallsitemap// nuxt.config.tsexportdefaultdefineNuxtConfig({modules:[nuxtjs/sitemap],site:{url:https://example.com,},sitemap:{sources:[/api/__sitemap__/urls],}})自動(dòng)生成/sitemap.xml和/robots.txt。七、圖片優(yōu)化安裝 NuxtImagenpx nuxi moduleinstallimage使用template NuxtImg src/images/product.jpg width400 height300 formatwebp loadinglazy alt商品圖 / /template效果自動(dòng)生成多種尺寸的響應(yīng)式圖片自動(dòng)轉(zhuǎn) WebP 格式體積小 30%-50%懶加載默認(rèn)開(kāi)啟生成 srcset 適配不同屏幕八、性能優(yōu)化路由級(jí)緩存routeRules// nuxt.config.tsexportdefaultdefineNuxtConfig({routeRules:{/:{prerender:true},// 構(gòu)建時(shí)預(yù)渲染/blog/**:{swr:3600},// 1小時(shí)增量緩存/api/heavy/**:{swr:600},// 重計(jì)算接口緩存 10 分鐘/admin/**:{ssr:false},// 后臺(tái)不走 SSR}})prerender構(gòu)建時(shí)生成靜態(tài) HTML運(yùn)行時(shí)零開(kāi)銷(xiāo)swrstale-while-revalidate返回緩存的同時(shí)后臺(tái)刷新兼顧速度和新鮮度ssr: false不走服務(wù)端渲染省服務(wù)器資源組件懶加載不立即需要的組件用懶加載script setup // 只在需要時(shí)才加載編輯器組件 const Editor defineAsyncComponent(() import(~/components/Editor.vue)) /script template ClientOnly Editor v-ifshowEditor / /ClientOnly /template數(shù)據(jù)預(yù)取script setup definePageMeta({ // 進(jìn)入這個(gè)頁(yè)面時(shí)預(yù)取 /api/users不用等組件加載 async middleware() { await useFetch(/api/users) } }) /script九、部署注意事項(xiàng)Node 部署環(huán)境變量構(gòu)建后的產(chǎn)物需要運(yùn)行時(shí)讀取環(huán)境變量。構(gòu)建時(shí)寫(xiě)死的值不會(huì)生效要用運(yùn)行時(shí)配置// nuxt.config.tsexportdefaultdefineNuxtConfig({runtimeConfig:{public:{apiBase:process.env.NUXT_PUBLIC_API_BASE||http://localhost:3000}}})啟動(dòng)時(shí)傳入NUXT_PUBLIC_API_BASEhttps://prod-api.example.comnode.output/server/index.mjs靜態(tài)站點(diǎn)部署注意SSG 模式下動(dòng)態(tài)路由的頁(yè)面要告訴 Nuxt 去預(yù)渲染哪些// nuxt.config.tsexportdefaultdefineNuxtConfig({nitro:{prerender:{crawlLinks:true,// 自動(dòng)爬取頁(yè)面里的鏈接routes:[/sitemap.xml],}}})或者用routeRules指定routeRules:{/blog/**:{prerender:true}}反向代理配置用 Nginx 反代 Nuxt 應(yīng)用server { listen 80; server_name example.com; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }十、常見(jiàn)報(bào)錯(cuò)排查1.window is not defined原因SSR 階段用了瀏覽器 API。解決用process.client判斷或放onMounted里。2.Hydration text mismatch原因服務(wù)端和客戶(hù)端渲染內(nèi)容不一致時(shí)間、隨機(jī)數(shù)、依賴(lài)客戶(hù)端狀態(tài)的數(shù)據(jù)。解決把不確定內(nèi)容放onMounted或用ClientOnly包裹。3.useFetch 重復(fù)請(qǐng)求原因沒(méi)有 SSR 預(yù)取或 key 重復(fù)。解決確保useFetch在setup頂層 await 調(diào)用不要包在函數(shù)里。4. 第三方庫(kù)報(bào)Cannot read properties of undefined原因庫(kù)依賴(lài)瀏覽器環(huán)境。解決用ClientOnly包裹或配vite.ssr.noExternal。5. 部署后 502 / 端口不對(duì)原因Nitro 默認(rèn) 3000 端口被占用或沒(méi)配對(duì)。解決PORT8080 node .output/server/index.mjs指定端口。6. 靜態(tài)生成后動(dòng)態(tài)路由 404原因SSG 模式下動(dòng)態(tài)路由沒(méi)有被預(yù)渲染。解決配置nitro.prerender.crawlLinks或手動(dòng)指定 routes。十一、結(jié)語(yǔ)三篇文章走完了 Nuxt 的完整認(rèn)知鏈路是什么Vue 之上的全棧框架解決 SSR、SEO、路由工程化、前后端一體怎么用約定式路由、自動(dòng)導(dǎo)入、useFetch、Pinia、server/api、部署踩什么坑SSR 兼容性、hydration、第三方庫(kù)、性能、部署核心心法一條凡是涉及瀏覽器 API 的代碼先想服務(wù)端階段會(huì)不會(huì)執(zhí)行到這里。這一條想通了Nuxt 大半的坑都不會(huì)踩。本系列共三篇第一篇Vue 開(kāi)發(fā)者為什么要關(guān)注 Nuxt第二篇從零搭建一個(gè) Nuxt 項(xiàng)目第三篇遷移踩坑與最佳實(shí)踐本文

相關(guān)新聞

豆瓣電影信息API參數(shù)詳解:從請(qǐng)求到響應(yīng)字段的完整指南

豆瓣電影信息API參數(shù)詳解:從請(qǐng)求到響應(yīng)字段的完整指南

適用場(chǎng)景 豆瓣電影信息 API 為開(kāi)發(fā)者提供通過(guò)豆瓣電影 ID 或完整 URL 獲取電影詳情的接口。常見(jiàn)使用場(chǎng)景包括: 個(gè)人電影收藏/評(píng)分網(wǎng)站,需要展示影片的評(píng)分、導(dǎo)演、演員等基礎(chǔ)信息。電影推薦系統(tǒng),根據(jù)用戶(hù)喜好獲取電影元數(shù)據(jù)用于內(nèi)容過(guò)濾。自…

2026/8/2 12:36:21 閱讀更多
C++實(shí)現(xiàn)高斯混合模型:從概率原理到高性能代碼實(shí)戰(zhàn)

C++實(shí)現(xiàn)高斯混合模型:從概率原理到高性能代碼實(shí)戰(zhàn)

1. 項(xiàng)目概述:從聚類(lèi)難題到概率模型的跨越在數(shù)據(jù)處理和機(jī)器學(xué)習(xí)的日常工作中,我們常常會(huì)遇到這樣的場(chǎng)景:給你一堆看起來(lái)混在一起的數(shù)據(jù)點(diǎn),比如不同品種鳶尾花的花瓣尺寸、用戶(hù)行為日志的混合模式,或者圖像中顏色相近但屬…

2026/8/2 12:36:21 閱讀更多
AI客戶(hù)畫(huà)像構(gòu)建最后窗口期:2025年前未完成實(shí)時(shí)畫(huà)像升級(jí)的企業(yè)將喪失30%以上LTV——附遷移路線圖與風(fēng)險(xiǎn)預(yù)警清單

AI客戶(hù)畫(huà)像構(gòu)建最后窗口期:2025年前未完成實(shí)時(shí)畫(huà)像升級(jí)的企業(yè)將喪失30%以上LTV——附遷移路線圖與風(fēng)險(xiǎn)預(yù)警清單

更多請(qǐng)點(diǎn)擊: https://intelliparadigm.com 第一章:AI客戶(hù)畫(huà)像構(gòu)建 AI客戶(hù)畫(huà)像構(gòu)建是現(xiàn)代智能營(yíng)銷(xiāo)與個(gè)性化服務(wù)的核心基礎(chǔ),它通過(guò)融合多源異構(gòu)數(shù)據(jù)(如交易記錄、行為日志、社交媒體互動(dòng)、客服對(duì)話等),利用機(jī)…

2026/8/2 12:46:09 閱讀更多
網(wǎng)盤(pán)直鏈下載助手:徹底告別下載限制的終極解決方案

網(wǎng)盤(pán)直鏈下載助手:徹底告別下載限制的終極解決方案

網(wǎng)盤(pán)直鏈下載助手:徹底告別下載限制的終極解決方案 【免費(fèi)下載鏈接】Online-disk-direct-link-download-assistant 一個(gè)基于 JavaScript 的網(wǎng)盤(pán)文件下載地址獲取工具。基于【網(wǎng)盤(pán)直鏈下載助手】修改 ,支持 百度網(wǎng)盤(pán) / 阿里云盤(pán) / 中國(guó)移動(dòng)云盤(pán) / 天翼云盤(pán)…

2026/8/2 12:46:09 閱讀更多
【AI交叉銷(xiāo)售推薦實(shí)戰(zhàn)指南】:20年零售AI專(zhuān)家親授5大高轉(zhuǎn)化模型架構(gòu)與落地避坑清單

【AI交叉銷(xiāo)售推薦實(shí)戰(zhàn)指南】:20年零售AI專(zhuān)家親授5大高轉(zhuǎn)化模型架構(gòu)與落地避坑清單

更多請(qǐng)點(diǎn)擊: https://intelliparadigm.com 第一章:AI交叉銷(xiāo)售推薦的核心價(jià)值與業(yè)務(wù)本質(zhì) AI交叉銷(xiāo)售推薦并非簡(jiǎn)單的“商品關(guān)聯(lián)彈窗”,而是企業(yè)以數(shù)據(jù)為紐帶重構(gòu)客戶(hù)旅程、釋放存量?jī)r(jià)值的戰(zhàn)略支點(diǎn)。其業(yè)務(wù)本質(zhì)在于將離散的用戶(hù)行為、商品屬性與…

2026/8/2 12:46:09 閱讀更多
算法偏差導(dǎo)致客單價(jià)下降22%?AI交叉銷(xiāo)售推薦的5個(gè)致命盲區(qū),資深架構(gòu)師緊急預(yù)警

算法偏差導(dǎo)致客單價(jià)下降22%?AI交叉銷(xiāo)售推薦的5個(gè)致命盲區(qū),資深架構(gòu)師緊急預(yù)警

更多請(qǐng)點(diǎn)擊: https://intelliparadigm.com 第一章:算法偏差導(dǎo)致客單價(jià)下降22%?AI交叉銷(xiāo)售推薦的5個(gè)致命盲區(qū),資深架構(gòu)師緊急預(yù)警 某頭部電商平臺(tái)在上線新一代圖神經(jīng)網(wǎng)絡(luò)(GNN)驅(qū)動(dòng)的交叉銷(xiāo)售引擎后&#xf…

2026/8/2 12:46:09 閱讀更多
Unity游戲開(kāi)發(fā)中MVC框架的實(shí)踐指南:從理論到代碼實(shí)現(xiàn)

Unity游戲開(kāi)發(fā)中MVC框架的實(shí)踐指南:從理論到代碼實(shí)現(xiàn)

1. 項(xiàng)目概述:為什么Unity開(kāi)發(fā)者需要關(guān)注MVC? 如果你在Unity社區(qū)里混跡過(guò)一段時(shí)間,或者面試過(guò)一些Unity相關(guān)的崗位,大概率會(huì)聽(tīng)到過(guò)“MVC框架”這個(gè)詞。它就像一個(gè)傳說(shuō)中的武林秘籍,人人都說(shuō)好,但真正能把它在…

2026/8/2 12:25:40 閱讀更多
MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案

MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案

MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案 【免費(fèi)下載鏈接】MoneyPrinterPlus AI一鍵批量生成各類(lèi)短視頻,自動(dòng)批量混剪短視頻,自動(dòng)把視頻發(fā)布到抖音,快手,小紅書(shū),視頻號(hào)上,賺錢(qián)從來(lái)沒(méi)有這么容易過(guò)! 支持本地語(yǔ)音模型chatTTS,fasterwhisper,…

2026/8/2 0:04:00 閱讀更多
3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南

3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南

3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南 【免費(fèi)下載鏈接】GetQzonehistory 獲取QQ空間發(fā)布的歷史說(shuō)說(shuō) 項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想過(guò),那些年發(fā)過(guò)的QQ空間說(shuō)說(shuō),那些記錄青春的文字…

2026/8/2 0:04:01 閱讀更多
MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案

MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案

MoneyPrinterPlus實(shí)戰(zhàn)指南:AI視頻批量生成與自動(dòng)化發(fā)布完整解決方案 【免費(fèi)下載鏈接】MoneyPrinterPlus AI一鍵批量生成各類(lèi)短視頻,自動(dòng)批量混剪短視頻,自動(dòng)把視頻發(fā)布到抖音,快手,小紅書(shū),視頻號(hào)上,賺錢(qián)從來(lái)沒(méi)有這么容易過(guò)! 支持本地語(yǔ)音模型chatTTS,fasterwhisper,…

2026/8/2 0:04:00 閱讀更多
3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南

3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南

3分鐘搞定!QQ空間歷史說(shuō)說(shuō)完整備份終極指南 【免費(fèi)下載鏈接】GetQzonehistory 獲取QQ空間發(fā)布的歷史說(shuō)說(shuō) 項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾想過(guò),那些年發(fā)過(guò)的QQ空間說(shuō)說(shuō),那些記錄青春的文字…

2026/8/2 0:04:01 閱讀更多
AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O 分配 PCB

AMAT 0100-02186 I/O分配PCB板是應(yīng)用材料(Applied Materials)公司生產(chǎn)的一款用于半導(dǎo)體設(shè)備的I/O信號(hào)分配電路板。該型號(hào)(0100-02186)的核心特點(diǎn)如下:專(zhuān)用于Endura等半導(dǎo)體工藝腔室。集成信號(hào)路由與分配功能。連接控制…

2026/8/2 2:51:21 閱讀更多
Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)

Nissei Corp FFMN-32L-10-T0 40AX 三相異步電動(dòng)機(jī)是日本日清(Nissei)品牌的一款工業(yè)用三相異步電機(jī),適用于自動(dòng)化設(shè)備及通用機(jī)械驅(qū)動(dòng)。該型號(hào)(FFMN-32L-10-T0 40AX)的核心特點(diǎn)如下:三相交流異步電動(dòng)機(jī)。額定…

2026/8/2 2:52:49 閱讀更多