Skip to content

Commit

Permalink
Add initial feature/UI customisations for profiling builds (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntie authored Dec 2, 2024
1 parent 6b80704 commit 7e54784
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 6 deletions.
1 change: 1 addition & 0 deletions config/gni/devtools_grd_files.gni
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,7 @@ grd_files_debug_sources = [
"front_end/entrypoints/node_app/NodeConnectionsPanel.js",
"front_end/entrypoints/node_app/NodeMain.js",
"front_end/entrypoints/node_app/nodeConnectionsPanel.css.js",
"front_end/entrypoints/rn_fusebox/FuseboxProfilingBuildObserver.js",
"front_end/entrypoints/shell/browser_compatibility_guard.js",
"front_end/entrypoints/wasmparser_worker/WasmParserWorker.js",
"front_end/entrypoints/worker_app/WorkerMain.js",
Expand Down
17 changes: 17 additions & 0 deletions front_end/entrypoints/rn_fusebox/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,25 @@
# Copyright 2021 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("../../../scripts/build/ninja/devtools_entrypoint.gni")
import("../../../scripts/build/ninja/devtools_module.gni")
import("../visibility.gni")

devtools_module("rn_fusebox") {
sources = [
"FuseboxProfilingBuildObserver.ts",
]

deps = [
"../../core/common:bundle",
"../../core/i18n:bundle",
"../../core/root:bundle",
"../../core/sdk:bundle",
"../../ui/legacy:bundle",
]
}

devtools_entrypoint("entrypoint") {
entrypoint = "rn_fusebox.ts"

Expand Down Expand Up @@ -39,6 +55,7 @@ devtools_entrypoint("entrypoint") {
"../../panels/webauthn:meta",
"../main:bundle",
"../shell",
":rn_fusebox",
]

visibility = [ "../../:*" ]
Expand Down
89 changes: 89 additions & 0 deletions front_end/entrypoints/rn_fusebox/FuseboxProfilingBuildObserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../../core/common/common.js';
import * as Protocol from '../../generated/protocol.js';
import * as Root from '../../core/root/root.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as i18n from '../../core/i18n/i18n.js';

const UIStrings = {
/**
* @description Message for the "settings changed" banner shown when a reload is required.
*/
reloadRequiredMessage: '[Profiling build first run] One or more settings have changed. Please reload to access the Performance panel.',
};

const str_ = i18n.i18n.registerUIStrings('entrypoints/rn_fusebox/FuseboxProfilingBuildModeObserver.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

/**
* [Experimental] Model observer which configures available DevTools features
* when a profiling build is identified.
*/
export default class FuseboxProfilingBuildObserver implements
SDK.TargetManager.SDKModelObserver<SDK.ReactNativeApplicationModel.ReactNativeApplicationModel> {
constructor(targetManager: SDK.TargetManager.TargetManager) {
targetManager.observeModels(SDK.ReactNativeApplicationModel.ReactNativeApplicationModel, this);
}

modelAdded(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.ensureEnabled();
model.addEventListener(SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
}

modelRemoved(model: SDK.ReactNativeApplicationModel.ReactNativeApplicationModel): void {
model.removeEventListener(
SDK.ReactNativeApplicationModel.Events.MetadataUpdated, this.#handleMetadataUpdated, this);
}

#handleMetadataUpdated(
event: Common.EventTarget.EventTargetEvent<Protocol.ReactNativeApplication.MetadataUpdatedEvent>): void {
const {unstable_isProfilingBuild} = event.data;

if (unstable_isProfilingBuild) {
this.#hideUnsupportedFeatures();
this.#ensurePerformancePanelEnabled();
}
}

#hideUnsupportedFeatures(): void {
UI.ViewManager.ViewManager.instance()
.resolveLocation(UI.ViewManager.ViewLocationValues.PANEL)
.then(location => {
UI.ViewManager.getRegisteredViewExtensions().forEach(view => {
switch (view.viewId()) {
case 'sources':
case 'network':
case 'react-devtools-components':
case 'react-devtools-profiler':
location?.removeView(view);
break;
}
});
});
}

#ensurePerformancePanelEnabled(): void {
if (
!Root.Runtime.experiments.isEnabled(
Root.Runtime.ExperimentName.ENABLE_PERFORMANCE_PANEL,
)
) {
Root.Runtime.experiments.setEnabled(
Root.Runtime.ExperimentName.ENABLE_PERFORMANCE_PANEL,
true,
);

const inspectorView = UI.InspectorView?.InspectorView?.instance();
if (inspectorView) {
inspectorView.displayReloadRequiredWarning(
i18nString(UIStrings.reloadRequiredMessage),
);
}
}
}
}
2 changes: 2 additions & 0 deletions front_end/entrypoints/rn_fusebox/rn_fusebox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as Protocol from '../../generated/protocol.js';
import type * as Platform from '../../core/platform/platform.js';
import type * as Sources from '../../panels/sources/sources.js';
import * as RNExperiments from '../../core/rn_experiments/rn_experiments.js';
import FuseboxProfilingBuildObserver from './FuseboxProfilingBuildObserver.js';

/*
* To ensure accurate timing measurements,
Expand Down Expand Up @@ -275,5 +276,6 @@ class FuseboxReactNativeApplicationObserver implements
}

new FuseboxReactNativeApplicationObserver(SDK.TargetManager.TargetManager.instance());
new FuseboxProfilingBuildObserver(SDK.TargetManager.TargetManager.instance());

Host.rnPerfMetrics.entryPointLoadingFinished('rn_fusebox');
4 changes: 4 additions & 0 deletions front_end/generated/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export namespace ReactNativeApplication {
* The React Native version.
*/
reactNativeVersion?: string;
/**
* Whether the app is a profiling build.
*/
unstable_isProfilingBuild?: boolean;
}
}

Expand Down
16 changes: 11 additions & 5 deletions front_end/panels/timeline/TimelinePanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);

