facebook / metro

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

React Native application does not update on many code changes when using vim #1211

Open antun opened 8 months ago

antun commented 8 months ago

Do you want to request a feature or report a bug? bug

What is the current behavior? Newly-created React Native app doesn't reflect every code change during development when using Metro. The behavior is intermittent. Some code changes will be reflected in the app, then some won't be after saving the file. None of the following work to "force" an update:

It looks minor, but it's really disruptive to development, since when I'm debugging, I can't tell which version of the app is currently being displayed. The only "workaround" I have is to add unique console.log() statements until one of them appears in the terminal that matches what I last wrote.

Usually the first code change is reflected after starting Metro. After that it's totally it or miss. I might get two or three successful updates in a row, and then none for a while.

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.

  1. Create a new React Native+metro application by running npx react-native@latest init react_native_update_test
  2. Run in Android with npx react-native run-android. (Although I see the same behavior with iOS.)
  3. Open App.tsx in editor, and make a change (e.g. to some text.) Save the file.
  4. Make more changes, line by line. Change the styles. Try changing the same padding value multiple times - saving each time.

In the attached video, you can see:

https://github.com/facebook/metro/assets/2186326/55843bea-b6ef-410d-a6b4-0d8efa7cce67

What is the expected behavior? I presume that the app should update on every code change.

Please provide your exact Metro configuration and mention your Metro, node, yarn/npm version and operating system. Node v18.19.0 watchman 2023.12.04.00 Mac OS 14.2.1 (23C71) metro@0.80.5

The metro config is the standard one for a new React Native app:

const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

/**
 * Metro configuration
 * https://facebook.github.io/metro/docs/configuration
 *
 * @type {import('metro-config').MetroConfig}
 */
const config = {};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
robhogan commented 8 months ago

Hi @antun - thanks for reporting. Something’s clearly wrong there but it’s hard to tell exactly where, since there are a few steps between a file event being detected and the app rendering updated modules (not all of them in Metro).

Just to clarify, when you hit r you see the client reload (the reloading indicator appears briefly and the state resets?), but the content doesn’t reflect your changes?

Could you possibly run a similar video starting Metro with DEBUG=Metro:* (eg DEBUG=Metro:* yarn start)? That should tell us more about whether file events are reaching Metro from Watchman, and whether the app is requesting updates.

antun commented 8 months ago

Hi @robhogan , thanks for reviewing this so quickly!

Here's an updated video in debug mode:

https://github.com/facebook/metro/assets/2186326/98206164-2ad2-4fd3-aa2d-67958a389b0d

In this video, only the very first change to code was captured (about 0:22 in the video).

When I hit r, you can see the client reload. (Go to about 1:02 in the video, that's when I hit the reload button.)

Observations:

When a change is captured correctly, and the app updates, this is the output:

  Metro:WatchmanWatcher Handling change to: App.tsx (new: false, exists: true, type: f) +0ms
  Metro:WatchmanWatcher Handling change to: App.tsx~ (new: true, exists: false, type: f) +1ms
  Metro:DeltaCalculator Handling change: /Users/akarlovac/git/nissan/react_native_update_test/App.tsx (type: f) +12m
  Metro:DeltaCalculator Calculating delta (reset: false, shallow: false) +51ms
  Metro:DeltaCalculator Traversing dependencies for 1 paths +0ms
  Metro:DeltaCalculator Calculated graph delta {added: 0, modified: 1, deleted: 0} +55ms

When I save, and nothing happens, this is the output:

  Metro:WatchmanWatcher Received subscription response: metro-file-map-32531--Users-akarlovac-git-nissan-react_native_update_test-fe3d54f5bc828c7ca49865afa3708247 (fresh: false, files: 2, enter: undefined, leave: undefined) +5s
  Metro:WatchmanWatcher Handling change to: App.tsx (new: true, exists: true, type: f) +0ms
  Metro:WatchmanWatcher Handling change to: App.tsx~ (new: true, exists: false, type: f) +1ms
  Metro:DeltaCalculator Handling add: /Users/akarlovac/git/nissan/react_native_update_test/App.tsx (type: f) +5s
  Metro:DeltaCalculator Calculating delta (reset: false, shallow: false) +49ms

I noticed it mentions an App.tsx~ file. I checked with ls -a, but there is no App.tsx~ file - it may be that my editor (vim) creates that temporarily while saving. Not sure if that's relevant.

antun commented 8 months ago

UPDATE

I did a bit more digging and found that with vim (editor) the default behavior is to write the buffer to a new file (I'm guessing this is App.tsx~), delete the original file (App.tsx) and then rename the new file (presumably App.tsx~ -> App.tsx). See this SO post.

If I set set nowritebackup in my .vimrc file, then the app updates on every code change. So I guess vim's save process is confusing Metro.

It sounds like it's not recommended to leave set nowritebackup since there's a risk of losing the file if something goes wrong during the save.

robhogan commented 8 months ago

Interesting, thanks! It looks like from Metro's perspective Watchman reports a "new file" event for App.tsx, which generally won't trigger a graph update (because the slightly naive assumption is that a new file isn't part of an existing graph, so there's no way it can change the graph).

If Watchman sees the file as new it's odd that there's no prior, corresponding deletion event - Metro would treat delete+add the same as modified. I'll raise this with Watchman folks, but in any case we can change our assumptions here to treat added as possibly-modified, and the vim repro will help us verify, so thanks again. I'll leave this open until we've landed some way to support this editor behaviour.

homedirectory commented 5 months ago

This bug should be mentioned in a FAQ somewhere so Metro users can easily discover it. I have almost blown my brains out because of it while trying to set up a development environment for React Native with Vim. In my case no changes whatsoever were being reloaded because of Vim creating a backup file.

itokun99 commented 5 months ago

I realize to find out "Why my code is not work after saving?" im using nvim btw, so there is a bug 😄