flisboac/react-native-monorepo-helper

Broken with lottie-react-native

Closed this issue · 8 comments

I'm submitting a ...

  • bug report
  • feature request
  • question about the decisions made in the repository
  • question about how to use this project

Summary
Hey, we recently moved our project over to a monorepo and used this helper so we can utilise a shared package. Everything seems to work, however, our lottie-react-native animations are no longer being rendered on both Android and iOS. There aren't any error/warning messages and console.logs() indicates everything is working as expected (so presumably the problem lies within the native side of Lottie?)

I do not know what else to try and have been stuck on this for most of the day :(

Any help would be greatly appreciated! If any more information would help, please do ask :)

Other information

What I've tried (without success):

  • full clean of project (deleting node_modules, locks, pods, builds etc);
  • no hoisting entire native app package, i.e.
"workspaces": {
    "nohoist": ["**"]
}
  • no hoisting all specific native packages (including Lottie ones);
  • modified Lottie's dist index.js, to include debug logs, within node_modules; everything seemed to work and the native functions were called with seemingly correct data;
  • checking Pod install and build logs (nothing suspicious emitted).
  • comment out react-native-monorepo-helper code, from rn-cli.config.js (Lottie continued to works).

Hey, @Braden1996 !

I never actually used lottie-react-native. Did a quick read on its documentation, and it appears to be a React Native library with some native portions of code to be linked. I'm assuming you react-native linked it.

Could you reproduce this bug in a small POC repository? If not, I may try and reproduce in a repository of my own, but then I won't be sure that I'm indeed covering your use-case fully. In any case, I'll probably take a quick look either later today or tomorrow night.

By the way, I must admit react-native-monorepo-helper's asset resolution is kind of lacking. I'm not sure how I would implement it, or if it should really be implemented at all as a separate thing. This will be a good opportunity to learn how Haste expects a CustomResolve to resolve non-source-code things. :)

Something really strange is going on. I have some observations to do, but I'm far from reaching a solution.

I made a quick react-native-cli app from the ground up and could reproduce your bug. When using the helper, everything is rendered except for the LottieView. The JSON animation file itself is resolved and loaded correctly. I don't think it's something to do with the native part of things, but I could be wrong.

Currently, I tried the following nohoist configuration:

    "nohoist": [
      "**/react-native",
      "**/lottie-react-native"
    ]

Nohoisting transitive dependencies prevents app rendering entirely (i.e. it becomes completely blank).

I tried to remote-debug the app, but I coudn't see any relevant log entry. I even tried debugging both ways (with and without the helper) in Android Studio, but as I suspected, I didn't see anything of relevance in the logs. Most notoriously, only when using the helper, a warning is shown in the app that appears in Android Studio's log in both cases (i.e. with and without the helper):

W/ReactNativeJS: Accessing view manager configs directly off UIManager via UIManager['LottieAnimationView'] is no longer supported. Use UIManager.getViewManagerConfig('LottieAnimationView') instead.

Relevant issue: lottie-react-native/lottie-react-native#437

I still can't say exactly what Metro's resolution mechanism does in the absence of a custom resolver that the helper's CustomResolver doesn't. Understanding this difference may be the key to finding why this problem is happening.

This line (metro@0.49.2) is where Metro starts to roll out its own resolution when Haste can't find a module. The helper's CustomResolver should do something similar to all of that. Some remarks:

  • It seems Metro's resolver expects the CustomResolver to take extraNodeModules into consideration. Although there's no extraNodeModules to consider (at least when resolving lottie-react-native and react-native-safe-module), the helper totally ignores it;
  • It seems the distinction between an asset and a non-asset file is done solely based on the module's file extension. There's a function used solely to resolve asset files, but I suspect we won't use it;
  • I still don't understand the relevancy/importance of using context.redirectModulePath (implemented here) in the resolution algorithm, though.

I also see that lottie-react-native uses react-native-safe-module to access its internals (native parts) from the exported React component written in JavaScript. Perhaps the problem may be something related to how the helper handles react-native-safe-module in general (e.g. transitive dependency resolution)? I tried nohoisting react-native-safe-module to no avail. Next time I may try to introduce a failure in SafeModule somewhere and see how the app without the helper reacts to that.

Please, feel free to modify the example app (via PR) in any way you may find relevant to your case.

Nevermind @Braden1996 , found why, and the fix is quite simple! I just need to check the platform extensions (e.g. *.android.js) before the pure file type extension (e.g. *.js).

The fix is in branch '#5'. (The example app was also changed to point to it).

Waiting for your reply!

@Braden1996 released v0.2.5 with the fixes for this issue. The fix branch will be deleted soon. Please, check it out when you can, and feel free to comment anything else that may be related. Closing!

If I'm not using monorepo, how can I fix the issue with react-native-safe-module?

Hey, @ananyacleetus !

If I'm not using monorepo, how can I fix the issue with react-native-safe-module?

If I recall correctly, this issue is related to how UIManager is used.

This is an upstream problem unrelated to monorepo usage. As suggested by the warning given by RN, the problem is about how lottie and its upstream dependencies get UIManager-based view configurations.

I remember that when I was dealing with #5, I made some quick and dirty search-and-replaces locally, to use UIManager.getViewManagerConfig('Component') instead of UIManager.Component, and it seemed to work. The problem is that I had to fix not only lottie-react-native, but react-native-safe-module as well. I even made a comment about that in a related issue (although I could just make a PR with fixes instead; my bad, I just didn't have time).

Hey @flisboac so I can't seem to find the right instances to change in NativeSafeComponent.js. What should I be looking for to change?

If I'm not mistaken: line 24, line 77 and line 113. Substitute every occurence of UIManager["Component"] or UIManager.Component by UIManager.getViewManagerConfig("Component").

The namespace verification in line 30 should also be substituted for something using e.g. getViewManagerNames (seems like, in JavaScript, this is a property named UIManager.ViewManagerNames). I mean, instead of nameOrArray in namespace, a check sould be made in terms of UIManager.ViewManagerNames, e.g. UIManager.ViewManagerNames.indexOf(name) >= 0.

But again, I don't know much about UIManager to be really sure. Also, this is not the right place to have this discussion! :D (Perhaps we could move this conversation to here).