日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
聊一聊Vue-SSR激活失?。╒uehydrationfails)

認識 Vue-SSR 激活失敗

1. 基本常識

什么是服務(wù)端渲染?

  • 客戶端渲染是在瀏覽器中輸出 Vue 組件,進行生成 DOM 和操作 DOM,并渲染為 HTML 頁面展示;
  • 服務(wù)端渲染是將同一個組件渲染為服務(wù)器端的 HTML 字符串,將它們直接發(fā)送到瀏覽器展示;
  • Vue SSR 則將這些服務(wù)端渲染的靜態(tài) HTML "激活"為客戶端上完全可交互的 HTML 頁面,服務(wù)端與客戶端渲染的 HTML 混合,體現(xiàn)了 Vue SSR 的一大特性--同構(gòu)。

為什么使用 SSR?

  • 首屏渲染速度快;
  • SEO,服務(wù)端渲染的頁面內(nèi)容可以被搜索引擎爬蟲獲取;

什么場景下使用 SSR?

SSR 服務(wù)端渲染的優(yōu)勢主要在于首屏渲染與 SEO,那為什么不直接全面推廣使用呢?主要考慮到存在以下劣勢:

創(chuàng)新互聯(lián)是一家專業(yè)提供南靖企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站制作、成都網(wǎng)站制作、成都h5網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為南靖眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進行中。

  • 代碼復雜度增加 - 為了實現(xiàn)前面提到的同構(gòu),應(yīng)用代碼中需要兼容服務(wù)端和客戶端兩種運行情況,那么原先只支持瀏覽器環(huán)境運行的 API 方法必須增加特殊處理才能在服務(wù)端渲染程序中運行;
  • 涉及構(gòu)建設(shè)置和部署有更多要求 - 完全靜態(tài)單頁面應(yīng)用程序 (SPA) 可以部署在任何靜態(tài)文件服務(wù)器上,而服務(wù)器渲染應(yīng)用程序,需要處于 Node.js server 運行環(huán)境;
  • 更多的服務(wù)器負載 - 在 Node.js 中渲染完整的應(yīng)用程序,

所以是否可以使用服務(wù)端渲染 SSR,需要開發(fā)者考慮投入產(chǎn)出比,如果應(yīng)用系統(tǒng)的大多數(shù)頁面都不需要 SEO,且首屏時間基本可以滿足需求,使用 SSR 就沒有必要了。結(jié)合上面的第 2 點, SSR 的使用場景:

  • 對首屏渲染時間要求高,且盡可能只把首屏內(nèi)容放到服務(wù)端渲染;
  • 對 SEO 要求高的內(nèi)容。

2. 主要痛點問題

服務(wù)端渲染有很多好處,特別是當像 Nuxt.js 或 GridSome 這樣的網(wǎng)站,無論是使用動態(tài) SSR 還是生成靜態(tài)網(wǎng)站,開發(fā) Vue-SSR 應(yīng)用程序都是一件輕而易舉的事。但從另一方面來講,由于同構(gòu)帶來的代碼復雜性與 node 端未知錯誤,降低了系統(tǒng)應(yīng)用的穩(wěn)定性與可靠性,并不推薦在非必要場景下使用 SSR 開發(fā)。盡管在官方指南的指導下,以及在前人踩坑后提供了變通的解決方案,多數(shù)錯誤都可以避開或者解決,但仍有未知錯誤導致的報錯致使我們無從下手。

比如我曾在 SSR 服務(wù)端渲染中遇到了一個 Bug,排查了整整 2 個小時,定位為客戶端渲染失敗,但導致客戶端渲染失敗的原因又有很多。

Error: Error while mounting app: HierarchyRequestError: Failed to execute 'appendChild' on 'Node':
This node type does not support this method. at some-file.js:1

在 SSR 應(yīng)用中不斷踩坑地經(jīng)歷讓我意識到:大多數(shù)時候遇到的棘手錯誤都是 Vue 客戶端激活失敗導致的。

3. 什么是 Vue 客戶端激活失敗(client-side hydration)客戶端激活

官方指南對 Vue 客戶端激活(client-side hydration)定義很清晰:

所謂客戶端激活,指的是 Vue 在瀏覽器端接管由服務(wù)端發(fā)送的靜態(tài) HTML,使其變?yōu)橛?Vue 管理的動態(tài) DOM 的過程。

這里 hydration,又可以翻譯為“注入”,可以了理解為將在客戶端生成的虛擬 DOM 結(jié)構(gòu)注入到服務(wù)端渲染出的 HTML 中使這些靜態(tài)的 HTML 變?yōu)閯討B(tài)的。從上面的構(gòu)建過程圖我們也可以看到,這里的激活發(fā)生在客戶端構(gòu)建完成的包到渲染為 HTML 的過程中。

客戶端激活失敗

