Moment: React-Native 发布版本,更改语言环境时深度崩溃

创建于 2019-10-10  ·  4评论  ·  资料来源: moment/moment

当使用 react-native 0.59.10 并为 momentJS 设置语言环境时,我们仅在发布版本中遇到了超级残酷的崩溃。 附加调试器后,我们无法重现此崩溃。 我们在 iOS 和 Android 上都发生了这种崩溃。 包装所有时刻使用的 try-catch 语句没有捕获崩溃!

重现

  1. 我们通过特定于应用程序的逻辑收集我们想要尝试的语言环境/语言。 例如["fr-CA", "en-US", "fr", "en"]
  2. 我们循环遍历这些,一次一个,而不是使用 Array setter,以便我们可以调用其他一些工具,并可能捕获任何抛出的 JS 异常并尝试下一个候选者。
  3. 尽管在 try-catch 块中调用了moment.locale(localeCandidate) ,应用程序仍然在这一行崩溃⁇

这是一个启动时崩溃,但仅适用于发布版本! 这使得提取有用的错误消息/日志变得非常棘手。

我们通过 Bugsnag 集成和系统控制台日志记录看到以下错误消息

  • iOS: Exception in HostFunction: Error loading module0from RAM Bundle: unspecified iostream_category error
  • 安卓: Exception in HostFunction: Module not found: 0
  • 一天后,在 iOS 和 Android 上,我们也看到了Requiring unknown module "./locale/en-us". ——但奇怪的是,这个错误没有得到及时处理。 可能是 react-native / bugsnag 问题。
  1. 最终追踪发现了一个导致崩溃的点:
    https://github.com/moment/moment/blob/96d0d6791ab495859d09a868803d31a55c917de1/moment.js#L1852 -L1853
    我相信来自这里: https :

解决方法:注释掉这两行可以阻止崩溃!

预期行为

  • Moment 永远不应该表现得崩溃,尤其是在仅发布版本中!
  • Moment 的异常应该是可捕获的(我们的 catch 语句可以防止崩溃)。 -- (在 Release 中弄乱require()时可能是一个 react-native 问题)

智能手机(请填写以下信息):

  • 设备:iPhone X、iPhone 11 Pro、三星(?——没有准确捕捉到什么)、谷歌 Pixel 3(react-native 0.59.10)
  • 操作系统:iOS和安卓
  • iOS JavaScript Core(适用于下面提到的 iOS 版本)和 jsc-android(+intl) 245459.0.0
  • 版本:iOS 12.4 和 iOS 13.1、iOS 13.1.2 和 iOS 13.2(测试版?)、Android 28 等。

特定时刻的环境

  • 太平洋时间,可能是伦敦时间
  • 过去 2 周(2019-10-09)在一天中的所有时间都出现代码错误。
  • 正在使用的其他库:moment-timezone 和 moment-with-locales、TypeScript、react-native 0.59.10、Apollo-Client 等

请在您的环境中运行以下代码并包含输出:

        console.log([
            new Date().toString(),
            new Date().toLocaleString(),
            new Date().getTimezoneOffset(),
            navigator && navigator.userAgent, // react-native might not have a navigator
            moment.version,
        ]);

输出:

[
  "Wed Oct 09 2019 18:52:16 GMT-0700 (PDT)",
  "09/10/2019 à 18:52:16", // This particular device is configured as fr-FR
  420,
  null,
  "2.24.0"
]

附加上下文

相关票证

  • #5214 - 不同,因为这里的上下文较少,并且使用不同的 API 并获得不同的错误消息。 类似,因为它只发生在发布版本中,这也暗示了 react-native,但他们只在 ios-simulator/ios 上重现了它。
  • #3872
  • #2979

最有用的评论

引用的行是“自动”尝试在运行时要求模块,但加载语言环境文档表明,如果您使用像 JSPM 这样的包管理器,则可以通过import "moment/locale/fr加载语言环境。 由于我们需要 react-native 包管理器“知道”必须导入文件,因此我们尝试了这种导入方式,以便 Packager 可以“看到”所有必须捆绑的文件。

最终,我们的导入行看起来像这样:

import moment from "moment";
import "moment/min/locales"; // Import all moment-locales -- it's just 400kb
import "moment-timezone";

require()的确切实现是由您正在使用的运行时注入的,这绝对是在 Debug 和 Release 构建之间的行为明显不同的东西。

在 react-native 中,还有几种不同风格的发布模式 JavaScript 捆绑包,包括多合一文件、多合一文件和 RAM 捆绑包。 这些中的每一个也改变了 require 的工作方式。 Debug require()连接到在本地 http 服务器上运行的Metro Bundler 。 这可能与 webpack/jspm/other 调试服务器非常相似,这可能是别名 require 在该环境中不会导致问题的原因。

所有4条评论

引用的行是“自动”尝试在运行时要求模块,但加载语言环境文档表明,如果您使用像 JSPM 这样的包管理器,则可以通过import "moment/locale/fr加载语言环境。 由于我们需要 react-native 包管理器“知道”必须导入文件,因此我们尝试了这种导入方式,以便 Packager 可以“看到”所有必须捆绑的文件。

最终,我们的导入行看起来像这样:

import moment from "moment";
import "moment/min/locales"; // Import all moment-locales -- it's just 400kb
import "moment-timezone";

require()的确切实现是由您正在使用的运行时注入的,这绝对是在 Debug 和 Release 构建之间的行为明显不同的东西。

在 react-native 中,还有几种不同风格的发布模式 JavaScript 捆绑包,包括多合一文件、多合一文件和 RAM 捆绑包。 这些中的每一个也改变了 require 的工作方式。 Debug require()连接到在本地 http 服务器上运行的Metro Bundler 。 这可能与 webpack/jspm/other 调试服务器非常相似,这可能是别名 require 在该环境中不会导致问题的原因。

我的修复建议:

A. 完全删除aliasedRequire如果这不是您应该再做的事情 + 调整有关它的安装说明?
B. 检测 react-native 与浏览器( navigator在 react-native 中不可用,但这里还有其他技术),并根据我们所处的情况采取不同的行为? 例如。 如果 react-native && DEV 然后打印一个 console.error 如果理论上支持语言环境,但还没有required (+更新文档)。
C. 将aliasedRequire从该函数中的局部变量移动到“半全局”。 moment.aliasedRequire ,这样我们就可以注入一个 no-op/do-nothing 函数,这样aliasedRequire就不会导致 react-native 崩溃了。

如果维护者可以向我指出他们希望我实施哪个选项,我将很乐意实施这些选项中的任何一个,并且对于提案 B/C 帮助我完善他们倾向于接受的确切实施!

@marwahaha - 不确定 Moment 的流程是什么。 您对我的修复建议有意见吗? 一旦我得到一些关于贡献者/维护者可以接受的路线的建议,我会很乐意实施 PR?

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

chitgoks picture chitgoks  ·  3评论

vbullinger picture vbullinger  ·  3评论

BCup picture BCup  ·  3评论

dbshwang picture dbshwang  ·  3评论

benhathaway picture benhathaway  ·  3评论