Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/react-devtools-extensions/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ function createPanelIfReactLoaded() {
}
};

const viewSourceLineFunction = (url, line) => {
chrome.devtools.panels.openResource(url, line);
};

let debugIDCounter = 0;

// For some reason in Firefox, chrome.runtime.sendMessage() from a content script
Expand Down Expand Up @@ -381,6 +385,7 @@ function createPanelIfReactLoaded() {
warnIfUnsupportedVersionDetected: true,
viewAttributeSourceFunction,
viewElementSourceFunction,
viewSourceLineFunction,
}),
);
};
Expand Down
18 changes: 18 additions & 0 deletions packages/react-devtools-shared/src/__tests__/utils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getDisplayName,
getDisplayNameForReactElement,
} from 'react-devtools-shared/src/utils';
import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils';
import {
format,
formatWithStyles,
Expand Down Expand Up @@ -53,6 +54,23 @@ describe('utils', () => {
const FauxComponent = {name: {}};
expect(getDisplayName(FauxComponent, 'Fallback')).toEqual('Fallback');
});

it('should parse a component stack trace', () => {
expect(
stackToComponentSources(`
at Foobar (http://localhost:3000/static/js/bundle.js:103:74)
at a
at header
at div
at App`),
).toEqual([
['Foobar', ['http://localhost:3000/static/js/bundle.js', 103, 74]],
['a', null],
['header', null],
['div', null],
['App', null],
]);
});
});

