Ao usar react-native 0.59.10 e definindo a localidade para momentJS, pegamos uma falha super brutal apenas para nossas compilações de lançamento. Esta falha não foi reproduzível para nós com o depurador anexado. Essa falha ocorreu para nós no iOS e no Android. instruções try-catch envolvendo todo o uso do momento não detectaram a falha!
Reproduzir
["fr-CA", "en-US", "fr", "en"]
moment.locale(localeCandidate)
dentro de um bloco try-catch, o aplicativo ainda trava nessa linha⁇Este foi um crash-on-launch, mas apenas para compilações de lançamento !! Isso tornou super complicado extrair mensagens de erro / logs úteis.
Vimos as seguintes mensagens de erro por meio de nossa integração Bugsnag e registro do console do sistema
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".
- mas, estranhamente, esse erro não estava sendo processado em tempo hábil. Possivelmente um problema react-native / bugsnag.Solução alternativa: comentar essas duas linhas interrompeu a falha!
Comportamentos esperados
require()
na versão)Smartphone (por favor, preencha as seguintes informações):
Ambiente específico do momento
Execute o seguinte código em seu ambiente e inclua a saída:
console.log([
new Date().toString(),
new Date().toLocaleString(),
new Date().getTimezoneOffset(),
navigator && navigator.userAgent, // react-native might not have a navigator
moment.version,
]);
Saída:
[
"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"
]
Contexto adicional
As linhas referenciadas estão "automaticamente" tentando exigir módulos em tempo de execução, mas os documentos de carregamento de localidades indicam que, se você estiver usando um Gerenciador de Pacotes como JSPM, poderá carregar localidades por import "moment/locale/fr
. Como precisamos que o gerenciador de pacotes react-native "saiba" que o arquivo deve ser importado, tentamos esse estilo de importação para que o Packager possa "ver" todos os arquivos que precisam ser empacotados.
Por fim, nossas linhas de importação ficaram assim:
import moment from "moment";
import "moment/min/locales"; // Import all moment-locales -- it's just 400kb
import "moment-timezone";
A implementação exata de require()
é injetada pelo tempo de execução com o qual você está trabalhando, e isso é definitivamente algo que se comporta de maneira significativamente diferente entre as compilações Debug e Release.
No react-native, também existem vários tipos diferentes de JavaScript Bundling de modo de lançamento, incluindo all-in-one-file, all-in-separate-files e RAM Bundles. Cada um deles também altera como o require funciona. Debug require()
conecta-se ao Metro Bundler rodando em um servidor http local. Isso provavelmente é muito semelhante ao webpack/jspm/outros servidores de depuração, e é provavelmente por isso que o alias require não causa problemas nesse ambiente.
A. Excluir o aliasedRequire
inteiramente se não é assim que você deveria fazer as coisas + ajustar as instruções de instalação sobre isso?
B. Detectar react-native vs browser ( navigator
não está disponível em react-native, mas existem outras técnicas aqui) e comportar-se de forma diferente dependendo da situação em que nos encontramos? por exemplo. se react-native && DEV então imprima um console.error se a localidade for teoricamente suportada, mas ainda não foi required
(+ update docs).
C. Mova o aliasedRequire
de uma variável local nessa função para uma "semi-global". moment.aliasedRequire
, dessa forma poderíamos injetar uma função no-op/do-nothing para que aliasedRequire
não pudesse mais fazer com que o react-native travasse com força.
Eu ficaria feliz em implementar qualquer uma dessas opções se um mantenedor puder me indicar qual delas eles gostariam que eu implementasse, e para Propostas B/C me ajudar a refinar qual implementação exata eles estariam inclinados a aceitar!
@marwahaha -- não tenho certeza de qual é o processo para o Moment. Você teria uma opinião sobre minhas propostas de correção? Eu ficaria feliz em implementar um PR assim que receber alguns conselhos sobre qual rota pode ser aceitável para os contribuidores/mantenedores?
Comentários muito úteis
As linhas referenciadas estão "automaticamente" tentando exigir módulos em tempo de execução, mas os documentos de carregamento de localidades indicam que, se você estiver usando um Gerenciador de Pacotes como JSPM, poderá carregar localidades por
import "moment/locale/fr
. Como precisamos que o gerenciador de pacotes react-native "saiba" que o arquivo deve ser importado, tentamos esse estilo de importação para que o Packager possa "ver" todos os arquivos que precisam ser empacotados.Por fim, nossas linhas de importação ficaram assim:
A implementação exata de
require()
é injetada pelo tempo de execução com o qual você está trabalhando, e isso é definitivamente algo que se comporta de maneira significativamente diferente entre as compilações Debug e Release.No react-native, também existem vários tipos diferentes de JavaScript Bundling de modo de lançamento, incluindo all-in-one-file, all-in-separate-files e RAM Bundles. Cada um deles também altera como o require funciona. Debug
require()
conecta-se ao Metro Bundler rodando em um servidor http local. Isso provavelmente é muito semelhante ao webpack/jspm/outros servidores de depuração, e é provavelmente por isso que o alias require não causa problemas nesse ambiente.