Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/26143
A new useColorScheme hook is provided as the preferred way of accessing the user's preferred color scheme (aka Dark Mode).
Changelog:
[General] [Added] - useColorScheme hook
Reviewed By: yungsters
Differential Revision: D16860954
fbshipit-source-id: 8a2b6c2624ed7cf431ab331158bc5456cde1f185
Summary:
Implements the Appearance native module as discussed in https://github.com/react-native-community/discussions-and-proposals/issues/126.
The purpose of the Appearance native module is to expose the user's appearance preferences. It provides a basic get() API that returns the user's preferred color scheme on iOS 13 devices, also known as Dark Mode. It also provides the ability to subscribe to events whenever an appearance preference changes.
The name, "Appearance", was chosen purposefully to allow for future expansion to cover other appearance preferences such as reduced motion, reduced transparency, or high contrast modes.
Changelog:
[iOS] [Added] - The Appearance native module can be used to prepare your app for Dark Mode on iOS 13.
Reviewed By: yungsters
Differential Revision: D16699954
fbshipit-source-id: 03b4cc5d2a1a69f31f3a6d9bece23f6867b774ea
Summary:
https://github.com/facebook/react-native/pull/25990 fixed the `forceUpdate` method to actually update the component, but caused the useEffect to fire on every render, causing continuous updates after dimensions changed (e.g. from rotation).
This reworks things a bit to be a bit simpler and more idiomatic so it's not quite as confusing, and fixes the bugs.
## Changelog
[General] [Fixed] - Fix useWindowDimensions hook firing continuously after dimensions change
Pull Request resolved: https://github.com/facebook/react-native/pull/26008
Test Plan:
Aparently the Mobile Home app supports rotation on iOS now, so replaced it's content with the first `DimensionsExample` and confirmed with logging that `useEffect` fires exactly once, on initial mount, but the view still updates as expected when rotated:
https://pxl.cl/Hfds
Reviewed By: yungsters
Differential Revision: D16765269
Pulled By: sahrens
fbshipit-source-id: ef55d8a470dcfe87aa125d4c426bf01cfe0091a7
Summary:
Need to add explicit type annotations in these areas to unblock types-first architecture for Flow. These are locations the codemod could not automatically handle.
I'll call out areas I need a close eye on in the comments.
Reviewed By: panagosg7
Differential Revision: D16659053
fbshipit-source-id: 167dd2abe093019b128676426374c1c62cf71e7f
Summary: This diff fixes the error message in the codegenNativeComponent fallback
Reviewed By: TheSavior
Differential Revision: D16579775
fbshipit-source-id: 176f81ea91e11f671407a5e5e5b000c4b83f93b2
Summary: ComponentScript uses Dimensions, but doesn't support native modules, so we need to keep the `nativeExtensions` stuff that was dropped in D16525189.
Reviewed By: PeteTheHeat
Differential Revision: D16611233
fbshipit-source-id: c0add40529743e02ab7943814dc9f2188e8e0633
Summary:
Previously codegenNativeCommands was just a hint to the babel transform. This meant that in order to use the codegen'd JS command functions it required having the babel transform turned on.
We aren't ready to turn the transform on for open source so we are adding runtime behavior to the function that will run when it isn't replaced with the transform.
Reviewed By: rickhanlonii
Differential Revision: D16574781
fbshipit-source-id: 583e8857f69ae1695445ee887432d15248dd35a9
Summary:
Original commit changeset: 34a8f8395ca7
The problem with the original commit was the usage of optional chaining. This diff removes the usage of optional chaining with good old fashioned null checks.
Reviewed By: rickhanlonii
Differential Revision: D16593623
fbshipit-source-id: d24cc40c85de9a2e712e5de19e9deb196003ccf2
Summary:
We want to enable codegenNativeCommands to have a runtime fallback that will work if the babel transform is not enabled. For example, in open source until we turn it on everywhere. By listing the supported commands, we can create the necessary functions at runtime to support what we need.
A follow up diff will add that runtime behavior to codegenNativeCommands.
Reviewed By: JoshuaGross
Differential Revision: D16573450
fbshipit-source-id: 189754a567a3a5ccd34629a8dfedf808e6824e82
Summary:
Automatically provides and subscribes to dimension updates - super easy usage:
```
function MyComponent(props: Props) {
const {width, height, scale, fontScale} = useWindowDimensions();
return <Text ...
};
```
Only window for now - it's what people want 99% of the time, so we'll just shovel out a pit of success for them...
There are still cases where `Dimensions` is needed outside of React component render functions, like in GraphQL variables, so we need to keep the existing module.
Reviewed By: zackargyle
Differential Revision: D16525189
fbshipit-source-id: 0a049fb3be8d92888a8a69e3898d337b93422a09
Summary: Symbol is not available in older versions of JSON resulting in crashes in `prettyFormat` because we are using a clowny transform.
Reviewed By: sebmck
Differential Revision: D16501208
fbshipit-source-id: 9952bf4993ae05335707cd386f9aa4bbc14b7564
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:
Error objects logged as part of the arguments to `console.error` such as from [rejected es6 promises](https://github.com/zloirock/core-js/blob/v2/modules/es6.promise.js#L110) contain the error that the user would want to see as the error object's message, but is not captured by `stringifySafe`. Here we modify it to if the logged value is an error object print the error similar to chrome:
```
const error = new Error('error');
stringifySafe(error); // Error: error
```
Versus the current behavior which does not recognize the error type and instead tries to stringify the it as an object:
```
JSON.stringify(new Error('error')) // "{}"
```
## Changelog
[JavaScript] [Changed] - Add support for stringifying error object messages to safeStringify
Pull Request resolved: https://github.com/facebook/react-native/pull/25723
Test Plan:
Tests:
<img width="802" alt="Screen Shot 2019-07-18 at 8 39 52 PM" src="https://user-images.githubusercontent.com/2192930/61501171-39218080-a99c-11e9-8e87-48ea413b3d01.png">
Lint:
<img width="406" alt="Screen Shot 2019-07-18 at 8 43 35 PM" src="https://user-images.githubusercontent.com/2192930/61501318-dc729580-a99c-11e9-9264-c0232515352c.png">
Differential Revision: D16437956
Pulled By: cpojer
fbshipit-source-id: ca3ce9c98ad585beb29c2bfeb81bbd14b2b1c700
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: D16107933 disabled the logs around setup unless they are explicitly enabled and this diff disables all logs from this module entirely unless they are explicitly turned on at the top of the file.
Reviewed By: gaearon
Differential Revision: D16108151
fbshipit-source-id: 355aaf8624fb0778884f25f02d58fe4e1237d686
Summary: This module logs helpful messages in `__DEV__` but it only logs actionable performance logs when the flag on top of the file is enabled. This diff changes those to only log when the toggle on top of the file is enabled as well.
Reviewed By: gaearon
Differential Revision: D16107933
fbshipit-source-id: 7671bc521af984d617a0f5ffc0eacd1aa5674a62
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