Summary: Right now we are using `JSON.stringify` which is very lossy with regards to JavaScript data types like functions, `undefined`, NaN and others. This diff switches the logging on the client side to use `prettyFormat` which is part of Jest. It allows to handle much richer log messages.
Reviewed By: gaearon
Differential Revision: D16458775
fbshipit-source-id: e1d2c125eb8357a9508521aa15510cb4f30a7fa9
Summary:
On iOS we don't call `HMRClient.setup()` when Metro is off. So we don't bump into any odd cases.
But on Android, we do call `HMRClient.setup()` even if Metro is off. As a result, we might show a warning about Metro not running to a native engineer who doesn't care (because they don't intend to work on JS).
We could fix this on Android on the native side. And we probably should.
But we can also strengthen it here. The idea is that we should only show warnings about disconnecting from Metro *if we ever managed to successfully connect in the first place*. Otherwise, we can assume that you didn't mean to connect.
If the user is trying to determine the source of the problem, they can still do a full Refresh (on iOS this will show a message about needing Metro, on Android it would show a redbox). So this diff makes the disconnected behavior closer to how it worked before Fast Refresh.
Reviewed By: sahrens
Differential Revision: D16460439
fbshipit-source-id: bf962ff34c25d9734d9668dd583591acacb98253
Summary:
Two changes:
1. If you're connected at startup, and then disconnect, we're supposed to show a yellow box. Looks like we weren't doing it for a few days because the field we were checking has turned into a method.
2. I changed the wording back to remove "Metro" since the packager may be Haul, for example. So I'm just calling it "development server". Does that seem reasonable? I also removed mentions of Fast Refresh since it's not actually relevant to the problem.
Reviewed By: cpojer
Differential Revision: D16459080
fbshipit-source-id: c9c1f19718d522c745e4107a3e7e3a6c63f82642
Summary:
This change switches the sending of log messages to Metro from HTTP over to WebSocket. This is what I should have done from the beginning *however* I only spent very little time on this initially, didn't realize that it would be a popular feature *and* we didn't have a persistent WebSocket connection on the client before that was always on. Together with D16442656 we can finally make this happen!
This change:
* Changes the `fetch` call to `HMRClient.log`
* Removes the middleware and integrates logging with `HmrServer` directly in Metro.
* Simplifies the logging logic as WebSockets guarantee messages are processed in order.
This also fixes an issue makovkastar identified when using the `MessageQueue` spy: because we send messages back and forth over the bridge, using `console.log` within `MessageQueue`'s spy method will actually cause an infinite logging loop. This is the proper solution to that problem instead of hacking around it using custom headers.
Note: in a follow-up we will rename these modules to drop the `HMR` prefix. We have not come up with a better name yet and are open to ideas.
Reviewed By: sebmck
Differential Revision: D16458499
fbshipit-source-id: 4c06acece1fef5234015c877354fb730b155168c
Summary: If there's a redbox at the start, we shouldn't dismiss it. Instead, redboxes should only be dismissed on explicit edits.
Reviewed By: yungsters
Differential Revision: D16421934
fbshipit-source-id: 770c5b5fc85e6b6ce00a4477aa87d6e91b14fc3c
Summary: When turning on Fast Refresh, we might have a compile error in previously saved files. We used to ignore it until a file is saved again, leading to a confusing experience. This changes it so that we remember the last compile error, and show it _either_ when we get it (if Fast Refresh is off), or when we _turn it on_.
Reviewed By: cpojer
Differential Revision: D16359160
fbshipit-source-id: 8dc237563c2a271a23019a32ff85b57de99cfabe
Summary: Right now we are using a local boolean and `bundle-registered` to hide the "Refresh" banner on the first update from the server (right after loading the bundle). This change adds `isInitialUpdate` to the `update-start` message which I'm now using to disable the banner. This also simplifies the HMRClient a little bit.
Reviewed By: cpojer
Differential Revision: D16357287
fbshipit-source-id: 29e72774989c4ba895a85be06a366e1b2fe7c02f
Summary:
If you change a file while Fast Refresh is off, this now stashes an update instead of ignoring it. When/if you turn it on, we will apply those stash updates. This solves the confusion that can happen when you enable it midway after making a bunch of changes, and therefore makes the experience more reliable.
**This current implementation is unfortunate because the app memory load increases with the number of file saves. This isn't really sustainable. So in the next diff I will change it to only remember the *latest versions* of every edited file instead.**
Reviewed By: cpojer
Differential Revision: D16344332
fbshipit-source-id: 69609a00eb9022f6b2797269fa091fa1b4125dd1
Summary:
We want to move to a world where Fast Refresh is on by default. As a first step, we can register the bundle early. This means we'll start receiving hot updates via the socket even if Fast Refresh is off. We'll just be ignoring those.
Anecdotally people with Fast Refresh on have had good experience even with invasive changes like branch switches. So this seems like a good way to test the waters further. It's also a prerequisite to unlocking a nicer experience where you can turn it on anytime and "catch up" on the changes you've missed. (That's out of scope of this diff.)
Reviewed By: cpojer
Differential Revision: D16344019
fbshipit-source-id: 6e5f8278909810b32c80e0af010251c876e4313b
Summary:
Two changes:
1. `disable` -> `close` to better match what's happening.
2. `enable` is inlined in the constructor because it's always called right after the constructor.
Reviewed By: rickhanlonii
Differential Revision: D16340009
fbshipit-source-id: 38a906b1ab3f5b39a57d2598ba400a2f03903951
Summary:
This adds a loading indicator when loading split bundles so that users get a visual indicator about what is going on.
Note that I am currently trying to get the dynamic message that shows the number of modules and percentage to work but it appears that the JavaScript networking client (XMLHttpRequest + RCTNetwork) are not set up to deal with multipart responses in the same way as our native multipart handlers are. I'd like to put this in place now and polish it later if it's possible to fix the issue (I spent all afternoon yesterday trying to make multipart messages work and failed :( ).
Reviewed By: gaearon
Differential Revision: D16281531
fbshipit-source-id: 84e53d7f25642398ed51d8f552919880b8090897
Summary:
This view will be re-used for bundle splitting so I'm changing the name to be more generic as it can be used for informing users of any loading activity.
I also cleaned up the files a bit from a class to just an object.
Reviewed By: gaearon
Differential Revision: D16281367
fbshipit-source-id: 5c2ee7790d29ccba473bd6e90737d2f0581e6291
Summary:
This diff builds on the previous ones and changes the setup process from using the WebSocket URL to using a message that is sent after the connection is established. It also exposes a function on the HMRClient that allows registering more bundles, which I will make use of in the next (and hopefully final :D ) diff.
I was initially planning on using structured data, like `{bundleName, platform}` but decided to keep using URLs as that is the format used throughout Metro. In fact, when we parse the options from the URL, we need to re-encode the input URL to create the `sourceMapUrl`. I thought it doesn't make sense to write more code to send structured data over the connection only to re-construct a URL on the server manually.
Finally, I also slightly modified the "Internal Bundler" error that is shown in a RedBox (now used by the websocket connection if an invalid message is received). I removed the "internal" wording from the message and I'm actually attaching the failure message to the error instead of directing users to the Terminal.
Reviewed By: gaearon
Differential Revision: D16162729
fbshipit-source-id: 977fde5f6c2f1c14efb4fd99ed30a6bf95a3b13e
Summary:
Previously, Fast Refresh socket was initialized lazily. This changes it to be initialized eagerly, even if Fast Refresh is off.
This makes it easier to reason about different states the app can be in. It also lets us later change the code to stash away updates even when Fast Refresh is off — and apply them when you turn it on. (That's out of scope of this diff).
This change should not be user observable. Even if setting up the socket fails, the error is saved, and should only be shown once you turn it on. (AFAIK, D16286232 fixes the last error that was shown unconditionally.)
Reviewed By: rickhanlonii
Differential Revision: D16287232
fbshipit-source-id: a88f9c9f72847074876087da46e19dffa4eb82eb
Summary: I originally added `forceFullRefresh` as an escape hatch in case Fast Refresh is too unreliable. In practice we haven't seen any major issues with it. Since this option is already very obscure, I'm just removing it.
Reviewed By: shergin
Differential Revision: D16286632
fbshipit-source-id: c3dc44cffd459912e194e273acf868f3380c64cc
Summary:
This fixes a problem that occurs when:
1. You run an Android app with Fast Refresh on
2. Kill the app
3. Start the app again
We used to redbox (on Android only). This is probably because we are missing some check on the native side, and we try to enable the socket anyway.
We could potentially fix this on the native side. But also, there's no good reason why this code needs to ever throw an error if Fast Refresh is disabled.
So I'm unifying it with the existing code path for other Fast Refresh errors. They are ignored when it's off, shown as yellowboxes when it's on, and shown as redboxes if you intentionally try to turn it off and on again.
I'm also adding core to prevent logging more than one Fast Refresh warning. Since they're not super actionable and usually indicate the same problem (e.g. Metro not running). The earliest one wins.
Reviewed By: rickhanlonii
Differential Revision: D16286232
fbshipit-source-id: bf3960f11c767a2352b1282d46950e4ba9e5031d
Summary: This diff changes a few things around so that a diff coming on top of this stack will be smaller. The aim of this change is to add a method `registerEntryPoint` which will allow a client to subscribe to updates for multiple bundles.
Reviewed By: gaearon
Differential Revision: D16131963
fbshipit-source-id: d460d6647b15a711021c7a3a51f52486a1aea535
Summary:
Running a PROD JS bundle with a DEV binary used to redbox with Fast Refresh on. The error said "HMRClient is not a registered callable module".
This isn't a new issue: https://www.google.com/search?q=%22hmrclient%20is%20not%20a%20registered%22. However, now it happens every time because `setup()` is now called unconditionally in a DEV native build.
Because a combination of DEV binary + PROD JS is technically possible, I'm adding a tiny shim that will make it a no-op instead of crashing. It will also explain what's wrong if you *intentionally* try to turn on Fast Refresh.
Reviewed By: sahrens
Differential Revision: D16145378
fbshipit-source-id: 0b9c0a6f30c02ca7f4a0133048450bdde3576ad2
Summary:
Metro symbolication can be expensive in large apps. However, there is no need to symbolicate _runtime stacks from compile errors_. Those are pretty much useless anyway.
This will reduce the workload on Metro workers, and the delays when iterating with Fast Refresh, as the server will be busy much less often.
So I'm special-casing them and not sending the symbolication request anymore.
Reviewed By: rickhanlonii
Differential Revision: D16030087
fbshipit-source-id: 41f83ac01780c0a60cca777014e4ed95c0f3d14b
Summary: If you make a syntax error while there is a redbox while Fast Refresh is on, we should dismiss that redbox. Otherwise there is no way for you to tell why your code is not working.
Reviewed By: rickhanlonii
Differential Revision: D15970337
fbshipit-source-id: 1ca6c9a1b2269d198ae726d3b64e5c51506503db
Summary:
If the error doesn't come in direct response to a user action, I think a redbox is too severe. I think we don't want to associate turning on Fast Refresh with a higher frequency of redboxes. So this downgrades these messages to warnings.
If you manually try to turn it off and on again, we'll still show a redbox to remind why it's not working.
Reviewed By: rickhanlonii, cpojer
Differential Revision: D15958952
fbshipit-source-id: bd144c98e87a9836871391ac583c268dca8009b3
Summary:
We have too many options in the Dev Menu, and they're really hard to pick from. They're also somewhat conflicting. This replaces two menu choices that have a similar purpose (faster iteration cycle) with one.
"Fast Refresh" tries to only update the affected modules, but falls back to doing a full reload if the update can't be handled by the React components.
If for some reason you prefer the "Reload-on-Save" behavior, please:
- Reach out to me so I can learn more about your use case.
- As a workaround, you can add `if (__DEV__) require.Refresh.forceFullRefresh = true` to your app's entry point to always do a full refresh.
Also note that I only removed the user-facing part of "Reload-on-Save". So if you have automation depending on it, that's gonna keep working.
I moved it above Systrace since it's a more generic feature.
As a total aside nit, I renamed "Enable Inspector" and "Disable Inspector" to "Show Inspector" and "Hide Inspector" because... that's what those options do, really.
Reviewed By: rickhanlonii
Differential Revision: D15958697
fbshipit-source-id: 20e856d56f661fe4d39b5ab47d8c44754bf70f67
Summary:
Since we always create `module.hot` objects, the `module.hot` checks were unnecessary. They give a false impression that we're checking for a Hot Reloading mode. However, they're just Flow refinements and always exist in DEV. I made that explicit by throwing early.
Similarly, I removed a `module.hot` check inside `setupReactRefresh`, as it is always truish in DEV.
Finally, I'm adding a new mechanism as an escape hatch. It lets you do:
```
if (__DEV__) {
require.Refresh.forceFullRefresh = true;
}
```
in your entry point and opt into full refreshes on every edit. This sounds similar to "Reload-on-Save". That is because in the next diff, I plan to remove "Reload-on-Save" from user-visible options (but it'll stay for automated workflows).
So this workaround is intended for people who for one reason or another don't want to opt into Hot Reloading as an alternative. We'll need to talk to them and find out why.
Reviewed By: rickhanlonii
Differential Revision: D15958475
fbshipit-source-id: 674187ddf86a4e286dfae28f4182555a8b5d7396
Summary:
As we saw in D15947985, and later traced down to D5623623, the `hot` option isn't used by Metro anymore. The relevant transforms _always_ run in DEV regardless of the option.
Given that, it doesn't make sense that enabling or disabling Hot Reloading forces a full refresh. This significantly raises the usage barrier because **currently, you might have to wait ~20 seconds (on a large app) to just start using Hot Reloading when you're already in the middle of some screen.** So you just end up not using it.
This diff changes enabling/disabling Hot Reloading to be _instant_.
Here's how it works:
1. Now we always send the necessary info to the client via the new `HMRClient.setup()` function. It creates a Metro HMR client instance, but only actually sets up the socket if Hot Reloading is on.
2. The "Enable Hot Reloading" menu no longer forces a reload. Instead, it calls `HMRClient.enable()` which lazily sets up a socket (at most once).
3. The "Disable Hot Reloading" menu also doesn't trigger a refresh now. Instead, it calls `HMRClient.disable()`. We don't actually tear down the socket here because it's a pain to deal with race conditions and such. Instead, we keep the connection — but we _ignore the updates_ that come in while we're disabled.
4. As a result, it is possible to enable and disable it many times during a single session. (Updates while disabled would be ignored — which has a risk of making your running app inconsistent — but I'd argue it's expected and is worth it. You can always save a particular file to force it to update once the mode is on.)
5. In order to support "ignoring" updates, Metro's `HMRClient` (not to be confused with RN's module) now supports a `shouldApplyUpdates` field. The RN module uses it to disable handling updates when the mode is off.
6. In case there is an error that makes hot reloading unavailable (such as the server disconnecting), we surface the error only if the mode is on. If the mode is off, we stash the error message in the `_hmrUnavailableReason` variable, and display it next time you try to enable Hot Reloading.
Reviewed By: rickhanlonii
Differential Revision: D15958160
fbshipit-source-id: 8256fc4d5c2c3f653a78edf13b8515a5671953e4
Summary:
D10527979 made the "update" message sequence part of initial connection signals. But the HMR client uses this sequence as a signal to show "Hot Reloading..." bar. As a result, we were showing it on every initial load when Hot Reloading is on. This is very confusing.
As a simple fix, I now send an explicit message to mark the end of the first load. I could infer that by first update message but figured this is more explicit and less likely to break. Until we receive `connection-done`, we now don't attempt to show the "Hot Reloading..." bar.
Reviewed By: rubennorte
Differential Revision: D15936085
fbshipit-source-id: b18b6aceea6c47d919b4265e58b21fc44f77b0b3
Summary:
Addresses a number of pieces of feedback regarding the debug menu.
- Simplify labels for the debugger actions (e.g. no "remote", no emoji).
- Reorder actions so that modal items are generally lower.
- Changed "Toggle Inspector" to "Show/Hide Inspector".
- Renamed "Live Reloading" to "Reload-on-Save".
- Hide disabled debug items when profiling is enabled.
- Changed "Start Systrace" to "Systrace Unavailable" when debugging.
- Renamed "Change packager location" to "Configure Bundler".
- Revised nomenclature in "Configure Bundler" menu to be clearer.
- Removed extraneous debug menu title.
- Consistently refer to HMR as "Hot Reloading".
Changelog:
[iOS] [Changed] - Cleaned up debug menu.
Reviewed By: axe-fb
Differential Revision: D15548628
fbshipit-source-id: 26b2ddca8280d1f6f8ff904439b403600e98a3b3
Summary:
This is the next step in moving RN towards standard path-based requires. All the requires in `Libraries` have been rewritten to use relative requires with a few exceptions, namely, `vendor` and `Renderer/oss` since those need to be changed upstream. This commit uses relative requires instead of `react-native/...` so that if Facebook were to stop syncing out certain folders and therefore remove code from the react-native package, internal code at Facebook would not need to change.
See the umbrella issue at https://github.com/facebook/react-native/issues/24316 for more detail.
[General] [Changed] - Migrate "Libraries" from Haste to standard path-based requires
Pull Request resolved: https://github.com/facebook/react-native/pull/24749
Differential Revision: D15258017
Pulled By: cpojer
fbshipit-source-id: a1f480ea36c05c659b6f37c8f02f6f9216d5a323
Summary: This is one more step to remove `fbjs` from `react-native-github`. This changes both the internal and external code to use `invariant` from zertosh instead of the copy in fbjs.
Reviewed By: yungsters
Differential Revision: D13195941
fbshipit-source-id: 73564ca1715110e7da9c7ef56dc57374d61377e0
Summary:
GraphNotFoundError: When the user moves the app to the background on Android, restarts the Metro server and reopens the app, since the client hasn't requested either a delta or a bundle, the graph cache of the server is empty and thus we can't compute an update for the client (what if changes happened when the metro server was down?).
RevisionNotFoundError: I didn't manage to reproduce that one. It could happen if two clients live side-by-side, requesting the exact same bundle. In the future, if we want to handle that case, we'll need to manage a list of clients listening to a single graph so that we don't try to update the same graph multiple times for a single file change.
Disconnection: Same as GraphNotFoundError, but happens when the user moves the app to the background on iOS.
Reviewed By: mjesun
Differential Revision: D12960939
fbshipit-source-id: 5ac1dc7fd12bad5e0ee8dfa5a21c112773454ee5
Summary: This change drops the year from the copyright headers and the LICENSE file.
Reviewed By: yungsters
Differential Revision: D9727774
fbshipit-source-id: df4fc1e4390733fe774b1a160dd41b4a3d83302a
Summary:
This PR removes the need for having the `providesModule` tags in all the modules in the repository.
It configures Flow, Jest and Metro to get the module names from the filenames (`Libraries/Animated/src/nodes/AnimatedInterpolation.js` => `AnimatedInterpolation`)
* Checked the Flow configuration by running flow on the project root (no errors):
```
yarn flow
```
* Checked the Jest configuration by running the tests with a clean cache:
```
yarn jest --clearCache && yarn test
```
* Checked the Metro configuration by starting the server with a clean cache and requesting some bundles:
```
yarn run start --reset-cache
curl 'localhost:8081/IntegrationTests/AccessibilityManagerTest.bundle?platform=android'
curl 'localhost:8081/Libraries/Alert/Alert.bundle?platform=ios'
```
[INTERNAL] [FEATURE] [All] - Removed providesModule from all modules and configured tools.
Closes https://github.com/facebook/react-native/pull/18995
Reviewed By: mjesun
Differential Revision: D7729509
Pulled By: rubennorte
fbshipit-source-id: 892f760a05ce1fddb088ff0cd2e97e521fb8e825
Summary:
Includes React Native and its dependencies Fresco, Metro, and Yoga. Excludes samples/examples/docs.
find: ^(?:( *)|( *(?:[\*~#]|::))( )? *)?Copyright (?:\(c\) )?(\d{4})\b.+Facebook[\s\S]+?BSD[\s\S]+?(?:this source tree|the same directory)\.$
replace: $1$2$3Copyright (c) $4-present, Facebook, Inc.\n$2\n$1$2$3This source code is licensed under the MIT license found in the\n$1$2$3LICENSE file in the root directory of this source tree.
Reviewed By: TheSavior, yungsters
Differential Revision: D7007050
fbshipit-source-id: 37dd6bf0ffec0923bfc99c260bb330683f35553e
Summary:
The code to display HMR errors on the client was reading the `description` field from Metro payloads. Metro does not include `description` in the body of its error payloads -- only in its `body.errors[]` items. This commit changes RN's HMR code to show `body.message` (set consistently with https://github.com/facebook/metro/pull/124) instead of the non-existent `body.description`.
Open a test RN app, enable HMR, and then introduce a syntax error in an app source file. See that the redbox provides information about the syntax error instead of just saying "TransformError undefined".
- https://github.com/facebook/metro/pull/124
[GENERAL][ENHANCEMENT][HMR] - Fix display of syntax error messages when HMR is enabled
Closes https://github.com/facebook/react-native/pull/17619
Differential Revision: D6726516
Pulled By: mjesun
fbshipit-source-id: b1d1008d6f1aa8f88ff8a2aa1374724a305c773b
Summary:
In several pervious diffs we have moved symbolication of JS stack traces
to the packeger. This lets us save a bunch of memory (~80MB) and CPU on device,
reduces dependency on JS after exception occured.
This diff cleans up a bunch of code that was used to do symbolication on client side.
Reviewed By: javache
Differential Revision: D3348676
fbshipit-source-id: 88baa5c502836c9ca892896e1ee5d83db37486d3
Summary:Source maps are broken on Genymotion right now as they aren't being loaded from the correct URL. refer - https://github.com/facebook/react-native/issues/5338#issuecomment-188232402
**Test plan**
Build and install UIExplorer from master branch in genymotion and enable hot reload. When you change a file and save it, you'll see a Yellow box due to source map fetching failed, as per the referenced comment.
Doing the same for this branch doesn't produce any yellow boxes.
Closes https://github.com/facebook/react-native/pull/6594
Differential Revision: D3088218
Pulled By: martinbigio
fb-gh-sync-id: 0d1c19cc263de5c6c62061c399eef33fa4ac4a7b
shipit-source-id: 0d1c19cc263de5c6c62061c399eef33fa4ac4a7b
Summary:We recently refactor the packager to transform the module names into numeric IDs but we forgot to update the HMR call site. As a consequence, HMR doesn't work the first time a file is saved but the second one.
This is affecting master as of 3/20. If we don't land this before v0.23 is cut we'll have to cherry pick it. This rev does *not* need to be picked on v0.22.
Reviewed By: bestander
Differential Revision: D3075192
fb-gh-sync-id: 410e4bf8f937c0cdb8f2b462dd36f928a24e8aa8
shipit-source-id: 410e4bf8f937c0cdb8f2b462dd36f928a24e8aa8
Summary:Sourcemaps on HMR where a couple of line off. The problem is that since the `__accept` call doesn't go through the sourcemaps pipeline we need to make sure that call is a single-line one.
This was originally written in a single line but I incorrectly updated it on 436db67126. Would be great having test coverage for this.
Reviewed By: davidaurelio
Differential Revision: D3075164
fb-gh-sync-id: c77ea99f26bdd675f241c5d20a620eb4ddfbf701
shipit-source-id: c77ea99f26bdd675f241c5d20a620eb4ddfbf701
Summary:Follow-up to https://github.com/facebook/react-native/pull/5084
This…
- changes all requires within RN to `require('fbjs/lib/…')`
- updates `.flowconfig`
- updates `packager/blacklist.js`
- adapts tests
- removes things from `Libraries/vendor/{core,emitter}` that are also in fbjs
- removes knowledge of `fbjs` from the packager
Closes https://github.com/facebook/react-native/pull/5084
Reviewed By: bestander
Differential Revision: D2926835
fb-gh-sync-id: 2095e22b2f38e032599d1f2601722b3560e8b6e9
shipit-source-id: 2095e22b2f38e032599d1f2601722b3560e8b6e9
Summary:This is just to try out the experience with HMR if we show toasts (might be annoying). Let's try it out before deciding on merging/closing.
Related #5906
Closes https://github.com/facebook/react-native/pull/5947
Differential Revision: D2987132
fb-gh-sync-id: 7bfbb6e1f0363a416805b67eb5674f79ac0881ad
shipit-source-id: 7bfbb6e1f0363a416805b67eb5674f79ac0881ad