Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire up Fusebox in react-native-windows #13008

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft

Conversation

rozele
Copy link
Collaborator

@rozele rozele commented Apr 29, 2024

Description

Type of Change

Erase all that don't apply.

  • New feature (non-breaking change which adds functionality)

Why

React Native is moving to a new direct debugging architecture. This PR is a stack of commits to unblock Fusebox debugging in react-native-windows.

What

Wires up the HostTarget in ReactNativeHost for react-native-windows. This code will only run if InspectorFlags::getEnableModernCDPRegistry() returns true.

Testing

TBD

Changelog

Should this change be included in the release notes: no

Microsoft Reviewers: Open in CodeFlow

@rozele rozele requested a review from a team as a code owner April 29, 2024 16:21
@rozele rozele changed the title Add HostTarget to CDP registry Wire up Fusebox in react-native-windows Apr 29, 2024
@rozele rozele marked this pull request as draft April 29, 2024 16:22
@rozele rozele force-pushed the fusebox branch 5 times, most recently from 25067d1 to 7f7bcaa Compare April 29, 2024 18:08
rozele added 7 commits May 1, 2024 16:35
In preparation for unblocking Fusebox in react-native-windows, this change adds a stable device ID, which is a hash of the publisher device ID from Windows APIs and the bundle ID.
Adds thread pool queue for Fusebox debugger for use when implementing callbacks for the HostTarget or the InspectorPackagerConnection.
Wires up the HostTarget in ReactNativeHost for react-native-windows. This code will only run if InspectorFlags::getEnableModernCDPRegistry() returns true.
This adds an implementation of InspectorPackagerConnectionDelegate for react-native-windows.
Using the same inspector thread initialized in ReactNativeHost, this
change wires up the InspectorPackagerConnectionDelegate to use when
initializatng the InspectorPackagerConnection from ReactCommon and
conditionally sets it for Hermes direct debugging when the appropriate
feature flag is set.
rozele added 2 commits May 1, 2024 19:04
To avoid conflicting with content manipulation of the ReactRootView, this change uses a Flyout anchored to the top of the ReactRootView to show the debugger paused overlay. It disables the default light dismiss (and automatic dismissal when the window loses focus) by overriding the Closing method and canceling the close event until we receive a hide debugger overlay notification.
Similar to browsers, this change adds the Ctrl+Shift+I shortcut to each XamlRoot containing a ReactRootView.

For simplicity, this only works with metro on localhost:8081, but we (or Microsoft) can revisit this in the future if we want to add more granular control over the host and port for metro.
@@ -73,6 +73,20 @@ using namespace Microsoft::JSI;
using std::make_shared;
using winrt::Microsoft::ReactNative::ReactPropertyBagHelper;

namespace facebook::react {
bool shouldStartHermesInspector(DevSettings &devSettings) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This didn't actually end up needing to be moved.

@@ -105,6 +119,12 @@ void LoadRemoteUrlScript(
hermesBytecodeVersion = ::hermes::hbc::BYTECODE_VERSION;
#endif

const auto bundlePath = ;
if (facebook::react::shouldStartHermesInspector(*devSettings)) {
devManager->EnsureHermesInspector(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't have to move either.

@@ -291,6 +291,18 @@ ReactInstanceWin::ReactInstanceWin(
}

ReactInstanceWin::~ReactInstanceWin() noexcept {
#ifdef USE_FABRIC
if (m_bridgelessReactInstance && m_options.InspectorTarget) {
auto messageDispatchQueue =
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using MessageDispatchQueue to get the runOnQueueSync function on an Mso::DispatchQueue. We need to ensure the ReactInstance stays alive for as long as it takes to unregister the inspector.

@@ -204,7 +204,7 @@ class ReactInstanceWin final : public Mso::ActiveObject<IReactInstanceInternal>

#ifdef USE_FABRIC
// Bridgeless
std::unique_ptr<facebook::react::ReactInstance> m_bridgelessReactInstance;
std::shared_ptr<facebook::react::ReactInstance> m_bridgelessReactInstance;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

converted to shared_ptr to provide weak_ptr to host target de-init

ReactNativeHost::ReactNativeHost() noexcept : m_reactHost{Mso::React::MakeReactHost()} {
#if _DEBUG
facebook::react::InitializeLogging([](facebook::react::RCTLogLevel /*logLevel*/, const char *message) {
std::string str = std::string("ReactNative:") + message;
OutputDebugStringA(str.c_str());
});
#endif

auto &inspectorFlags = facebook::react::jsinspector_modern::InspectorFlags::getInstance();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should all be lazy init'd on the first reload, otherwise you have to set the feature flag before calling the ReactNativeHost ctor, rather than just before attaching the ReactNativeHost to the ReactRootView.

const std::string &message,
const std::function<void()> &onResume) noexcept {
// Initialize content
const xaml::Controls::Grid contentGrid;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be converted to a xaml string or something, or a xaml component, but since we don't have a XAML compiler outside visual studio, I prefer this to be imperative WinUI set up :|

messageBlock.Text(winrt::to_hstring(message));
messageBlock.FontWeight(winrt::Windows::UI::Text::FontWeights::SemiBold());
xaml::Controls::FontIcon resumeGlyph;
resumeGlyph.FontFamily(xaml::Media::FontFamily(L"Segoe MDL2 Assets"));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal is to look like this, but I didn't want to introduce an image asset in Microsoft.ReactNative for various reasons (most notably I'd end up having to configure it twice, once for Visual Studio and once for buck), so I took a shortcut here and just used a glyph that kind of looks like the Visual Studio continue debugging button.
image

// Disable light dismiss
m_debuggerPausedFlyout.Closing([weakThis = this->get_weak()](auto &&, const auto &args) {
if (auto strongThis = weakThis.get()) {
args.Cancel(strongThis->m_isDebuggerPausedOverlayOpen);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still a bug with this Flyout where it dismisses when resizing the window :(

if (const auto strongThis = weakThis.get()) {
if (IsCtrlShiftI(args.Key())) {
::Microsoft::ReactNative::GetSharedDevManager()->OpenDevTools(
winrt::to_string(strongThis->m_reactNativeHost.InstanceSettings().BundleAppId()));
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a hack, we probably need to put this somewhere else, but I couldn't think of a good place that both had access to DevSettings and all active XamlRoots, and I was being a bit lazy not wanting to wire this through the ReactNativeHost.

// TODO: Use currently configured dev server host
winrt::Windows::Foundation::Uri uri(
Microsoft::Common::Unicode::Utf8ToUtf16(facebook::react::DevServerHelper::get_OpenDebuggerUrl(
std::string{DevServerHelper::DefaultPackagerHost},
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we'd specifically not want to use the defaults (localhost:8081)

class FuseboxInspectorThread final {
public:
static Mso::DispatchQueue &Instance() {
static Mso::DispatchQueue queue = Mso::DispatchQueue::MakeSerialQueue();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used a SerialQueue so I didn't have to worry about tearing anything down, maybe that's not really true though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant