道阻且长

道阻且长

问君西游何时还,畏途巉岩不可攀。
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 就行 :_)

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。