react-native 0.59.10を使用し、momentJSのロケールを設定すると、リリースビルドのみで非常に残酷なクラッシュが発生しました。 このクラッシュは、デバッガーを接続した状態では再現できませんでした。 このクラッシュは、iOSとAndroidの両方で発生しました。 すべての瞬間の使用法をラップするtry-catchステートメントはクラッシュをキャッチしませんでした!
再現するには
["fr-CA", "en-US", "fr", "en"]
moment.locale(localeCandidate)
呼び出しても、アプリケーションはこの行でクラッシュします⁇これは起動時のクラッシュでしたが、リリースビルドの場合のみです!! これにより、有用なエラーメッセージ/ログを抽出するのが非常に難しくなりました。
Bugsnag統合とシステムコンソールログを介して次のエラーメッセージが表示されました
Exception in HostFunction: Error loading module0from RAM Bundle: unspecified iostream_category error
Exception in HostFunction: Module not found: 0
Requiring unknown module "./locale/en-us".
が表示されましたが、奇妙なことに、このエラーはタイムリーに処理されていませんでした。 おそらくreact-native / bugsnagの問題です。回避策:これらの2行をコメントアウトすると、クラッシュが停止しました。
期待される動作
require()
をいじる場合、react-nativeの問題になる可能性があります)スマートフォン(以下の情報を入力してください):
モーメント固有の環境
ご使用の環境で次のコードを実行し、出力を含めてください。
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"
]
追加のコンテキスト
参照されている行は、実行時にモジュールを「自動的に」要求しようとしていますが、ロケールのimport "moment/locale/fr
ロケールを読み込むことができることが示されています。 インポートする必要があるファイルを「認識」するためにreact-nativeパッケージマネージャーが必要なため、パッケージャーがバンドルする必要のあるすべてのファイルを「認識」できるように、そのスタイルのインポートを試みました。
最終的に、インポート行は次のようになりました。
import moment from "moment";
import "moment/min/locales"; // Import all moment-locales -- it's just 400kb
import "moment-timezone";
require()
の正確な実装は、使用しているランタイムによって注入されます。これは、デバッグビルドとリリースビルドの間で動作が大幅に異なることは間違いありません。
react-nativeには、リリースモードのJavaScriptバンドルには、オールインワンファイル、オールインセパレートファイル、RAMバンドルなど、いくつかの異なるフレーバーがあります。 これらはそれぞれ、requireの動作方法も変更します。 デバッグrequire()
は、ローカルhttpサーバーで実行されているMetroBundlerに接続します。 これはおそらくwebpack / jspm / otherデバッグサーバーと非常に似ているため、エイリアシングrequireがその環境で問題を引き起こさないのはおそらくそのためです。
A. aliasedRequire
完全に削除してください。そうしない場合は、それ以上の操作を行う必要があります。それに加えて、インストール手順を微調整しますか?
B. react-nativeとbrowserを検出し( navigator
はreact-nativeでは使用できませんが、ここには他の手法があります)、どの状況にあるかによって動作が異なりますか? 例えば。 react-native && DEVの場合、ロケールが理論的にサポートされているが、まだrequired
になっていない場合はconsole.errorを出力します(+ドキュメントを更新)。
C. aliasedRequire
をその関数のローカル変数から「セミグローバル」に移動します。 moment.aliasedRequire
、そうすれば、no-op / do-nothing関数を挿入して、 aliasedRequire
がreact-nativeを激しくクラッシュさせないようにすることができます。
メンテナが私に実装してほしいオプションを教えてくれれば、これらのオプションのいずれかを実装できれば幸いです。提案B / Cは、どの実装を受け入れる傾向があるかを正確に改善するのに役立ちます。
@ marwahaha-モーメントのプロセスがわからない。 私の修正提案について意見がありますか? 寄稿者/メンテナがどのルートを受け入れることができるかについてアドバイスをもらったら、PRを実装できれば幸いです。
最も参考になるコメント
参照されている行は、実行時にモジュールを「自動的に」要求しようとしていますが、ロケールの
import "moment/locale/fr
ロケールを読み込むことができることが示されています。 インポートする必要があるファイルを「認識」するためにreact-nativeパッケージマネージャーが必要なため、パッケージャーがバンドルする必要のあるすべてのファイルを「認識」できるように、そのスタイルのインポートを試みました。最終的に、インポート行は次のようになりました。
require()
の正確な実装は、使用しているランタイムによって注入されます。これは、デバッグビルドとリリースビルドの間で動作が大幅に異なることは間違いありません。react-nativeには、リリースモードのJavaScriptバンドルには、オールインワンファイル、オールインセパレートファイル、RAMバンドルなど、いくつかの異なるフレーバーがあります。 これらはそれぞれ、requireの動作方法も変更します。 デバッグ
require()
は、ローカルhttpサーバーで実行されているMetroBundlerに接続します。 これはおそらくwebpack / jspm / otherデバッグサーバーと非常に似ているため、エイリアシングrequireがその環境で問題を引き起こさないのはおそらくそのためです。