File tree Expand file tree Collapse file tree 5 files changed +92
-1
lines changed
ReactCommon/jsinspector-modern Expand file tree Collapse file tree 5 files changed +92
-1
lines changed Original file line number Diff line number Diff line change @@ -229,10 +229,15 @@ Error: ${e.message}`;
229229 }
230230 } ) ;
231231
232- client . on ( 'update-done' , ( ) => {
232+ client . on ( 'update-done' , body => {
233233 pendingUpdatesCount -- ;
234234 if ( pendingUpdatesCount === 0 ) {
235235 DevLoadingView . hide ( ) ;
236+ const changeId = body ?. changeId ;
237+ if ( changeId != null && changeId !== lastMarkerChangeId ) {
238+ lastMarkerChangeId = changeId ;
239+ emitFastRefreshCompleteEvents ( ) ;
240+ }
236241 }
237242 } ) ;
238243
@@ -378,4 +383,25 @@ function showCompileError() {
378383 throw error ;
379384}
380385
386+ function emitFastRefreshCompleteEvents ( ) {
387+ // Add marker entry in performance timeline
388+ performance . mark ( 'Fast Refresh - Update done' , {
389+ detail : {
390+ devtools : {
391+ dataType : 'marker' ,
392+ color : 'primary' ,
393+ tooltipText : 'Fast Refresh \u269b' ,
394+ } ,
395+ } ,
396+ } ) ;
397+
398+ // Notify CDP clients via internal binding
399+ if (
400+ // $FlowFixMe[prop-missing] - Injected by RuntimeTarget
401+ typeof globalThis . __notifyFastRefreshComplete === 'function'
402+ ) {
403+ globalThis . __notifyFastRefreshComplete ( ) ;
404+ }
405+ }
406+
381407export default HMRClient ;
Original file line number Diff line number Diff line change 88#include " RuntimeAgent.h"
99#include " SessionState.h"
1010
11+ #include < folly/dynamic.h>
12+ #include < jsinspector-modern/cdp/CdpJson.h>
13+
14+ #include < chrono>
1115#include < utility>
1216
1317namespace facebook ::react::jsinspector_modern {
@@ -119,6 +123,21 @@ void RuntimeAgent::notifyBindingCalled(
119123 " name" , bindingName)(" payload" , payload)));
120124}
121125
126+ void RuntimeAgent::notifyFastRefreshComplete () {
127+ if (!sessionState_.isReactNativeApplicationDomainEnabled ) {
128+ return ;
129+ }
130+ folly::dynamic params = folly::dynamic::object (
131+ " timestamp" ,
132+ std::chrono::duration_cast<std::chrono::milliseconds>(
133+ std::chrono::system_clock::now ().time_since_epoch ())
134+ .count ());
135+ frontendChannel_ (
136+ cdp::jsonNotification (
137+ " ReactNativeApplication.unstable_fastRefreshComplete" ,
138+ std::move (params)));
139+ }
140+
122141RuntimeAgent::ExportedState RuntimeAgent::getExportedState () {
123142 return {
124143 .delegateState = delegate_ ? delegate_->getExportedState () : nullptr ,
Original file line number Diff line number Diff line change @@ -72,6 +72,13 @@ class RuntimeAgent final {
7272
7373 void notifyBindingCalled (const std::string &bindingName, const std::string &payload);
7474
75+ /* *
76+ * Called by RuntimeTarget when JS calls __notifyFastRefreshComplete().
77+ * Emits a ReactNativeApplication.unstable_fastRefreshComplete CDP
78+ * notification if the ReactNativeApplication domain is enabled.
79+ */
80+ void notifyFastRefreshComplete ();
81+
7582 struct ExportedState {
7683 std::unique_ptr<RuntimeAgentDelegate::ExportedState> delegateState;
7784 };
Original file line number Diff line number Diff line change @@ -60,6 +60,8 @@ void RuntimeTarget::installGlobals() {
6060 // NOTE: RuntimeTarget::installNetworkReporterAPI is in
6161 // RuntimeTargetNetwork.cpp
6262 installNetworkReporterAPI ();
63+
64+ installFastRefreshHandler ();
6365}
6466
6567std::shared_ptr<RuntimeAgent> RuntimeTarget::createAgent (
@@ -141,6 +143,37 @@ void RuntimeTarget::installBindingHandler(const std::string& bindingName) {
141143 });
142144}
143145
146+ void RuntimeTarget::installFastRefreshHandler () {
147+ jsExecutor_ ([selfExecutor = executorFromThis ()](jsi::Runtime& runtime) {
148+ auto globalObj = runtime.global ();
149+ try {
150+ auto name =
151+ jsi::PropNameID::forUtf8 (runtime, " __notifyFastRefreshComplete" );
152+ globalObj.setProperty (
153+ runtime,
154+ name,
155+ jsi::Function::createFromHostFunction (
156+ runtime,
157+ name,
158+ 0 ,
159+ [selfExecutor](
160+ jsi::Runtime& /* rt*/ ,
161+ const jsi::Value&,
162+ const jsi::Value*,
163+ size_t ) -> jsi::Value {
164+ selfExecutor ([](auto & self) {
165+ self.agents_ .forEach (
166+ [](auto & agent) { agent.notifyFastRefreshComplete (); });
167+ });
168+
169+ return jsi::Value::undefined ();
170+ }));
171+ } catch (jsi::JSError&) {
172+ // Swallow JavaScript exceptions that occur while setting up the global.
173+ }
174+ });
175+ }
176+
144177void RuntimeTarget::emitDebuggerSessionCreated () {
145178 jsExecutor_ ([selfExecutor = executorFromThis ()](jsi::Runtime& runtime) {
146179 try {
Original file line number Diff line number Diff line change @@ -289,6 +289,12 @@ class JSINSPECTOR_EXPORT RuntimeTarget : public EnableExecutorFromThis<RuntimeTa
289289 */
290290 void installGlobals ();
291291
292+ /* *
293+ * Installs __notifyFastRefreshComplete on the runtime's global object.
294+ * When called from JS, dispatches to all connected RuntimeAgents.
295+ */
296+ void installFastRefreshHandler ();
297+
292298 /* *
293299 * Install the console API handler.
294300 */
You can’t perform that action at this time.
0 commit comments