Skip to content

Commit 5d09e43

Browse files
authored
[0.83] Add unstable_fastRefreshComplete CDP event (#56399)
* Update Metro to 0.83.6 * Add unstable_fastRefreshComplete CDP event (#56273) Summary: Pull Request resolved: #56273 Adds a new, experimental `ReactNativeApplication.unstable_fastRefreshComplete` CDP event, emitted to subscribed active CDP sessions when a Fast Refresh update completes. **Notes** - As with D97486551, we reuse the `changeId` block in `HMRClient.js`, ensuring duplicate updates for the same change are not reported. Changelog: [Internal] Reviewed By: GijsWeterings, hoxyq Differential Revision: D98493216 fbshipit-source-id: b0b81a210fb84873e9358aa5484038062f110103
1 parent efc4cf4 commit 5d09e43

10 files changed

Lines changed: 323 additions & 138 deletions

File tree

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@
101101
"markdownlint-cli2": "^0.17.2",
102102
"markdownlint-rule-relative-links": "^3.0.0",
103103
"memfs": "^4.38.2",
104-
"metro-babel-register": "^0.83.3",
105-
"metro-transform-plugins": "^0.83.3",
104+
"metro-babel-register": "^0.83.6",
105+
"metro-transform-plugins": "^0.83.6",
106106
"micromatch": "^4.0.4",
107107
"node-fetch": "^2.2.0",
108108
"nullthrows": "^1.1.1",

packages/community-cli-plugin/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
"@react-native/dev-middleware": "0.83.5",
2626
"debug": "^4.4.0",
2727
"invariant": "^2.2.4",
28-
"metro": "^0.83.3",
29-
"metro-config": "^0.83.3",
30-
"metro-core": "^0.83.3",
28+
"metro": "^0.83.6",
29+
"metro-config": "^0.83.6",
30+
"metro-core": "^0.83.6",
3131
"semver": "^7.1.3"
3232
},
3333
"devDependencies": {
34-
"metro-resolver": "^0.83.3"
34+
"metro-resolver": "^0.83.6"
3535
},
3636
"peerDependencies": {
3737
"@react-native-community/cli": "*",

packages/metro-config/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"dependencies": {
2929
"@react-native/js-polyfills": "0.83.5",
3030
"@react-native/metro-babel-transformer": "0.83.5",
31-
"metro-config": "^0.83.3",
32-
"metro-runtime": "^0.83.3"
31+
"metro-config": "^0.83.6",
32+
"metro-runtime": "^0.83.6"
3333
}
3434
}

packages/react-native/Libraries/Utilities/HMRClient.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ let hmrUnavailableReason: string | null = null;
2626
let hmrOrigin: string | null = null;
2727
let currentCompileErrorMessage: string | null = null;
2828
let didConnect: boolean = false;
29+
let lastMarkerChangeId: ?string = null;
2930
let pendingLogs: Array<[LogLevel, $ReadOnlyArray<mixed>]> = [];
3031

3132
type LogLevel =
@@ -229,10 +230,15 @@ Error: ${e.message}`;
229230
}
230231
});
231232

232-
client.on('update-done', () => {
233+
client.on('update-done', body => {
233234
pendingUpdatesCount--;
234235
if (pendingUpdatesCount === 0) {
235236
DevLoadingView.hide();
237+
const changeId = body?.changeId;
238+
if (changeId != null && changeId !== lastMarkerChangeId) {
239+
lastMarkerChangeId = changeId;
240+
emitFastRefreshCompleteEvents();
241+
}
236242
}
237243
});
238244

@@ -378,4 +384,25 @@ function showCompileError() {
378384
throw error;
379385
}
380386

387+
function emitFastRefreshCompleteEvents() {
388+
// Add marker entry in performance timeline
389+
performance.mark('Fast Refresh - Update done', {
390+
detail: {
391+
devtools: {
392+
dataType: 'marker',
393+
color: 'primary',
394+
tooltipText: 'Fast Refresh \u269b',
395+
},
396+
},
397+
});
398+
399+
// Notify CDP clients via internal binding
400+
if (
401+
// $FlowFixMe[prop-missing] - Injected by RuntimeTarget
402+
typeof globalThis.__notifyFastRefreshComplete === 'function'
403+
) {
404+
globalThis.__notifyFastRefreshComplete();
405+
}
406+
}
407+
381408
export default HMRClient;

packages/react-native/ReactCommon/jsinspector-modern/RuntimeAgent.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
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

1317
namespace 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+
122141
RuntimeAgent::ExportedState RuntimeAgent::getExportedState() {
123142
return {
124143
.delegateState = delegate_ ? delegate_->getExportedState() : nullptr,

packages/react-native/ReactCommon/jsinspector-modern/RuntimeAgent.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff 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
};

packages/react-native/ReactCommon/jsinspector-modern/RuntimeTarget.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff 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

6567
std::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+
144177
void RuntimeTarget::emitDebuggerSessionCreated() {
145178
jsExecutor_([selfExecutor = executorFromThis()](jsi::Runtime& runtime) {
146179
try {

packages/react-native/ReactCommon/jsinspector-modern/RuntimeTarget.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff 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
*/

packages/react-native/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@
180180
"invariant": "^2.2.4",
181181
"jest-environment-node": "^29.7.0",
182182
"memoize-one": "^5.0.0",
183-
"metro-runtime": "^0.83.3",
184-
"metro-source-map": "^0.83.3",
183+
"metro-runtime": "^0.83.6",
184+
"metro-source-map": "^0.83.6",
185185
"nullthrows": "^1.1.1",
186186
"pretty-format": "^29.7.0",
187187
"promise": "^8.3.0",

0 commit comments

Comments
 (0)