react-native-windows 0.80.0 → 0.80.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/Directory.Build.props +1 -1
  2. package/Microsoft.ReactNative/Fabric/Composition/DebuggerUIIsland.cpp +169 -0
  3. package/Microsoft.ReactNative/Fabric/Composition/DebuggerUIIsland.h +42 -0
  4. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.cpp +1 -1
  5. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +60 -33
  6. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +68 -1
  7. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +9 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +5 -37
  9. package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.cpp +5 -3
  10. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +6 -1
  11. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +14 -1
  12. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorUtils.cpp +0 -17
  13. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorUtils.h +0 -3
  14. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.cpp +75 -24
  15. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.h +4 -25
  16. package/Microsoft.ReactNative/JsiApi.cpp +1 -1
  17. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -0
  18. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +3 -0
  19. package/Microsoft.ReactNative/ReactHost/DebuggerNotifications.h +54 -0
  20. package/Microsoft.ReactNative/ReactHost/React.h +11 -4
  21. package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +195 -29
  22. package/Microsoft.ReactNative/ReactHost/ReactHost.h +22 -4
  23. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +24 -5
  24. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -1
  25. package/Microsoft.ReactNative/ReactRootView.cpp +108 -0
  26. package/Microsoft.ReactNative/ReactRootView.h +6 -0
  27. package/Microsoft.ReactNative/Views/DevMenu.cpp +1 -1
  28. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +1 -1
  29. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  30. package/PropertySheets/JSEngine.props +1 -1
  31. package/PropertySheets/React.Cpp.props +2 -2
  32. package/ReactCommon/ReactCommon.vcxproj +18 -1
  33. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/NativeToJsBridge.cpp +1 -1
  34. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/test/testlib.cpp +4 -4
  35. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.cpp +23 -9
  36. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsinspector-modern/NetworkIOAgent.h +16 -0
  37. package/ReactCommon/cgmanifest.json +1 -1
  38. package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +2 -0
  39. package/Shared/DevServerHelper.h +13 -3
  40. package/Shared/DevSettings.h +7 -0
  41. package/Shared/DevSupportManager.cpp +79 -20
  42. package/Shared/DevSupportManager.h +7 -19
  43. package/Shared/Hermes/HermesRuntimeAgentDelegate.cpp +99 -0
  44. package/Shared/Hermes/HermesRuntimeAgentDelegate.h +81 -0
  45. package/Shared/Hermes/HermesRuntimeTargetDelegate.cpp +263 -0
  46. package/Shared/Hermes/HermesRuntimeTargetDelegate.h +77 -0
  47. package/Shared/HermesRuntimeHolder.cpp +29 -111
  48. package/Shared/HermesRuntimeHolder.h +214 -32
  49. package/Shared/IDevSupportManager.h +5 -2
  50. package/Shared/Inspector/ReactInspectorPackagerConnectionDelegate.cpp +108 -0
  51. package/Shared/Inspector/ReactInspectorPackagerConnectionDelegate.h +19 -0
  52. package/Shared/Inspector/ReactInspectorThread.h +18 -0
  53. package/Shared/JSI/RuntimeHolder.h +5 -2
  54. package/Shared/OInstance.cpp +44 -27
  55. package/Shared/Shared.vcxitems +27 -17
  56. package/Shared/Shared.vcxitems.filters +33 -15
  57. package/package.json +4 -4
  58. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +0 -79
  59. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.h +0 -51
  60. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +0 -50
  61. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.cpp +0 -41
  62. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.h +0 -127
  63. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi.inc +0 -125
  64. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +0 -16
  65. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_win.cpp +0 -23
  66. package/Microsoft.ReactNative.Cxx/JSI/decorator.h +0 -1054
  67. package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +0 -145
  68. package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +0 -372
  69. package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +0 -797
  70. package/Microsoft.ReactNative.Cxx/JSI/jsi.h +0 -1799
  71. package/Microsoft.ReactNative.Cxx/JSI/threadsafe.h +0 -79
  72. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +0 -3531
  73. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +0 -38
  74. package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +0 -614
  75. package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +0 -212
  76. package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +0 -199
  77. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.cpp +0 -78
  78. package/ReactCommon/TEMP_UntilReactCommonUpdate/cxxreact/JSExecutor.h +0 -196
  79. package/ReactCommon/TEMP_UntilReactCommonUpdate/jserrorhandler/JsErrorHandler.cpp +0 -429
  80. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsitooling/react/runtime/JSRuntimeFactory.cpp +0 -45
  81. package/ReactCommon/TEMP_UntilReactCommonUpdate/jsitooling/react/runtime/JSRuntimeFactory.h +0 -91
  82. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/runtime/ReactInstance.cpp +0 -670
  83. package/Shared/InspectorPackagerConnection.cpp +0 -232
  84. package/Shared/InspectorPackagerConnection.h +0 -61
  85. /package/Shared/{HermesSamplingProfiler.cpp → Hermes/HermesSamplingProfiler.cpp} +0 -0
  86. /package/Shared/{HermesSamplingProfiler.h → Hermes/HermesSamplingProfiler.h} +0 -0
