Moment: React-Native Release Builds, Deep Crash beim Wechseln von Locales

Erstellt am 10. Okt. 2019  ·  4Kommentare  ·  Quelle: moment/moment

Bei der Verwendung von Reactive-native 0.59.10 und der Einstellung des Gebietsschemas für momentJS haben wir nur bei unseren Release-Builds einen superbrutalen Absturz erlebt. Dieser Absturz war für uns mit angeschlossenem Debugger nicht reproduzierbar. Dieser Absturz trat bei uns sowohl auf iOS als auch auf Android auf. try-catch-Anweisungen, die den gesamten Moment umschließen, haben den Absturz nicht abgefangen!

Reproduzieren

  1. Wir sammeln die Gebietsschemas/Sprachen, die wir ausprobieren möchten, über anwendungsspezifische Logik. ZB ["fr-CA", "en-US", "fr", "en"]
  2. Wir durchlaufen diese einzeln, anstatt den Array-Setter zu verwenden, damit wir eine andere Instrumentierung aufrufen und möglicherweise alle ausgelösten JS-Ausnahmen abfangen und den nächsten Kandidaten ausprobieren können.
  3. Obwohl moment.locale(localeCandidate) innerhalb eines Try-Catch-Blocks aufgerufen wird, stürzt die Anwendung in dieser Zeile immer noch ab⁇

Dies war ein Crash-on-Launch, aber nur für Release-Builds!! Dies machte es sehr schwierig, nützliche Fehlermeldungen / Protokolle zu extrahieren.

Wir haben die folgenden Fehlermeldungen über unsere Bugsnag-Integration und die Systemkonsolenprotokollierung gesehen

  • iOS: Exception in HostFunction: Error loading module0from RAM Bundle: unspecified iostream_category error
  • Android: Exception in HostFunction: Module not found: 0
  • Einen Tag später sahen wir auf iOS & Android auch Requiring unknown module "./locale/en-us". - aber seltsamerweise wurde dieser Fehler nicht rechtzeitig bearbeitet. Möglicherweise ein reaktives natives / bugsnag-Problem.
  1. Bei der Nachverfolgung wurde ein einzelner Punkt gefunden, der den Absturz verursachte:
    https://github.com/moment/moment/blob/96d0d6791ab495859d09a868803d31a55c917de1/moment.js#L1852 -L1853
    Was ich glaube, kommt von hier: https://github.com/moment/moment/blob/6a06e7a0db2c83fb92aa72bbf6bde955d4c75a16/src/lib/locale/locales.js#L55 -L56

Problemumgehung: Das

Erwartetes Verhalten

  • Moment sollte sich niemals abstürzend verhalten, aber schon gar nicht in Release-Builds-only!
  • Die Ausnahmen von Moment sollten abfangbar sein (unsere catch-Anweisungen hätten einen Absturz verhindert). -- (könnte ein reaktives Problem sein, wenn man in Release mit require() herumspielt)

Smartphone (bitte füllen Sie die folgenden Informationen aus):

  • Gerät: iPhone X, iPhone 11 Pro, Samsung (? -- hat nicht genau erfasst, was), Google Pixel 3, (react-native 0.59.10)
  • Betriebssystem: iOS und Android
  • iOS JavaScript Core (für die unten genannten iOS-Versionen) und jsc-android(+intl) 245459.0.0
  • Versionen: iOS 12.4 & iOS 13.1, iOS 13.1.2 und iOS 13.2 (Beta?), Android 28, andere.

Momentspezifische Umgebung

  • Pacific Time und möglicherweise Londoner Zeit
  • Code-Bug wurde in den letzten 2 Wochen (2019-10-09) zu jeder Tageszeit durchgängig angezeigt.
  • Andere verwendete Bibliotheken: moment-timezone und moment-with-locales, TypeScript, React-native 0.59.10, Apollo-Client & andere

Führen Sie den folgenden Code in Ihrer Umgebung aus und fügen Sie die Ausgabe ein:

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

Ausgabe:

[
  "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"
]

Zusätzlicher Kontext

Zugehörige Tickets

  • #5214 - Anders, weil hier weniger Kontext vorhanden ist und eine andere API verwendet wird und eine andere Fehlermeldung angezeigt wird. Ähnlich, weil es nur in Release-Builds passiert, was ebenfalls auf Reaktiv-Native hindeutet, aber es wurde nur auf ios-simulator/ios reproduziert.
  • #3872
  • #2979

