facebook / metro

🚇 The JavaScript bundler for React Native
https://metrobundler.dev
MIT License
5.22k stars 626 forks source link

Custom import syntax issues with Haste module map cache #369

Open jwhiddent3 opened 5 years ago

jwhiddent3 commented 5 years ago

Do you want to request a feature or report a bug? Not sure? It could be a feature request and a bug report.

What is the current behavior? We are using a custom import style using a babel plugin to rewrite imports such as '*/Component' to the proper path in a react-native app. When first loading the packager, this is fine. However, if the path of a component changes or a new component is added, the module not found haste error occurs. If the module was moved, it shows the old fully resolved path. Starting packager with --reset-cache solves this, but I'd like a way to either: A. have watchman let haste know it needs to update its cache or B. rn-cli.config.js custom resolver C. Some other option I don't know about but fixes the issue easier than A or B

Because moving a file that's imported by other files doesn't give watchman any indication to mark those files for running through babel again, I can see the difficulty in that approach, although a workaround would be to trigger a full babel transpile whenever watchman detected any file move/addition.

I've tried reading the documentation and implementing a custom resolver, which it says will not be used if Haste can resolve it, but it was calling that function for every single resolution request, not just the custom ones, and I didn't know how to resolve all of those cases. This seems like a bug. However, even in the case of an old absolute path not resolving correctly, Haste would probably think that it could resolve it, and maybe won't pass it down to the custom resolver?

I know that other babel plugins that use custom rewrite imports have this same issue with haste cache and none of them that I've seen have solved it, so what would the recommended approach be? Obviously it's inefficient to run babel on all files/reset metro cache every time, and still pretty difficult to maintain a map of files importing the moved file or to do a search to find that information. I could see potential fixes in allowing a fallback to re-run babel if this occurs, or a custom resolver that provides the new resolution when it fails. Possibly the custom resolver that exists in the rn-cli can already solve my problem, there's just very little documentation and no examples I could find of a working implementation.

Unfortunately the failed resolution occurs before the chrome debugger is ready, so I haven't been able to debug the metro package myself and really find out how best to approach this. I do think it's reasonable that if at one point the babel transpiled import was correct, and now it's not resolving, a one-off re-resolve or re-transpile of that file is a better approach than requiring the entire cache to be reset. I have looked at the code but I can't pinpoint exactly where the cached resolution fails, as the stack comes from native side and the message is in several places across the repo. I will likely start experimenting with a branch of metro to come up with my own fix.

If the current behavior is a bug, please provide the steps to reproduce and a minimal repository on GitHub that we can yarn install and yarn test. No need to reproduce, issue is understood

What is the expected behavior? If a cached path cannot be resolved, a fallback should be available to fix the resolution instead of requiring full cache reset

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system. config includes proprietary code, but isn't relevant to request. node 10.12 yarn 1.10 mac osX 10.13.6

jwhiddent3 commented 5 years ago

As an update, I finally found an example of how to make the custom resolver, and I've set it up so that if the resolution fails through Metro, it will do the correct resolution using the updated component map from the custom plugin. However, when the packager server attempts to load the actual file, it says it can't find the file at the old location, so I'm not sure what to do about this. It no longer requires a --reset-cache though, I can just restart the packager.