服務(wù)端已經(jīng)渲染好了 HTML,無需將其丟棄再重新創(chuàng)建所有的 DOM 元素,而是去激活這些渲染好的靜態(tài) HTML,使他們成為動態(tài)的以能夠響應(yīng)后續(xù)的數(shù)據(jù)變化。但如果 Vue 客戶端生成的虛擬 DOM 樹與服務(wù)端渲染的 DOM 結(jié)構(gòu)無法匹配,就會發(fā)生客戶端激活失敗。

這里又分為開發(fā)模式和生產(chǎn)模式兩種情況:

在開發(fā)模式下,如果無法匹配,它將退出混合模式,丟棄現(xiàn)有的 DOM 并從頭開始渲染;

在生產(chǎn)模式下,此檢測會被跳過,以避免性能損耗。

這也就能說明為什么有些錯誤僅在生產(chǎn)模式下才會出現(xiàn)。

在排查錯誤問題的過程中,讀到(谷歌)了一篇關(guān)于 SSR 服務(wù)中客戶端激活失敗梳理較為細致的文章,列舉出了大多數(shù)可能出現(xiàn)的原因以及解決方案。

原文地址 - What to do when Vue hydration fails

二、正文 - What to do when Vue hydration fails

1. 什么是 Vue 激活失敗

第一次聽到"hydration"這個詞時,它對我來說非常抽象,我想不出它的意思。最終,我意識到它并不像一開始聽起來那么復雜:

hydration 是 Vue 轉(zhuǎn)換服務(wù)器端渲染的標記并使其具有動態(tài)反應(yīng)性的過程,因此它可以反映來自 Vue 的動態(tài)更改。

如果 Vue 期望與服務(wù)端渲染的 HTML 不同的標記,則 hydration 將失敗(也稱為“Vue 將 hydration 丟棄”)。你可以在官方的 Vue SSR 文檔中閱讀更多相關(guān)內(nèi)容。

2. 如何識別激活失敗

我們現(xiàn)在已經(jīng)意識到激活是什么和在什么時候會失敗,但是我們作為開發(fā)者要如何發(fā)現(xiàn)激活沒有如預期一般工作呢?

有兩條錯誤消息肯定會指出激活失敗但都有限制條件。

1)第一條是僅在開發(fā)環(huán)境中出現(xiàn):Parent:

Parent:  
client-hook-3.js:1:16358
Mismatching childNodes vs. VNodes: NodeList(3) [ p, p, p ] Array [ {…} ]

[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content.
This is likely caused by incorrect HTML markup, for example nesting block-level elements inside

, or missing .
Bailing hydration and performing full client-side render.

2)第二條錯誤消息是僅在生產(chǎn)環(huán)境下使用靜態(tài)生成站點時:

Error: Error while mounting app: HierarchyRequestError: Failed to execute 'appendChild' on 'Node':
This node type does not support this method. at some-file.js:1

眾所周知,激活僅在頁面首先由服務(wù)端渲染時發(fā)生,因此通常僅在你應(yīng)用的初始化請求中。

當通過一個標簽導航時激活失敗是不可見的,僅能在硬重載時才能復現(xiàn),這就使得在開發(fā)環(huán)境下發(fā)現(xiàn)激活失敗問題變得更加困難。

因此激活錯誤有時僅在階段系統(tǒng)或者更糟,僅在生產(chǎn)環(huán)境下被發(fā)現(xiàn)。在極少數(shù)情況下,甚至不會打印出錯誤而僅僅時某些組件停止工作。

3. 一般引發(fā)錯誤的原因

現(xiàn)在我們了解了如何發(fā)現(xiàn)激活錯誤,接下來將研究導致 Vue 激活錯誤的典型原因。當然這里不可能覆蓋所有可能的原因,因為這些錯誤原因差別很大,而且主要取決于代碼。

在以下章節(jié)中,每次提到服務(wù)端渲染,它就與兩種情況都相關(guān)(動態(tài) SSR 和靜態(tài)站點生成),因為從技術(shù)上講,兩者都具有服務(wù)端渲染內(nèi)容(除非另有說明)。

1)不合理的 HTML當激活失敗發(fā)生時,首先要檢查的應(yīng)該是 HTML 是否合理,官方指南有這類踩坑提示,同時一般會有錯誤信息提示:

This is likely caused by incorrect HTML markup, for example nesting block-level elements inside 

, or missing

不幸的是,不合理的 HTML 通常不是激活失敗的原因。不過,你還是應(yīng)該仔細檢查你的標記。

另外,你還要確保檢查縮小設(shè)置,因為過度的 HTML 縮小可能會導致無效的 HTML。

如果你有用戶生成的輸出或來自 CMS 的內(nèi)容,需要驗證此內(nèi)容也是有效的 HTML。

最后,第三方插件或服務(wù)也可能影響和操縱 HTML。后者的一個常見示例是 Cloudflare,當你啟用了它們的服務(wù) -- 如 HTML 縮小,Rocket loader 或其他更改頁面內(nèi)容的功能時。

這里有一個簡單的示例 codeandbox,其中包含無效的 HTML 并觸發(fā)了激活失敗。

2)修改 HTML 的腳本關(guān)于腳本:如果向 Vue 應(yīng)用中插入第三方 JS 文件,也可以在 Vue 接收并激活來自服務(wù)器的 HTML 之前更改 HTML。

3)服務(wù)器和客戶端的狀態(tài)不同服務(wù)器和客戶端上狀態(tài)不一致是發(fā)生激活失敗最常見的原因。像往常一樣,不一致的原因千差萬別。

日期、時間戳和隨機化

當網(wǎng)站包含日期或者時間戳時,應(yīng)盡可能小心并使其盡可能靜態(tài),尤其在網(wǎng)站是靜態(tài)生成的情況下。如果客戶端評估像 new Date() 這樣的表達式,則該表達式可能會與在服務(wù)器上開發(fā)階段檢索相同日期時生成的日期不同。這也讓我對公司的“關(guān)于”頁面感到困惑,在該頁面上,我想根據(jù)當前分鐘對顯示的人員進行排序。

export const deterministicRotate = (arr) => {
if (arr.length <= 1) {
return arr
}
const rotations = (new Date()).getMinutes() % arr.length

return rotations ? arr : arr.reverse()
}

如果用戶打開頁面的時間很奇怪,則計劃將陣列反轉(zhuǎn)。當使用動態(tài) SSR 時效果很好。但當切換到靜態(tài)生成的 JAMstack 站點時,該功能就會成為一個 Bug。你可以在一分鐘后點擊鏈接刷新,會發(fā)現(xiàn)名字和人正確的交換了,但圖片和原來一致。糟糕!這是由于服務(wù)器和客戶端時間不匹配導致的。在移除不確定性代碼后工作恢復正常。

  • 授權(quán)

不一致的另一個常見原因是用戶身份驗證。這適用于動態(tài) SSR 和靜態(tài)站點生成。當僅在客戶端(例如,在 localStorage 中)上存儲身份驗證狀態(tài)時,服務(wù)器“不知道身份驗證”。這將不可避免地導致激活問題,因為登錄時服務(wù)器和客戶端信息根本不同。因此,如果服務(wù)器不知道正在靜態(tài)生成頁面的身份驗證狀態(tài)**,**則不應(yīng)在服務(wù)器端呈現(xiàn)任何與身份驗證相關(guān)的組件。你可能想知道為什么它總是適用于靜態(tài)網(wǎng)站:因為當生成網(wǎng)站時,它是 HTML,而序列化的代碼是“無狀態(tài)的”。在構(gòu)建階段,我們無法考慮“已登錄的用戶狀態(tài)”。這意味著必須從服務(wù)器上的渲染中排除所有與身份驗證相關(guān)的組件。

  • 其他原因

除了這兩種情況外,還有更多邊緣情況可能會打擊你并引起不一致。即使未在此處列出,我們也將解決激活錯誤!首先,我們應(yīng)該將其范圍縮小到導致問題的 DOM 元素。

4. 解決激活失敗問題

1)發(fā)現(xiàn)導致激活失敗的元素我們可以使用您最喜愛的瀏覽器上的 devTools 縮小問題到一個特定的組件或者 DOM 元素。

  • 確保你在開發(fā)環(huán)境下
  • 打開開發(fā)調(diào)試工具
  • 觸發(fā)激活警告(通常通過重載網(wǎng)頁)
  • 展開[Vue Warn] The client side ...錯誤消息查看追蹤堆棧(取決于瀏覽器,也打開彈出的 VueJS 列表)
  • 點擊一個激活回調(diào),將會打開 Vue 激活函數(shù)的源代碼
  • 現(xiàn)在,無論何時這個函數(shù)返回 false 都設(shè)置一個 debugger,在撰寫文本時,這種情況發(fā)生了三遍:
if (process.env.NODE_ENV !== 'production') {
if (!assertNodeMatch(elm, vnode, inVPre)) {
return false //HERE
}
}
if (process.env.NODE_ENV !== 'production' &&
typeof console !== 'undefined' &&
!hydrationBailed
) {
hydrationBailed = true;
console.warn('Parent: ', elm);
console.warn('server innerHTML: ', i);
console.warn('client innerHTML: ', elm.innerHTML);
}
return false //HERE
}
 if (process.env.NODE_ENV !== 'production' &&
typeof console !== 'undefined' &&
!hydrationBailed
) {
hydrationBailed = true;
console.warn('Parent: ', elm);
console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children);
}
return false //HERE
}

