背景#
在之前就发现过本平台一个颇为微妙的 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 就行 :_)