背景#
在之前就發現過本平台一個頗為微妙的 bug:
當使用 Chrome 內建的翻譯工具進行全局翻譯時,頁面會出現錯誤,具體提示為
應用程式錯誤:發生了客戶端異常(有關詳細資訊,請參閱瀏覽器控制台)。
不過因為平台本身具有良好的 i18n,加上也並無過於複雜的內容,極少會在相關頁面使用全局翻譯,也就沒有多做關注。直到近日看到其他的小夥伴提起這個問題 https://github.com/Crossbell-Box/xLog/issues/229 ,勾起了好奇心,遂簡單看看具體緣故。
探究#
既然說了參閱控制台,那麼就看看到底說了什麼:
react-dom.production.min.js:189 DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
at e (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:89708)
at e (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:89781)
at e (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:89781)
at uK (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:89833)
at uq (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86503)
at uQ (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86382)
at uq (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86495)
at uQ (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86382)
at uq (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86692)
at uQ (https://xlog.xlog.app/_next/static/chunks/framework-9e494f4410668bc3.js:9:86382)
粗略掃一眼,嗯,看不出來。再看看,猜測應該是 React 內部爆出的錯誤。那麼直接操起 Google,很輕易地就搜到了原因以及解決方案:https://github.com/facebook/react/issues/11538#issuecomment-390386520
問題在於 Google Translate 用包含翻譯的
<font>
標籤替換文字節點,而 React 保留了不在 DOM 樹中的文字節點的引用。
而解決方案也堪稱簡單粗暴:
最簡單的解決方法是使用
<span>
將那些文字節點包裝起來,這樣被 React 引用的節點即使其內容被替換為<font>
標籤,也會保留在 DOM 樹中。
解決#
有了原因和解決方案,那麼只需要找到出錯的地方修復即可。
xLog 的程式碼也不算少,直接去找也算是個大工程,所以為了定位,幹脆用了個很粗暴的方案,使用二分法逐步在控制台刪除元素。
運氣頗好地,沒用幾下就找到了引起問題的地方:src/components/site/SiteFooter.tsx
<div className="max-w-screen-md mx-auto px-5 py-10 text-xs flex justify-between">
<div className="font-medium text-base">
©{" "}
<UniLink href="/" className="hover:text-accent">
{site?.name}
</UniLink>{" "}
·{" "}
<Trans
i18nKey="powered by"
defaults={"Powered by <name/>"}
components={{
name: <LogoWithLink />,
}}
ns="site"
/>
</div>
大致兩步搞定:
- 直接用
<span>
標籤包裹住純文字 - 修正
Trans
元件輸出的結構:按照 https://react.i18next.com/latest/trans-component 所言修改對應語言檔案中的字串模板,然後在components
欄位中添加對應的span
宣告即可。
粗略看了下,沒什麼問題了,當然不排除沒改乾淨的情況,遇到了再說吧。
總結#
沒啥可說的,多用 Google 就行 :_)