@@ -17,7 +17,4 @@ winrt::Windows::UI::Color ResolvePlatformColor(const std::vector<std::string> &s
17
17
  // Get appropriate placeholder text color for TextInput based on focus state and background
18
18
  SharedColor GetTextInputPlaceholderColor(bool isFocused, const winrt::Windows::UI::Color &backgroundColor = {});
19
19
 
20
- // Get default text foreground color for Text component (theme-aware)
21
- SharedColor GetDefaultTextColor();
22
-
23
20
  } // namespace facebook::react
@@ -12,8 +12,11 @@
12
12
 
13
13
  #include <folly/portability/SysResource.h>
14
14
  #include <folly/system/ThreadName.h>
15
- #include <chrono>
15
+ #include <condition_variable>
16
16
  #include <future>
17
+ #include <mutex>
18
+ #include <queue>
19
+ #include <thread>
17
20
  #include <utility>
18
21
 
19
22
  #include <glog/logging.h>
@@ -25,40 +28,88 @@
25
28
 
26
29
  namespace facebook::react {
27
30
 
28
- TaskDispatchThread::TaskDispatchThread(std::string threadName, int priorityOffset) noexcept
29
- : threadName_(std::move(threadName)) {
30
- #ifdef ANDROID
31
- // Attaches the thread to JVM just in case anything calls out to Java
32
- thread_ = std::thread([&]() {
33
- facebook::jni::ThreadScope::WithClassLoader([&]() {
34
- int result = setpriority(PRIO_PROCESS, static_cast<pid_t>(::syscall(SYS_gettid)), priorityOffset);
31
+ class TaskDispatchThread::Impl : public std::enable_shared_from_this<TaskDispatchThread::Impl> {
32
+ public:
33
+ Impl(std::string &&threadName) noexcept;
34
+ ~Impl() noexcept;
35
+
36
+ void start() noexcept;
37
+ bool isOnThread() noexcept;
38
+ bool isRunning() noexcept;
39
+ void runAsync(TaskFn &&task, std::chrono::milliseconds delayMs = std::chrono::milliseconds::zero()) noexcept;
40
+ void runSync(TaskFn &&task) noexcept;
41
+ void quit() noexcept;
42
+ void loop() noexcept;
43
+
44
+ private:
45
+ struct Task {
46
+ TimePoint dispatchTime;
47
+ TaskFn fn;
48
+
49
+ Task(TimePoint dispatchTime, TaskFn &&fn) : dispatchTime(dispatchTime), fn(std::move(fn)) {}
50
+
51
+ bool operator<(const Task &other) const {
52
+ // Have the earliest tasks be at the front of the queue.
53
+ return dispatchTime > other.dispatchTime;
54
+ }
55
+ };
56
+
57
+ std::mutex queueLock_;
58
+ std::condition_variable loopCv_;
59
+ std::priority_queue<Task> queue_;
60
+ std::atomic<bool> running_{true};
61
+ std::string threadName_;
62
+ std::thread thread_;
63
+ };
64
+
65
+ TaskDispatchThread::TaskDispatchThread(std::string threadName, int /*priorityOffset*/) noexcept
66
+ : impl_(std::make_shared<Impl>(std::move(threadName))) {
67
+ impl_->start();
68
+ }
35
69
 
36
- if (result != 0) {
37
- LOG(INFO) << " setCurrentThreadPriority failed with pri errno: " << errno;
38
- }
70
+ TaskDispatchThread::~TaskDispatchThread() noexcept {
71
+ impl_->quit();
72
+ }
39
73
 
40
- loop();
41
- });
42
- });
74
+ bool TaskDispatchThread::isOnThread() noexcept {
75
+ return impl_->isOnThread();
76
+ }
43
77
 
44
- #else
45
- thread_ = std::thread(&TaskDispatchThread::loop, this);
46
- #endif
78
+ bool TaskDispatchThread::isRunning() noexcept {
79
+ return impl_->isRunning();
47
80
  }
48
81
 
49
- TaskDispatchThread::~TaskDispatchThread() noexcept {
82
+ void TaskDispatchThread::runAsync(TaskFn &&task, std::chrono::milliseconds delayMs) noexcept {
83
+ impl_->runAsync(std::move(task), delayMs);
84
+ }
85
+
86
+ void TaskDispatchThread::runSync(TaskFn &&task) noexcept {
87
+ impl_->runSync(std::move(task));
88
+ }
89
+
90
+ void TaskDispatchThread::quit() noexcept {
91
+ impl_->quit();
92
+ }
93
+
94
+ TaskDispatchThread::Impl::Impl(std::string &&threadName) noexcept : threadName_(std::move(threadName)) {}
95
+
96
+ TaskDispatchThread::Impl::~Impl() noexcept {
50
97
  quit();
51
98
  }
52
99
 
53
- bool TaskDispatchThread::isOnThread() noexcept {
100
+ void TaskDispatchThread::Impl::start() noexcept {
101
+ thread_ = std::thread([self = shared_from_this()]() { self->loop(); });
102
+ }
103
+
104
+ bool TaskDispatchThread::Impl::isOnThread() noexcept {
54
105
  return std::this_thread::get_id() == thread_.get_id();
55
106
  }
56
107
 
57
- bool TaskDispatchThread::isRunning() noexcept {
108
+ bool TaskDispatchThread::Impl::isRunning() noexcept {
58
109
  return running_;
59
110
  }
60
111
 
61
- void TaskDispatchThread::runAsync(TaskFn &&task, std::chrono::milliseconds delayMs) noexcept {
112
+ void TaskDispatchThread::Impl::runAsync(TaskFn &&task, std::chrono::milliseconds delayMs) noexcept {
62
113
  if (!running_) {
63
114
  return;
64
115
  }
@@ -68,7 +119,7 @@ void TaskDispatchThread::runAsync(TaskFn &&task, std::chrono::milliseconds delay
68
119
  loopCv_.notify_one();
69
120
  }
70
121
 
71
- void TaskDispatchThread::runSync(TaskFn &&task) noexcept {
122
+ void TaskDispatchThread::Impl::runSync(TaskFn &&task) noexcept {
72
123
  std::promise<void> promise;
73
124
  runAsync([&]() {
74
125
  if (running_) {
@@ -79,7 +130,7 @@ void TaskDispatchThread::runSync(TaskFn &&task) noexcept {
79
130
  promise.get_future().wait();
80
131
  }
81
132
 
82
- void TaskDispatchThread::quit() noexcept {
133
+ void TaskDispatchThread::Impl::quit() noexcept {
83
134
  if (!running_) {
84
135
  return;
85
136
  }
@@ -94,7 +145,7 @@ void TaskDispatchThread::quit() noexcept {
94
145
  }
95
146
  }
96
147
 
97
- void TaskDispatchThread::loop() noexcept {
148
+ void TaskDispatchThread::Impl::loop() noexcept {
98
149
  if (!threadName_.empty()) {
99
150
  folly::setThreadName(threadName_);
100
151
  }
@@ -11,11 +11,8 @@
11
11
  #pragma once
12
12
 
13
13
  #include <chrono>
14
- #include <condition_variable>
15
14
  #include <functional>
16
- #include <mutex>
17
- #include <queue>
18
- #include <thread>
15
+ #include <memory>
19
16
 
20
17
  namespace facebook::react {
21
18
 
@@ -47,27 +44,9 @@ class TaskDispatchThread {
47
44
  /** Shut down and clean up the thread. */
48
45
  void quit() noexcept;
49
46
 
50
- protected:
51
- struct Task {
52
- TimePoint dispatchTime;
53
- TaskFn fn;
54
-
55
- Task(TimePoint dispatchTime, TaskFn &&fn) : dispatchTime(dispatchTime), fn(std::move(fn)) {}
56
-
57
- bool operator<(const Task &other) const {
58
- // Have the earliest tasks be at the front of the queue.
59
- return dispatchTime > other.dispatchTime;
60
- }
61
- };
62
-
63
- void loop() noexcept;
64
-
65
- std::mutex queueLock_;
66
- std::condition_variable loopCv_;
67
- std::priority_queue<Task> queue_;
68
- std::atomic<bool> running_{true};
69
- std::string threadName_;
70
- std::thread thread_;
47
+ private:
48
+ class Impl;
49
+ std::shared_ptr<Impl> impl_;
71
50
  };
72
51
 
73
52
  } // namespace facebook::react
@@ -479,7 +479,7 @@ facebook::jsi::JSError const &jsError) { \
479
479
  }();
480
480
  )JS");
481
481
  // TODO: consider implementing this script as a resource file and loading it with the resource URL.
482
- jsiRuntime->evaluateJavaScript(jsiPalBuffer, "Form_JSI_API_not_a_real_file");
482
+ jsiRuntime->evaluateJavaScript(jsiPalBuffer, "jsi-internal://host-function-manager.js");
483
483
  ReactNative::JsiRuntime abiJsiResult{make<JsiRuntime>(Mso::Copy(jsiRuntimeHolder), Mso::Copy(jsiRuntime))};
484
484
  std::scoped_lock lock{s_mutex};
485
485
  auto it = s_jsiRuntimeMap.try_emplace(reinterpret_cast<uintptr_t>(jsiRuntime.get()), abiJsiResult);
@@ -268,6 +268,7 @@
268
268
  <SubType>Code</SubType>
269
269
  </ClInclude>
270
270
  <ClInclude Include="ReactHost\AsyncActionQueue.h" />
271
+ <ClInclude Include="ReactHost\DebuggerNotifications.h" />
271
272
  <ClInclude Include="ReactHost\InstanceFactory.h" />
272
273
  <ClInclude Include="ReactHost\IReactInstanceInternal.h" />
273
274
  <ClInclude Include="ReactHost\JSBundle.h" />
@@ -313,6 +313,9 @@
313
313
  <ClInclude Include="ReactHost\AsyncActionQueue.h">
314
314
  <Filter>ReactHost</Filter>
315
315
  </ClInclude>
316
+ <ClInclude Include="ReactHost\DebuggerNotifications.h">
317
+ <Filter>ReactHost</Filter>
318
+ </ClInclude>
316
319
  <ClInclude Include="ReactHost\InstanceFactory.h">
317
320
  <Filter>ReactHost</Filter>
318
321
  </ClInclude>
@@ -0,0 +1,54 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include <winrt/Microsoft.ReactNative.h>
7
+
8
+ namespace Microsoft::ReactNative {
9
+
10
+ struct DebuggerNotifications {
11
+ static winrt::Microsoft::ReactNative::IReactPropertyName ShowDebuggerPausedOverlayEventName() noexcept {
12
+ static winrt::Microsoft::ReactNative::IReactPropertyName propertyName{
13
+ winrt::Microsoft::ReactNative::ReactPropertyBagHelper::GetName(
14
+ winrt::Microsoft::ReactNative::ReactPropertyBagHelper::GetNamespace(L"ReactNative.Debugger"),
15
+ L"ShowDebuggerPausedOverlay")};
16
+ return propertyName;
17
+ }
18
+
19
+ static void OnShowDebuggerPausedOverlay(
20
+ winrt::Microsoft::ReactNative::IReactNotificationService const &service,
21
+ std::string message,
22
+ std::function<void()> onResume) {
23
+ const winrt::Microsoft::ReactNative::ReactNonAbiValue<std::tuple<std::string, std::function<void()>>> nonAbiValue{
24
+ std::in_place, std::tie(message, onResume)};
25
+ service.SendNotification(ShowDebuggerPausedOverlayEventName(), nullptr, nonAbiValue);
26
+ }
27
+
28
+ static void OnHideDebuggerPausedOverlay(winrt::Microsoft::ReactNative::IReactNotificationService const &service) {
29
+ service.SendNotification(ShowDebuggerPausedOverlayEventName(), nullptr, nullptr);
30
+ }
31
+
32
+ static winrt::Microsoft::ReactNative::IReactNotificationSubscription SubscribeShowDebuggerPausedOverlay(
33
+ winrt::Microsoft::ReactNative::IReactNotificationService const &service,
34
+ winrt::Microsoft::ReactNative::IReactDispatcher const &dispatcher,
35
+ std::function<void(std::string, std::function<void()>)> showCallback,
36
+ std::function<void()> hideCallback) {
37
+ return service.Subscribe(
38
+ ShowDebuggerPausedOverlayEventName(),
39
+ dispatcher,
40
+ [showCallback, hideCallback](auto &&, winrt::Microsoft::ReactNative::IReactNotificationArgs const &args) {
41
+ if (args.Data()) {
42
+ const auto [message, onResume] = args.Data()
43
+ .as<winrt::Microsoft::ReactNative::ReactNonAbiValue<
44
+ std::tuple<std::string, std::function<void()>>>>()
45
+ .Value();
46
+ showCallback(message, onResume);
47
+ } else {
48
+ hideCallback();
49
+ }
50
+ });
51
+ }
52
+ };
53
+
54
+ } // namespace Microsoft::ReactNative
@@ -33,6 +33,10 @@
33
33
  #include <Fabric/Composition/UriImageManager.h>
34
34
  #endif
35
35
 
36
+ namespace facebook::react::jsinspector_modern {
37
+ class HostTarget;
38
+ } // namespace facebook::react::jsinspector_modern
39
+
36
40
  namespace Mso::React {
37
41
 
38
42
  // Forward declarations
@@ -216,9 +220,9 @@ struct ReactOptions {
216
220
  //! Base path of the SDX. The absolute path of the SDX can be constructed from this and the Identity.
217
221
  std::string BundleRootPath;
218
222
 
219
- //! Javascript Bundles
220
- //! This List includes both Platform and User Javascript Bundles
221
- //! Bundles are loaded into Javascript engine in the same order
223
+ //! JavaScript Bundles
224
+ //! This List includes both Platform and User JavaScript Bundles
225
+ //! Bundles are loaded into JavaScript engine in the same order
222
226
  //! as they are specified in this list.
223
227
  std::vector<Mso::CntPtr<IJSBundle>> JSBundles;
224
228
 
@@ -237,7 +241,7 @@ struct ReactOptions {
237
241
  //! during development to report JavaScript errors to users
238
242
  std::shared_ptr<Mso::React::IRedBoxHandler> RedBoxHandler;
239
243
 
240
- //! Flag to suggest sdx owner's preference on enabling Bytecode caching in Javascript Engine for corresponding SDX.
244
+ //! Flag to suggest sdx owner's preference on enabling Bytecode caching in JavaScript Engine for corresponding SDX.
241
245
  bool EnableBytecode{true};
242
246
 
243
247
  //! Flag controlling whether the JavaScript engine uses JIT compilation.
@@ -347,6 +351,9 @@ struct ReactOptions {
347
351
  //! The callback is called when IReactInstance is destroyed and must not be used anymore.
348
352
  //! It is called from the native queue.
349
353
  OnReactInstanceDestroyedCallback OnInstanceDestroyed;
354
+
355
+ //! The HostTarget instance for modern inspector integration.
356
+ facebook::react::jsinspector_modern::HostTarget *InspectorHostTarget;
350
357
  };
351
358
 
352
359
  //! IReactHost manages a ReactNative instance.
@@ -8,9 +8,16 @@
8
8
 
9
9
  #include <CppRuntimeOptions.h>
10
10
 
11
+ #include <jsinspector-modern/HostCommand.h>
12
+ #include <jsinspector-modern/InspectorFlags.h>
11
13
  #include <react/featureflags/ReactNativeFeatureFlags.h>
12
14
  #include <react/featureflags/ReactNativeFeatureFlagsDefaults.h>
13
15
 
16
+ #include "Inspector/ReactInspectorThread.h"
17
+ #include "ReactHost/DebuggerNotifications.h"
18
+
19
+ using namespace facebook::react;
20
+
14
21
  namespace Mso::React {
15
22
 
16
23
  //=============================================================================================
@@ -282,6 +289,10 @@ bool ReactOptions::EnableDefaultCrashHandler() const noexcept {
282
289
  return winrt::unbox_value_or<bool>(properties.Get(EnableDefaultCrashHandlerProperty()), false);
283
290
  }
284
291
 
292
+ //=============================================================================================
293
+ // ReactNativeWindowsFeatureFlags implementation
294
+ //=============================================================================================
295
+
285
296
  class ReactNativeWindowsFeatureFlags : public facebook::react::ReactNativeFeatureFlagsDefaults {
286
297
  public:
287
298
  bool enableBridgelessArchitecture() override {
@@ -295,9 +306,77 @@ class ReactNativeWindowsFeatureFlags : public facebook::react::ReactNativeFeatur
295
306
  bool enableCppPropsIteratorSetter() override {
296
307
  return true;
297
308
  }
309
+
310
+ bool fuseboxEnabledRelease() override {
311
+ return true; // Enable Fusebox (modern CDP backend) by default for React Native Windows
312
+ }
313
+ };
314
+
315
+ //=============================================================================================
316
+ // ReactInspectorHostTargetDelegate implementation
317
+ //=============================================================================================
318
+
319
+ class ReactInspectorHostTargetDelegate : public jsinspector_modern::HostTargetDelegate,
320
+ public std::enable_shared_from_this<ReactInspectorHostTargetDelegate> {
321
+ public:
322
+ ReactInspectorHostTargetDelegate(Mso::WeakPtr<ReactHost> &&reactHost) noexcept : m_reactHost(std::move(reactHost)) {}
323
+
324
+ jsinspector_modern::HostTargetMetadata getMetadata() override {
325
+ jsinspector_modern::HostTargetMetadata metadata{};
326
+ metadata.integrationName = "React Native Windows (Host)";
327
+ metadata.platform = "windows";
328
+
329
+ if (Mso::CntPtr<ReactHost> reactHost = m_reactHost.GetStrongPtr()) {
330
+ const ReactOptions &options = reactHost->Options();
331
+ if (!options.Identity.empty()) {
332
+ std::string identity = options.Identity;
333
+ // Replace illegal characters with underscore
334
+ for (char &c : identity) {
335
+ if (c == '\\' || c == '/' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' ||
336
+ c == '|') {
337
+ c = '_';
338
+ }
339
+ }
340
+ metadata.appDisplayName = identity;
341
+ }
342
+ }
343
+
344
+ wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
345
+ DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
346
+ if (GetComputerNameW(computerName, &size)) {
347
+ metadata.deviceName = winrt::to_string(computerName);
348
+ }
349
+
350
+ return metadata;
351
+ }
352
+
353
+ void onReload(jsinspector_modern::HostTargetDelegate::PageReloadRequest const &request) override {
354
+ if (Mso::CntPtr<ReactHost> reactHost = m_reactHost.GetStrongPtr()) {
355
+ reactHost->ReloadInstance();
356
+ }
357
+ }
358
+
359
+ void onSetPausedInDebuggerMessage(
360
+ jsinspector_modern::HostTargetDelegate::OverlaySetPausedInDebuggerMessageRequest const &request) override {
361
+ if (Mso::CntPtr<ReactHost> reactHost = m_reactHost.GetStrongPtr()) {
362
+ auto notifications = reactHost->Options().Notifications;
363
+ if (request.message.has_value()) {
364
+ ::Microsoft::ReactNative::DebuggerNotifications::OnShowDebuggerPausedOverlay(
365
+ notifications, request.message.value(), [weakReactHost = m_reactHost]() {
366
+ if (Mso::CntPtr<ReactHost> strongReactHost = weakReactHost.GetStrongPtr()) {
367
+ strongReactHost->OnDebuggerResume();
368
+ }
369
+ });
370
+ } else {
371
+ ::Microsoft::ReactNative::DebuggerNotifications::OnHideDebuggerPausedOverlay(notifications);
372
+ }
373
+ }
374
+ }
375
+
376
+ private:
377
+ Mso::WeakPtr<ReactHost> m_reactHost;
298
378
  };
299
379
 
300
- std::once_flag g_FlagInitFeatureFlags;
301
380
  //=============================================================================================
302
381
  // ReactHost implementation
303
382
  //=============================================================================================
@@ -305,9 +384,16 @@ std::once_flag g_FlagInitFeatureFlags;
305
384
  ReactHost::ReactHost(Mso::DispatchQueue const &queue) noexcept
306
385
  : Super{EnsureSerialQueue(queue)},
307
386
  m_options{Queue(), m_mutex},
308
- m_notifyWhenClosed{ReactHostRegistry::Register(*this), Queue(), m_mutex} {
309
- std::call_once(g_FlagInitFeatureFlags, []() noexcept {
310
- facebook::react::ReactNativeFeatureFlags::override(std::make_unique<ReactNativeWindowsFeatureFlags>());
387
+ m_notifyWhenClosed{ReactHostRegistry::Register(*this), Queue(), m_mutex},
388
+ m_inspectorHostTargetDelegate{std::make_shared<ReactInspectorHostTargetDelegate>(this)},
389
+ m_inspectorHostTarget{
390
+ jsinspector_modern::HostTarget::create(*m_inspectorHostTargetDelegate, [](std::function<void()> &&callback) {
391
+ ::Microsoft::ReactNative::ReactInspectorThread::Instance().Post(
392
+ [callback = std::move(callback)]() { callback(); });
393
+ })} {
394
+ static std::once_flag initFeatureFlagsOnce;
395
+ std::call_once(initFeatureFlagsOnce, []() noexcept {
396
+ ReactNativeFeatureFlags::override(std::make_unique<ReactNativeWindowsFeatureFlags>());
311
397
  });
312
398
  }
313
399
 
@@ -319,15 +405,16 @@ void ReactHost::Finalize() noexcept {
319
405
  // Since each AsyncAction has a strong ref count to ReactHost, the AsyncActionQueue must be empty.
320
406
  // Thus, we only need to call UnloadInQueue to unload ReactInstance if the ReactHost is not closed yet.
321
407
  if (Mso::Promise<void> notifyWhenClosed = m_notifyWhenClosed.Exchange(nullptr)) {
322
- UnloadInQueue(0).Then<Mso::Executors::Inline>(
323
- [notifyWhenClosed = std::move(notifyWhenClosed)]() noexcept { notifyWhenClosed.TrySetValue(); });
408
+ UnloadInQueue(UnloadReason::CloseHost, 0)
409
+ .Then<Mso::Executors::Inline>(
410
+ [notifyWhenClosed = std::move(notifyWhenClosed)]() noexcept { notifyWhenClosed.TrySetValue(); });
324
411
  }
325
412
  }
326
413
 
327
414
  void ReactHost::Close() noexcept {
328
415
  InvokeInQueue([this]() noexcept {
329
416
  // Put the ReactHost to the closed state, unload ReactInstance, and notify the closing Promise.
330
- auto whenClosed = m_actionQueue.Load()->PostAction(MakeUnloadInstanceAction());
417
+ auto whenClosed = m_actionQueue.Load()->PostAction(MakeUnloadInstanceAction(UnloadReason::CloseHost));
331
418
 
332
419
  // After we set the m_notifyWhenClosed to null, the ReactHost is considered to be closed.
333
420
  Mso::SetPromiseValue(m_notifyWhenClosed.Exchange(nullptr), std::move(whenClosed));
@@ -379,12 +466,14 @@ Mso::Future<void> ReactHost::ReloadInstance() noexcept {
379
466
 
380
467
  Mso::Future<void> ReactHost::ReloadInstanceWithOptions(ReactOptions &&options) noexcept {
381
468
  return PostInQueue([this, options = std::move(options)]() mutable noexcept {
382
- return m_actionQueue.Load()->PostActions({MakeUnloadInstanceAction(), MakeLoadInstanceAction(std::move(options))});
469
+ return m_actionQueue.Load()->PostActions(
470
+ {MakeUnloadInstanceAction(UnloadReason::Unload), MakeLoadInstanceAction(std::move(options))});
383
471
  });
384
472
  }
385
473
 
386
474
  Mso::Future<void> ReactHost::UnloadInstance() noexcept {
387
- return PostInQueue([this]() noexcept { return m_actionQueue.Load()->PostAction(MakeUnloadInstanceAction()); });
475
+ return PostInQueue(
476
+ [this]() noexcept { return m_actionQueue.Load()->PostAction(MakeUnloadInstanceAction(UnloadReason::Unload)); });
388
477
  }
389
478
 
390
479
  AsyncAction ReactHost::MakeLoadInstanceAction(ReactOptions &&options) noexcept {
@@ -393,11 +482,13 @@ AsyncAction ReactHost::MakeLoadInstanceAction(ReactOptions &&options) noexcept {
393
482
  };
394
483
  }
395
484
 
396
- AsyncAction ReactHost::MakeUnloadInstanceAction() noexcept {
485
+ AsyncAction ReactHost::MakeUnloadInstanceAction(UnloadReason reason) noexcept {
397
486
  Mso::Internal::VerifyIsInQueueElseCrash(Queue());
398
487
  size_t unloadActionId = ++m_nextUnloadActionId;
399
488
  m_pendingUnloadActionId = unloadActionId;
400
- return [spThis = Mso::CntPtr{this}, unloadActionId]() noexcept { return spThis->UnloadInQueue(unloadActionId); };
489
+ return [spThis = Mso::CntPtr{this}, reason, unloadActionId]() noexcept {
490
+ return spThis->UnloadInQueue(reason, unloadActionId);
491
+ };
401
492
  }
402
493
 
403
494
  Mso::CntPtr<IReactViewHost> ReactHost::MakeViewHost(ReactViewOptions &&options) noexcept {
@@ -428,6 +519,18 @@ Mso::Future<void> ReactHost::LoadInQueue(ReactOptions &&options) noexcept {
428
519
  return Mso::MakeCanceledFuture();
429
520
  }
430
521
 
522
+ // Start or stop inspector page if needed.
523
+ // Make sure to update the both copies of options.
524
+ if (IsInspectable()) {
525
+ AddInspectorPage();
526
+ options.InspectorHostTarget = m_inspectorHostTarget.get();
527
+ m_options.Load().InspectorHostTarget = m_inspectorHostTarget.get();
528
+ } else {
529
+ RemoveInspectorPage();
530
+ options.InspectorHostTarget = nullptr;
531
+ m_options.Load().InspectorHostTarget = nullptr;
532
+ }
533
+
431
534
  Mso::Promise<void> whenCreated;
432
535
  Mso::Promise<void> whenLoaded;
433
536
 
@@ -463,7 +566,7 @@ Mso::Future<void> ReactHost::LoadInQueue(ReactOptions &&options) noexcept {
463
566
  });
464
567
  }
465
568
 
466
- Mso::Future<void> ReactHost::UnloadInQueue(size_t unloadActionId) noexcept {
569
+ Mso::Future<void> ReactHost::UnloadInQueue(UnloadReason reason, size_t unloadActionId) noexcept {
467
570
  Mso::Internal::VerifyIsInQueueElseCrash(Queue());
468
571
 
469
572
  // If the pending unload action Id does not match, then we have newer unload action,
@@ -485,21 +588,25 @@ Mso::Future<void> ReactHost::UnloadInQueue(size_t unloadActionId) noexcept {
485
588
 
486
589
  // We unload ReactInstance after all view instances are unloaded.
487
590
  // It is safe to capture 'this' because the Unload action keeps a strong reference to ReactHost.
488
- return Mso::WhenAllCompleted(unloadCompletionList).Then(m_executor, [this](Mso::Maybe<void> && /*value*/) noexcept {
489
- Mso::Future<void> onUnloaded;
490
- if (auto reactInstance = m_reactInstance.Exchange(nullptr)) {
491
- onUnloaded = reactInstance->Destroy();
492
- }
493
-
494
- m_isInstanceUnloading.Store(false);
495
- m_lastError.Store({});
496
-
497
- if (!onUnloaded) {
498
- onUnloaded = Mso::MakeSucceededFuture();
499
- }
500
-
501
- return onUnloaded;
502
- });
591
+ return Mso::WhenAllCompleted(unloadCompletionList)
592
+ .Then(m_executor, [this, reason](Mso::Maybe<void> && /*value*/) noexcept {
593
+ Mso::Future<void> onUnloaded;
594
+ if (auto reactInstance = m_reactInstance.Exchange(nullptr)) {
595
+ onUnloaded = reactInstance->Destroy();
596
+ }
597
+
598
+ m_isInstanceUnloading.Store(false);
599
+ m_lastError.Store({});
600
+
601
+ if (!onUnloaded) {
602
+ onUnloaded = Mso::MakeSucceededFuture();
603
+ }
604
+
605
+ if (reason == UnloadReason::CloseHost) {
606
+ RemoveInspectorPage();
607
+ }
608
+ return onUnloaded;
609
+ });
503
610
  }
504
611
 
505
612
  void ReactHost::ForEachViewHost(const Mso::FunctorRef<void(ReactViewHost &)> &action) noexcept {
@@ -528,6 +635,65 @@ void ReactHost::DetachViewHost(ReactViewHost &viewHost) noexcept {
528
635
  viewHosts.erase(it);
529
636
  }
530
637
 
638
+ bool ReactHost::IsInspectable() noexcept {
639
+ ReactOptions &options = m_options.Load();
640
+ return options.JsiEngine() == JSIEngine::Hermes && options.UseDirectDebugger();
641
+ }
642
+
643
+ void ReactHost::AddInspectorPage() noexcept {
644
+ std::optional<int32_t> &inspectorPageId = m_inspectorPageId.Load();
645
+ if (inspectorPageId.has_value())
646
+ return;
647
+
648
+ jsinspector_modern::InspectorTargetCapabilities capabilities;
649
+ capabilities.nativePageReloads = true;
650
+ capabilities.prefersFuseboxFrontend = true;
651
+
652
+ auto metadata = m_inspectorHostTargetDelegate->getMetadata();
653
+ std::string pageName;
654
+ if (metadata.appDisplayName.has_value() && !metadata.appDisplayName.value().empty()) {
655
+ pageName = metadata.appDisplayName.value();
656
+ } else {
657
+ pageName = "React Native Windows (Experimental)";
658
+ }
659
+ if (metadata.deviceName.has_value() && !metadata.deviceName.value().empty()) {
660
+ pageName += " (" + metadata.deviceName.value() + ")";
661
+ }
662
+
663
+ inspectorPageId = jsinspector_modern::getInspectorInstance().addPage(
664
+ pageName,
665
+ "Hermes",
666
+ [weakInspectorHostTarget =
667
+ std::weak_ptr(m_inspectorHostTarget)](std::unique_ptr<jsinspector_modern::IRemoteConnection> remote)
668
+ -> std::unique_ptr<jsinspector_modern::ILocalConnection> {
669
+ if (std::shared_ptr<jsinspector_modern::HostTarget> inspectorHostTarget = weakInspectorHostTarget.lock()) {
670
+ return inspectorHostTarget->connect(std::move(remote));
671
+ }
672
+
673
+ // This can happen if we're about to shut down. Reject the connection.
674
+ return nullptr;
675
+ },
676
+ capabilities);
677
+ }
678
+
679
+ void ReactHost::RemoveInspectorPage() noexcept {
680
+ std::optional<int32_t> &inspectorPageId = m_inspectorPageId.Load();
681
+ if (!inspectorPageId.has_value())
682
+ return;
683
+
684
+ jsinspector_modern::getInspectorInstance().removePage(*inspectorPageId);
685
+ inspectorPageId.reset();
686
+ }
687
+
688
+ void ReactHost::OnDebuggerResume() noexcept {
689
+ ::Microsoft::ReactNative::ReactInspectorThread::Instance().Post(
690
+ [weakInspectorHostTarget = std::weak_ptr(m_inspectorHostTarget)]() {
691
+ if (std::shared_ptr<jsinspector_modern::HostTarget> inspectorHostTarget = weakInspectorHostTarget.lock()) {
692
+ inspectorHostTarget->sendCommand(jsinspector_modern::HostCommand::DebuggerResume);
693
+ }
694
+ });
695
+ }
696
+
531
697
  //=============================================================================================
532
698
  // ReactViewHost implementation
533
699
  //=============================================================================================
@@ -579,8 +745,8 @@ Mso::Future<void> ReactViewHost::AttachViewInstance(IReactViewInstance &viewInst
579
745
  m_reactHost->AttachViewHost(*this);
580
746
 
581
747
  return InitViewInstanceInQueue();
582
- //// Schedule the viewInstance load in the action queue since there can be other load actions in the queue that need
583
- //// to be consolidated.
748
+ // Schedule the viewInstance load in the action queue since there can be other load actions in the queue that need
749
+ // to be consolidated.
584
750
  // return m_actionQueue.Load()->PostAction(MakeInitViewInstanceAction());
585
751
  });
586
752
  }