let timelinePanelInstance: TimelinePanel;
let isNode: boolean;
let isReactNative: boolean;

export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineModeViewDelegate {
private readonly dropTarget: UI.DropTarget.DropTarget;
Expand Down Expand Up @@ -364,7 +365,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
this.captureLayersAndPicturesSetting.setTitle(i18nString(UIStrings.enableAdvancedPaint));

this.showScreenshotsSetting =
Common.Settings.Settings.instance().createSetting('timeline-show-screenshots', isNode ? false : true);
Common.Settings.Settings.instance().createSetting('timeline-show-screenshots', isNode || isReactNative ? false : true);
this.showScreenshotsSetting.setTitle(i18nString(UIStrings.screenshots));
this.showScreenshotsSetting.addChangeListener(this.updateOverviewControls, this);

Expand All @@ -377,7 +378,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
this.panelToolbar = new UI.Toolbar.Toolbar('timeline-main-toolbar', timelineToolbarContainer);
this.panelToolbar.makeWrappable(true);
this.panelRightToolbar = new UI.Toolbar.Toolbar('', timelineToolbarContainer);
if (!isNode) {
if (!isNode && !isReactNative) {
this.createSettingsPane();
this.updateShowSettingsToolbarButton();
}
Expand Down Expand Up @@ -454,6 +455,11 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
const {forceNew, isNode: isNodeMode} = opts;
isNode = isNodeMode;

// [RN] Used to scope down available features for React Native targets
isReactNative = Root.Runtime.experiments.isEnabled(
Root.Runtime.ExperimentName.REACT_NATIVE_SPECIFIC_UI,
);

if (!timelinePanelInstance || forceNew) {
timelinePanelInstance = new TimelinePanel();
}
Expand Down Expand Up @@ -560,7 +566,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod

// View
this.panelToolbar.appendSeparator();
if (!isNode) {
if (!isNode && !isReactNative) {
this.showScreenshotsToolbarCheckbox =
this.createSettingCheckbox(this.showScreenshotsSetting, i18nString(UIStrings.captureScreenshots));
this.panelToolbar.appendToolbarItem(this.showScreenshotsToolbarCheckbox);
Expand All @@ -581,7 +587,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
}

// Settings
if (!isNode) {
if (!isNode && !isReactNative) {
this.panelRightToolbar.appendSeparator();
this.panelRightToolbar.appendToolbarItem(this.showSettingsPaneButton);
}
Expand Down Expand Up @@ -801,7 +807,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
}

private updateSettingsPaneVisibility(): void {
if (isNode) {
if (isNode || isReactNative) {
return;
}
if (this.showSettingsPaneSetting.get()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@
"description": "The React Native version.",
"optional": true,
"type": "string"
},
{
"name": "unstable_isProfilingBuild",
"description": "Whether the app is a profiling build.",
"optional": true,
"type": "boolean"
}
]
}
Expand Down Expand Up @@ -29262,4 +29268,4 @@
]
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ experimental domain ReactNativeApplication
optional string platform
# The React Native version.
optional string reactNativeVersion
# Whether the app is a profiling build.
optional boolean unstable_isProfilingBuild

0 comments on commit 7e54784

Please sign in to comment.