describe('getDisplayNameForReactElement', () => {
Expand Down
25 changes: 25 additions & 0 deletions packages/react-devtools-shared/src/devtools/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,28 @@ export function smartStringify(value: any) {

return JSON.stringify(value);
}

// [url, row, column]
export type Stack = [string, number, number];

const STACK_DELIMETER = /\n\s+at /;
const STACK_SOURCE_LOCATION = /([^\s]+) \((.+):(.+):(.+)\)/;

export function stackToComponentSources(
stack: string,
): Array<[string, ?Stack]> {
const out = [];
stack
.split(STACK_DELIMETER)
.slice(1)
.forEach(entry => {
const match = STACK_SOURCE_LOCATION.exec(entry);
if (match) {
const [, component, url, row, column] = match;
out.push([component, [url, parseInt(row, 10), parseInt(column, 10)]]);
} else {
out.push([entry, null]);
}
});
return out;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import {createContext} from 'react';

import type {ViewSourceLine} from 'react-devtools-shared/src/devtools/views/DevTools';

export type Context = {|
viewSourceLineFunction: ViewSourceLine | null,
|};

const ViewSourceContext = createContext<Context>(((null: any): Context));
ViewSourceContext.displayName = 'ViewSourceContext';

export default ViewSourceContext;
109 changes: 63 additions & 46 deletions packages/react-devtools-shared/src/devtools/views/DevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import TabBar from './TabBar';
import {SettingsContextController} from './Settings/SettingsContext';
import {TreeContextController} from './Components/TreeContext';
import ViewElementSourceContext from './Components/ViewElementSourceContext';
import ViewSourceContext from './Components/ViewSourceContext';
import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
import HookNamesModuleLoaderContext from 'react-devtools-shared/src/devtools/views/Components/HookNamesModuleLoaderContext';
import {ProfilerContextController} from './Profiler/ProfilerContext';
Expand Down Expand Up @@ -57,6 +58,7 @@ export type ViewElementSource = (
id: number,
inspectedElement: InspectedElement,
) => void;
export type ViewSourceLine = (url: string, row: number, column: number) => void;
export type ViewAttributeSource = (
id: number,
path: Array<string | number>,
Expand All @@ -77,6 +79,7 @@ export type Props = {|
warnIfUnsupportedVersionDetected?: boolean,
viewAttributeSourceFunction?: ?ViewAttributeSource,
viewElementSourceFunction?: ?ViewElementSource,
viewSourceLineFunction?: ?ViewSourceLine,
readOnly?: boolean,
hideSettings?: boolean,
hideToggleErrorAction?: boolean,
Expand Down Expand Up @@ -136,6 +139,7 @@ export default function DevTools({
warnIfUnsupportedVersionDetected = false,
viewAttributeSourceFunction,
viewElementSourceFunction,
viewSourceLineFunction,
readOnly,
hideSettings,
hideToggleErrorAction,
Expand Down Expand Up @@ -199,6 +203,15 @@ export default function DevTools({
[canViewElementSourceFunction, viewElementSourceFunction],
);

const viewSource = useMemo(
() => ({
viewSourceLineFunction: viewSourceLineFunction || null,
// todo(blakef): Add inspect(...) method here and remove viewElementSource
// to consolidate source code inspection.
}),
[viewSourceLineFunction],
);

const contextMenu = useMemo(
() => ({
isEnabledForInspectedElement: enabledInspectedElementContextMenu,
Expand Down Expand Up @@ -267,55 +280,59 @@ export default function DevTools({
componentsPortalContainer={componentsPortalContainer}
profilerPortalContainer={profilerPortalContainer}>
<ViewElementSourceContext.Provider value={viewElementSource}>
<HookNamesModuleLoaderContext.Provider
value={hookNamesModuleLoaderFunction || null}>
<FetchFileWithCachingContext.Provider
value={fetchFileWithCaching || null}>
<TreeContextController>
<ProfilerContextController>
<TimelineContextController>
<ThemeProvider>
<div
className={styles.DevTools}
ref={devToolsRef}
data-react-devtools-portal-root={true}>
{showTabBar && (
<div className={styles.TabBar}>
<ReactLogo />
<span className={styles.DevToolsVersion}>
{process.env.DEVTOOLS_VERSION}
</span>
<div className={styles.Spacer} />
<TabBar
currentTab={tab}
id="DevTools"
selectTab={selectTab}
tabs={tabs}
type="navigation"
<ViewSourceContext.Provider value={viewSource}>
<HookNamesModuleLoaderContext.Provider
value={hookNamesModuleLoaderFunction || null}>
<FetchFileWithCachingContext.Provider
value={fetchFileWithCaching || null}>
<TreeContextController>
<ProfilerContextController>
<TimelineContextController>
<ThemeProvider>
<div
className={styles.DevTools}
ref={devToolsRef}
data-react-devtools-portal-root={true}>
{showTabBar && (
<div className={styles.TabBar}>
<ReactLogo />
<span className={styles.DevToolsVersion}>
{process.env.DEVTOOLS_VERSION}
</span>
<div className={styles.Spacer} />
<TabBar
currentTab={tab}
id="DevTools"
selectTab={selectTab}
tabs={tabs}
type="navigation"
/>
</div>
)}
<div
className={styles.TabContent}
hidden={tab !== 'components'}>
<Components
portalContainer={
componentsPortalContainer
}
/>
</div>
<div
className={styles.TabContent}
hidden={tab !== 'profiler'}>
<Profiler
portalContainer={profilerPortalContainer}
/>
</div>
)}
<div
className={styles.TabContent}
hidden={tab !== 'components'}>
<Components
portalContainer={componentsPortalContainer}
/>
</div>
<div
className={styles.TabContent}
hidden={tab !== 'profiler'}>
<Profiler
portalContainer={profilerPortalContainer}
/>
</div>
</div>
</ThemeProvider>
</TimelineContextController>
</ProfilerContextController>
</TreeContextController>
</FetchFileWithCachingContext.Provider>
</HookNamesModuleLoaderContext.Provider>
</ThemeProvider>
</TimelineContextController>
</ProfilerContextController>
</TreeContextController>
</FetchFileWithCachingContext.Provider>
</HookNamesModuleLoaderContext.Provider>
</ViewSourceContext.Provider>
</ViewElementSourceContext.Provider>
</SettingsContextController>
<UnsupportedBridgeProtocolDialog />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import CommitFlamegraph from './CommitFlamegraph';
import CommitRanked from './CommitRanked';
import RootSelector from './RootSelector';
import {Timeline} from 'react-devtools-timeline/src/Timeline';
import SidebarEventInfo from './SidebarEventInfo';
import RecordToggle from './RecordToggle';
import ReloadAndProfileButton from './ReloadAndProfileButton';
import ProfilingImportExportButtons from './ProfilingImportExportButtons';
Expand Down Expand Up @@ -102,6 +103,9 @@ function Profiler(_: {||}) {
}
}
break;
case 'timeline':
sidebar = <SidebarEventInfo />;
break;
default:
break;
}
Expand Down Expand Up @@ -145,9 +149,7 @@ function Profiler(_: {||}) {
<ModalDialog />
</div>
</div>
{isLegacyProfilerSelected && (
<div className={styles.RightColumn}>{sidebar}</div>
)}
<div className={styles.RightColumn}>{sidebar}</div>
<SettingsModal />
</div>
</SettingsModalContextController>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
.Toolbar {
height: 2.25rem;
padding: 0 0.5rem;
flex: 0 0 auto;
display: flex;
align-items: center;
border-bottom: 1px solid var(--color-border);
}

.Content {
padding: 0.5rem;
user-select: none;
overflow: auto;
}

.List {
list-style: none;
margin: 0;
padding: 0;
}

.ListItem {
margin: 0;
}

.Label {
display: flex;
justify-content: space-between;

font-weight: bold;
}

[data-source="true"]:hover .Label > .Button {
background-color: var(--color-background-hover);
}

.Value {
font-family: var(--font-family-monospace);
font-size: var(--font-size-monospace-normal);
}

.NothingSelected {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: var(--color-dim);
}

.Button {
display: flex;
flex: 1;

max-width: 95%;
overflow: hidden;
text-overflow: ellipsis;
}

[data-source="true"] .Button {
cursor: pointer;
}


.Button > span {
display: block;
text-align: left;
}

.Source {
}
Loading