Hilfreichster Kommentar

Die Zeilen, auf die verwiesen wird, versuchen "automatisch", Module zur Laufzeit anzufordern, aber die Dokumentation zum import "moment/locale/fr laden können. Da wir den reaktiven Paketmanager brauchen, um zu "wissen", dass die Datei importiert werden muss, haben wir diesen Importstil ausprobiert, damit der Packager alle Dateien "sehen" kann, die eingebunden werden müssen.

Letztendlich sahen unsere Importlinien so aus:

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

Die genaue Implementierung von require() wird von der Laufzeit eingefügt, mit der Sie arbeiten, und das ist definitiv etwas, das sich zwischen Debug- und Release-Builds erheblich unterscheidet.

In React-Native gibt es auch verschiedene Varianten des JavaScript-Bündels im Release-Modus, einschließlich All-in-One-Datei, All-in-Separate-Dateien und RAM-Bundles. Jeder von ihnen ändert auch die Funktionsweise von Require. Debug require() stellt eine Verbindung zum Metro Bundler her , der auf einem lokalen http-Server ausgeführt wird. Dies ist wahrscheinlich den webpack/jspm/other Debug-Servern sehr ähnlich, weshalb das Aliasing require in dieser Umgebung wahrscheinlich keine Probleme verursacht.

Alle 4 Kommentare

Die Zeilen, auf die verwiesen wird, versuchen "automatisch", Module zur Laufzeit anzufordern, aber die Dokumentation zum import "moment/locale/fr laden können. Da wir den reaktiven Paketmanager brauchen, um zu "wissen", dass die Datei importiert werden muss, haben wir diesen Importstil ausprobiert, damit der Packager alle Dateien "sehen" kann, die eingebunden werden müssen.

Letztendlich sahen unsere Importlinien so aus:

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

Die genaue Implementierung von require() wird von der Laufzeit eingefügt, mit der Sie arbeiten, und das ist definitiv etwas, das sich zwischen Debug- und Release-Builds erheblich unterscheidet.

In React-Native gibt es auch verschiedene Varianten des JavaScript-Bündels im Release-Modus, einschließlich All-in-One-Datei, All-in-Separate-Dateien und RAM-Bundles. Jeder von ihnen ändert auch die Funktionsweise von Require. Debug require() stellt eine Verbindung zum Metro Bundler her , der auf einem lokalen http-Server ausgeführt wird. Dies ist wahrscheinlich den webpack/jspm/other Debug-Servern sehr ähnlich, weshalb das Aliasing require in dieser Umgebung wahrscheinlich keine Probleme verursacht.

Meine Fixvorschläge:

A. Löschen Sie aliasedRequire vollständig, wenn Sie dies nicht mehr tun sollen + Installationsanweisungen dafür anpassen?
B. Reaktiv-native vs. Browser erkennen ( navigator ist in Reaktiv-Native nicht verfügbar, aber es gibt hier andere Techniken) und verhalten sich je nachdem, in welcher Situation wir uns befinden, unterschiedlich? z.B. if reaktiv-native && DEV, dann drucke eine console.error, wenn das Gebietsschema theoretisch unterstützt wird, aber noch nicht required (+ Update-Dokumente) war.
C. Verschieben Sie aliasedRequire von einer lokalen Variablen in dieser Funktion in eine "semi-globale". moment.aliasedRequire , auf diese Weise könnten wir eine No-Op/Do-Nothing-Funktion einfügen, damit aliasedRequire nicht mehr dazu führen kann, dass Reactive-native stark abstürzt.

Ich würde mich freuen, jede dieser Optionen zu implementieren, wenn mir ein Betreuer zeigen kann, welche ich implementieren möchte, und für Vorschläge B/C helfen Sie mir, zu verfeinern, welche genaue Implementierung er akzeptieren würde!

@marwahaha – nicht sicher, wie der Prozess für Moment ist. Hätten Sie eine Meinung zu meinen Fixvorschlägen? Ich würde mich freuen, eine PR zu implementieren, sobald ich einen Rat erhalten habe, welcher Weg für Mitwirkende/Betreuer akzeptabel sein könnte?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen