道阻且长

道阻且长

问君西游何时还,畏途巉岩不可攀。
twitter
github

xLog 修補小記 —— 純文字節點引發的應用崩潰

背景#

在之前就發現過本平台一個頗為微妙的 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">
    &copy;{" "}
    <UniLink href="/" className="hover:text-accent">
      {site?.name}
    </UniLink>{" "}
    ·{" "}
    <Trans
      i18nKey="powered by"
      defaults={"Powered by <name/>"}
      components={{
        name: <LogoWithLink />,
      }}
      ns="site"
    />
</div>

大致兩步搞定:

  1. 直接用 <span> 標籤包裹住純文本
  2. 修正 Trans 元件輸出的結構:按照 https://react.i18next.com/latest/trans-component 所言修改對應語言檔案中的字串模板,然後在 components 欄位中添加對應的 span 声明即可。

粗略看了下,沒什麼問題了,當然不排除沒改乾淨的情況,遇到了再說吧。

總結#

沒啥可說的,多用 Google 就行 :_)

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。