這同樣允許在激活失敗前檢查激活函數(shù)的參數(shù)。

  • 最后但同樣重要的是,讓激活錯誤復現(xiàn),通常再次重載頁面是有可能的但有時更困難
  • 你現(xiàn)在看到觸發(fā)了我們的一個斷點,腳本停止執(zhí)行了
  • 現(xiàn)在打開調(diào)試工具的控制臺,在激活失敗的地方寫一個元素去獲取 DOM 元素。使用 DOM 元素,你將能夠?qū)⒓せ铄e誤追溯到你的 Vue 組件之一
  • 繼續(xù)執(zhí)行下一步 PS:這是用戶 budden73對此 StackOverflow 答案改編后的問題定位順序。

2)確保你的 HTML 標記合理現(xiàn)在你發(fā)現(xiàn)了導致問題的代碼,你首先要做的事確保你的標記(也許來自一個 API)是合理的。像這樣的代碼

Text

無效,因為一個p元素不允許在其中包含其他塊元素(如段落標簽)。但是注意,標記不允許像

這樣的標簽作為子元素,這些標記是 Vue 過渡的默認標記。你可以通過進行改變。因為一個p元素不允許在其中包含其他塊元素(如段落標簽)。但是注意,標記不允許像

3)解決服務(wù)器與客戶端之間的不一致在 debugger 期間,你能夠從服務(wù)器看到結(jié)果和重新繪制客戶端側(cè)。如果存在不同,你可以看一看,你是如何獲取數(shù)據(jù)和你在服務(wù)端或客戶端渲染了什么。一個常見的問題是靜態(tài)網(wǎng)頁的認證,因為 HTML 在構(gòu)建時生成的是無狀態(tài)的,因此不知道任何授權(quán)狀態(tài),你應(yīng)用的所有和授權(quán)有關(guān)的部分都應(yīng)該在客戶端重新渲染。否則,在客戶端有授權(quán)狀態(tài)的用戶,因為登錄而期望從服務(wù)端獲取不同的 HTML。然后只剩下一個方案...

4)最終避免措施:最后一個解決激活錯誤的選擇是完全避免組件出現(xiàn)激活錯誤。這對于在靜態(tài)生成的頁面上與身份驗證相關(guān)的組件來說是必須的,有時對于交付你不能更改但必須嵌入的內(nèi)容的組件(例如,來自第三方應(yīng)用程序)也是必需的。正如我們在一開始了解到的,激活僅發(fā)生在組件被同時渲染在服務(wù)端和客戶端時。為了避免激活失敗,可以通過標簽避免重新渲染服務(wù)端組件。唯一的缺點:該組件不包含在服務(wù)器返回的 HTML 中,對 SEO 沒有幫助。

5. 總結(jié)

這篇文章結(jié)束了!現(xiàn)在你了解了更多關(guān)于 vue 激活失敗的知識:

  • 什么是激活以及它做了什么?
  • 激活怎么失敗的以及如何發(fā)現(xiàn)激活失敗?
  • 激活失敗的一般原因
  • 如何調(diào)試激活失敗及解決你的應(yīng)用程序

我希望這篇文章很有見解,并且你學到了一兩件事。你是否遇到了此處未描述的激活錯誤原因,或者我錯過了一個常見原因?隨時在 Twitter 上或通過郵件給我發(fā)消息。而且像往常一樣 —— 如果您能宣傳并與同事分享博客文章,我將很高興。

三、踩坑小結(jié)

這篇博客講到了大多數(shù)我在服務(wù)端渲染中遇到的客戶端激活失敗報錯問題,甚至也包括了我沒有遇到的問題。當然這篇博客也有不足,比如這是 2020 年的文章,其中一些問題也許有了新的進展,當然可能也有許多如我一般的新手還在踩坑。最后整理一下我在開發(fā)期間學習踩坑所得經(jīng)驗:

1. 同構(gòu)

因為我們采用同構(gòu)的目的是寫一份盡量通用的代碼, 讓它運行在兩端。所以我們需要熟悉不同端的運行環(huán)境, 至少要熟悉相關(guān) API,Node.js 端是沒有瀏覽器對象的, 所以 window, document, DOM 操作都沒法執(zhí)行。同理, 瀏覽器端是沒有 process 對象的,他們各自的 API 實現(xiàn)也有差別, 這點需要特別留意。還有比較麻煩的就是第三方庫的引入, 有時候你并不知道引入的庫能不能完全運行在 Node 端/瀏覽器端,如果它只能運行在純?yōu)g覽器環(huán)境, 那可以在 created 階段之后引入和執(zhí)行來避開 Node.js 下執(zhí)行。

2. 數(shù)據(jù)預取問題

問題:使用 v-html 注入動態(tài)獲取的 HTML 內(nèi)容的時候. 如果 HTML 內(nèi)容有