Skip to content

Commit

Permalink
Fusebox reload-to-profile (#46856)
Browse files Browse the repository at this point in the history
Summary:

Changelog:
[General][Added] - Add support for reload-to-profile in Fusebox.

CDT: facebookexperimental/rn-chrome-devtools-frontend#117
React: facebook/react#31021

This diff adds support for reload2profile under bridge and bridgeless for iOS, Android, and C++

Differential Revision: D63233256
  • Loading branch information
EdmondChuiHW authored and facebook-github-bot committed Oct 8, 2024
1 parent 40a4feb commit 9ece2c7
Show file tree
Hide file tree
Showing 17 changed files with 414 additions and 1 deletion.
40 changes: 39 additions & 1 deletion packages/react-native/Libraries/Core/setUpReactDevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
'use strict';

import type {Domain} from '../../src/private/debugging/setUpFuseboxReactDevToolsDispatcher';
import type {
PartialReloadAndProfileConfig,
Spec as NativeReactDevToolsRuntimeSettingsModuleSpec,
} from '../../src/private/fusebox/specs/NativeReactDevToolsRuntimeSettingsModule';

if (__DEV__) {
// Register dispatcher on global, which can be used later by Chrome DevTools frontend
Expand All @@ -24,6 +28,8 @@ if (__DEV__) {
const reactDevToolsSettingsManager = require('../../src/private/debugging/ReactDevToolsSettingsManager');
const serializedHookSettings =
reactDevToolsSettingsManager.getGlobalHookSettings();
const maybeReactDevToolsRuntimeSettingsModuleModule =
require('../../src/private/fusebox/specs/NativeReactDevToolsRuntimeSettingsModule').default;

let hookSettings = null;
if (serializedHookSettings != null) {
Expand All @@ -36,8 +42,17 @@ if (__DEV__) {
);
}
}

const reloadAndProfileConfigPersistence =
makeReloadAndProfileConfigPersistence(
maybeReactDevToolsRuntimeSettingsModuleModule,
);

// Install hook before React is loaded.
initialize(hookSettings);
initialize(
hookSettings,
reloadAndProfileConfigPersistence?.getReloadAndProfileConfig(),
);

// This should be defined in DEV, otherwise error is expected.
const fuseboxReactDevToolsDispatcher =
Expand Down Expand Up @@ -76,6 +91,9 @@ if (__DEV__) {
nativeStyleEditorValidAttributes: Object.keys(ReactNativeStyleAttributes),
resolveRNStyle,
onSettingsUpdated: handleReactDevToolsSettingsUpdate,
isReloadAndProfileSupported:
maybeReactDevToolsRuntimeSettingsModuleModule != null,
reloadAndProfileConfigPersistence,
});
}

Expand Down Expand Up @@ -135,6 +153,9 @@ if (__DEV__) {
),
websocket: ws,
onSettingsUpdated: handleReactDevToolsSettingsUpdate,
isReloadAndProfileSupported:
maybeReactDevToolsRuntimeSettingsModuleModule != null,
reloadAndProfileConfigPersistence,
});
}
}
Expand Down Expand Up @@ -166,3 +187,20 @@ if (__DEV__) {
);
connectToWSBasedReactDevToolsFrontend(); // Try connecting once on load
}

function makeReloadAndProfileConfigPersistence(
maybeModule: ?NativeReactDevToolsRuntimeSettingsModuleSpec,
) {
if (maybeModule == null) {
return;
}

return {
setReloadAndProfileConfig(config: PartialReloadAndProfileConfig): void {
maybeModule.setReloadAndProfileConfig(config);
},
getReloadAndProfileConfig() {
return maybeModule.getReloadAndProfileConfig();
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <Foundation/Foundation.h>

@interface RCTDevToolsRuntimeSettingsModule : NSObject

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTDevToolsRuntimeSettingsModule.h>

#import "CoreModulesPlugins.h"

struct Config {
bool shouldReloadAndProfile = false;
bool recordChangeDescriptions = false;
};

// static to persist across Turbo Module reloads
static Config _config;

@interface RCTDevToolsRuntimeSettingsModule () <NativeReactDevToolsRuntimeSettingsModuleSpec> {
}
@end

@implementation RCTDevToolsRuntimeSettingsModule
RCT_EXPORT_MODULE(ReactDevToolsRuntimeSettingsModule)

RCT_EXPORT_METHOD(setReloadAndProfileConfig
: (JS::NativeReactDevToolsRuntimeSettingsModule::PartialReloadAndProfileConfig &)config)
{
if (config.shouldReloadAndProfile().has_value()) {
_config.shouldReloadAndProfile = config.shouldReloadAndProfile().value();
}
if (config.recordChangeDescriptions().has_value()) {
_config.recordChangeDescriptions = config.recordChangeDescriptions().value();
}
}

RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(getReloadAndProfileConfig)
{
return @{
@"shouldReloadAndProfile" : @(_config.shouldReloadAndProfile),
@"recordChangeDescriptions" : @(_config.recordChangeDescriptions),
};
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeReactDevToolsRuntimeSettingsModuleSpecJSI>(params);
}

@end

Class RCTDevToolsRuntimeSettingsCls(void)
{
return RCTDevToolsRuntimeSettingsModule.class;
}
6 changes: 6 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -3373,6 +3373,12 @@ public final class com/facebook/react/modules/devloading/DevLoadingModule : com/
public final class com/facebook/react/modules/devloading/DevLoadingModule$Companion {
}

public final class com/facebook/react/modules/devtoolsruntimesettings/ReactDevToolsRuntimeSettingsModule : com/facebook/fbreact/specs/NativeReactDevToolsRuntimeSettingsModuleSpec {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
public fun getReloadAndProfileConfig ()Lcom/facebook/react/bridge/WritableMap;
public fun setReloadAndProfileConfig (Lcom/facebook/react/bridge/ReadableMap;)V
}

public class com/facebook/react/modules/dialog/AlertFragment : androidx/fragment/app/DialogFragment, android/content/DialogInterface$OnClickListener {
public fun <init> ()V
public fun <init> (Lcom/facebook/react/modules/dialog/DialogModule$AlertFragmentListener;Landroid/os/Bundle;)V
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/ReactAndroid/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ val preparePrefab by
Pair("../ReactCommon/cxxreact/", "cxxreact/"),
// react_featureflags
Pair("../ReactCommon/react/featureflags/", "react/featureflags/"),
// react_devtoolsruntimesettings
Pair(
"../ReactCommon/react/devtoolsruntimesettings/",
"react/devtoolsruntimesettings/"),
// react_render_animations
Pair(
"../ReactCommon/react/renderer/animations/",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.modules.devtoolsruntimesettings

import com.facebook.fbreact.specs.NativeReactDevToolsRuntimeSettingsModuleSpec
import com.facebook.jni.annotations.DoNotStripAny
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.WritableMap
import com.facebook.react.module.annotations.ReactModule

private class Settings {
var shouldReloadAndProfile: Boolean = false
var recordChangeDescriptions: Boolean = false
}

@DoNotStripAny
@ReactModule(name = NativeReactDevToolsRuntimeSettingsModuleSpec.NAME)
public class ReactDevToolsRuntimeSettingsModule(reactContext: ReactApplicationContext?) :
NativeReactDevToolsRuntimeSettingsModuleSpec(reactContext) {

// static to persist across Turbo Module reloads
private companion object {
private val settings = Settings()
}

override fun setReloadAndProfileConfig(map: ReadableMap) {
if (map.hasKey("shouldReloadAndProfile")) {
settings.shouldReloadAndProfile = map.getBoolean("shouldReloadAndProfile")
}
if (map.hasKey("recordChangeDescriptions")) {
settings.recordChangeDescriptions = map.getBoolean("recordChangeDescriptions")
}
}

override fun getReloadAndProfileConfig(): WritableMap {
val map = Arguments.createMap()
map.putBoolean("shouldReloadAndProfile", settings.shouldReloadAndProfile)
map.putBoolean("recordChangeDescriptions", settings.recordChangeDescriptions)
return map
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.facebook.react.modules.camera.ImageStoreManager;
import com.facebook.react.modules.clipboard.ClipboardModule;
import com.facebook.react.modules.devloading.DevLoadingModule;
import com.facebook.react.modules.devtoolsruntimesettings.ReactDevToolsRuntimeSettingsModule;
import com.facebook.react.modules.dialog.DialogModule;
import com.facebook.react.modules.fresco.FrescoModule;
import com.facebook.react.modules.i18nmanager.I18nManagerModule;
Expand Down Expand Up @@ -88,6 +89,7 @@
NetworkingModule.class,
PermissionsModule.class,
ReactDevToolsSettingsManagerModule.class,
ReactDevToolsRuntimeSettingsModule.class,
ShareModule.class,
SoundManagerModule.class,
StatusBarModule.class,
Expand Down Expand Up @@ -156,6 +158,8 @@ public MainReactPackage(MainPackageConfig config) {
return new WebSocketModule(context);
case ReactDevToolsSettingsManagerModule.NAME:
return new ReactDevToolsSettingsManagerModule(context);
case ReactDevToolsRuntimeSettingsModule.NAME:
return new ReactDevToolsRuntimeSettingsModule(context);
default:
return null;
}
Expand Down Expand Up @@ -302,6 +306,7 @@ private ReactModuleInfoProvider fallbackForMissingClass() {
NetworkingModule.class,
PermissionsModule.class,
ReactDevToolsSettingsManagerModule.class,
ReactDevToolsRuntimeSettingsModule.class,
ShareModule.class,
StatusBarModule.class,
SoundManagerModule.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)

add_compile_options(
-fexceptions
-frtti
-std=c++20
-Wall
-Wpedantic)

add_library(react_devtoolsruntimesettingscxx INTERFACE)

target_include_directories(react_devtoolsruntimesettingscxx INTERFACE .)

target_link_libraries(react_devtoolsruntimesettingscxx
jsi
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "DevToolsRuntimeSettings.h"

namespace facebook::react {

void DevToolsRuntimeSettings::setReloadAndProfileConfig(
NativePartialReloadAndProfileConfig config) {
if (config.shouldReloadAndProfile.has_value()) {
_config.shouldReloadAndProfile = config.shouldReloadAndProfile.value();
}
if (config.shouldReloadAndProfile.has_value()) {
_config.recordChangeDescriptions = config.recordChangeDescriptions.value();
}
};

NativeReloadAndProfileConfig
DevToolsRuntimeSettings::getReloadAndProfileConfig() const {
return _config;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>

namespace facebook::react {

using NativePartialReloadAndProfileConfig =
NativeReactDevToolsRuntimeSettingsModulePartialReloadAndProfileConfig<
std::optional<bool>,
std::optional<bool>>;

template <>
struct Bridging<NativePartialReloadAndProfileConfig>
: NativeReactDevToolsRuntimeSettingsModulePartialReloadAndProfileConfigBridging<
NativePartialReloadAndProfileConfig> {};

using NativeReloadAndProfileConfig =
NativeReactDevToolsRuntimeSettingsModuleReloadAndProfileConfig<bool, bool>;

template <>
struct Bridging<NativeReloadAndProfileConfig>
: NativeReactDevToolsRuntimeSettingsModuleReloadAndProfileConfigBridging<
NativeReloadAndProfileConfig> {};

class DevToolsRuntimeSettings {
public:
// static to persist across Turbo Module reloads
static DevToolsRuntimeSettings& getInstance() {
static DevToolsRuntimeSettings instance;
return instance;
}

private:
NativeReloadAndProfileConfig _config;

DevToolsRuntimeSettings() : _config() {}

public:
DevToolsRuntimeSettings(const DevToolsRuntimeSettings&) = delete;
void operator=(const DevToolsRuntimeSettings&) = delete;

void setReloadAndProfileConfig(NativePartialReloadAndProfileConfig config);
NativeReloadAndProfileConfig getReloadAndProfileConfig() const;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ target_include_directories(react_nativemodule_defaults PUBLIC ${REACT_COMMON_DIR

target_link_libraries(react_nativemodule_defaults
react_nativemodule_dom
react_nativemodule_devtoolsruntimesettings
react_nativemodule_featureflags
react_nativemodule_microtasks
react_nativemodule_idlecallbacks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <react/nativemodule/idlecallbacks/NativeIdleCallbacks.h>
#include <react/nativemodule/microtasks/NativeMicrotasks.h>

#ifdef HERMES_ENABLE_DEBUGGER
#include <react/nativemodule/devtoolsruntimesettings/DevToolsRuntimeSettingsModule.h>
#endif

namespace facebook::react {

/* static */ std::shared_ptr<TurboModule> DefaultTurboModules::getTurboModule(
Expand All @@ -32,6 +36,12 @@ namespace facebook::react {
return std::make_shared<NativeDOM>(jsInvoker);
}

#ifdef HERMES_ENABLE_DEBUGGER
if (name == DevToolsRuntimeSettingsModule::kModuleName) {
return std::make_shared<DevToolsRuntimeSettingsModule>(jsInvoker);
}
#endif

return nullptr;
}

Expand Down
Loading

0 comments on commit 9ece2c7

Please sign in to comment.