Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DevTools shows unsupported renderer version dialog #16897

Merged
merged 2 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion packages/react-devtools-extensions/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ function createPanelIfReactLoaded() {
overrideTab,
profilerPortalContainer,
showTabBar: false,
showWelcomeToTheNewDevToolsDialog: true,
warnIfUnsupportedVersionDetected: true,
store,
viewElementSourceFunction,
}),
Expand Down
4 changes: 4 additions & 0 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,10 @@ export default class Agent extends EventEmitter<{|
}
};

onUnsupportedRenderer(rendererID: number) {
this._bridge.send('unsupportedRendererVersion', rendererID);
}

_throttledPersistSelection = throttle((rendererID: number, id: number) => {
// This is throttled, so both renderer and selected ID
// might not be available by the time we read them.
Expand Down
30 changes: 22 additions & 8 deletions packages/react-devtools-shared/src/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export function initBackend(
},
),

hook.sub('unsupported-renderer-version', (id: number) => {
agent.onUnsupportedRenderer(id);
}),

hook.sub('operations', agent.onHookOperations),

// TODO Add additional subscriptions required for profiling mode
Expand All @@ -48,23 +52,33 @@ export function initBackend(
let rendererInterface = hook.rendererInterfaces.get(id);

// Inject any not-yet-injected renderers (if we didn't reload-and-profile)
if (!rendererInterface) {
if (rendererInterface == null) {
if (typeof renderer.findFiberByHostInstance === 'function') {
// react-reconciler v16+
rendererInterface = attach(hook, id, renderer, global);
} else {
} else if (renderer.ComponentTree) {
// react-dom v15
rendererInterface = attachLegacy(hook, id, renderer, global);
} else {
// Older react-dom or other unsupported renderer version
}

hook.rendererInterfaces.set(id, rendererInterface);
if (rendererInterface != null) {
hook.rendererInterfaces.set(id, rendererInterface);
}
}

// Notify the DevTools frontend about new renderers.
// This includes any that were attached early (via __REACT_DEVTOOLS_ATTACH__).
hook.emit('renderer-attached', {
id,
renderer,
rendererInterface,
});
if (rendererInterface != null) {
hook.emit('renderer-attached', {
id,
renderer,
rendererInterface,
});
} else {
hook.emit('unsupported-renderer-version', id);
}
};

// Connect renderers that have already injected themselves.
Expand Down
5 changes: 4 additions & 1 deletion packages/react-devtools-shared/src/backend/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ export type ReactRenderer = {
// Enables DevTools to append owners-only component stack to error messages.
getCurrentFiber?: () => Fiber | null,

// <= 15
// Uniquely identifies React DOM v15.
ComponentTree?: any,

// Present for React DOM v12 (possibly earlier) through v15.
Mount?: any,
};

Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type BackendEvents = {|
stopInspectingNative: [boolean],
syncSelectionFromNativeElementsPanel: [],
syncSelectionToNativeElementsPanel: [],
unsupportedRendererVersion: [RendererID],

// React Native style editor plug-in.
isNativeStyleEditorSupported: [
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export const PROFILER_EXPORT_VERSION = 4;
export const CHANGE_LOG_URL =
'https://github.com/facebook/react/blob/master/packages/react-devtools/CHANGELOG.md';

export const UNSUPPORTED_VERSION_URL =
'https://reactjs.org/blog/2019/08/15/new-react-devtools.html#how-do-i-get-the-old-version-back';

// HACK
//
// Extracting during build time avoids a temporarily invalid state for the inline target.
Expand Down
17 changes: 17 additions & 0 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export default class Store extends EventEmitter<{|
supportsNativeStyleEditor: [],
supportsProfiling: [],
supportsReloadAndProfile: [],
unsupportedRendererVersionDetected: [],
|}> {
_bridge: FrontendBridge;

Expand Down Expand Up @@ -125,6 +126,8 @@ export default class Store extends EventEmitter<{|
_supportsProfiling: boolean = false;
_supportsReloadAndProfile: boolean = false;

_unsupportedRendererVersionDetected: boolean = false;

// Total number of visible elements (within all roots).
// Used for windowing purposes.
_weightAcrossRoots: number = 0;
Expand Down Expand Up @@ -179,6 +182,10 @@ export default class Store extends EventEmitter<{|
'isNativeStyleEditorSupported',
this.onBridgeNativeStyleEditorSupported,
);
bridge.addListener(
'unsupportedRendererVersion',
this.onBridgeUnsupportedRendererVersion,
);

this._profilerStore = new ProfilerStore(bridge, this, isProfiling);
}
Expand Down Expand Up @@ -337,6 +344,10 @@ export default class Store extends EventEmitter<{|
return this._supportsReloadAndProfile && this._isBackendStorageAPISupported;
}

get unsupportedRendererVersionDetected(): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it normal that we use getters vs generic functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the DevTools Store I guess it is. Any reason to prefer one over the other?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In DevTools Store I guess it is. Any reason to prefer one over the other?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's fine as this won't be used on unsupported browsers anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, DevTools has the benefit of only being used in Chrome & Firefox

return this._unsupportedRendererVersionDetected;
}

containsElement(id: number): boolean {
return this._idToElement.get(id) != null;
}
Expand Down Expand Up @@ -1009,4 +1020,10 @@ export default class Store extends EventEmitter<{|

this.emit('supportsReloadAndProfile');
};

onBridgeUnsupportedRendererVersion = () => {
this._unsupportedRendererVersionDetected = true;

this.emit('unsupportedRendererVersionDetected');
};
}
4 changes: 4 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/DevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import ViewElementSourceContext from './Components/ViewElementSourceContext';
import {ProfilerContextController} from './Profiler/ProfilerContext';
import {ModalDialogContextController} from './ModalDialog';
import ReactLogo from './ReactLogo';
import UnsupportedVersionDialog from './UnsupportedVersionDialog';
import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';

import styles from './DevTools.css';
Expand Down Expand Up @@ -51,6 +52,7 @@ export type Props = {|
showTabBar?: boolean,
store: Store,
warnIfLegacyBackendDetected?: boolean,
warnIfUnsupportedVersionDetected?: boolean,
viewElementSourceFunction?: ?ViewElementSource,

// This property is used only by the web extension target.
Expand Down Expand Up @@ -92,6 +94,7 @@ export default function DevTools({
showTabBar = false,
store,
warnIfLegacyBackendDetected = false,
warnIfUnsupportedVersionDetected = false,
viewElementSourceFunction,
}: Props) {
const [tab, setTab] = useState(defaultTab);
Expand Down Expand Up @@ -164,6 +167,7 @@ export default function DevTools({
</ViewElementSourceContext.Provider>
</SettingsContextController>
{warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
{warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
</ModalDialogContextController>
</StoreContext.Provider>
</BridgeContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.Row {
display: flex;
flex-direction: row;
align-items: center;
}

.Column {
display: flex;
flex-direction: column;
align-items: center;
}

.Title {
font-size: var(--font-size-sans-large);
margin-bottom: 0.5rem;
}

.ReleaseNotesLink {
color: var(--color-button-active);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* 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 React, {Fragment, useContext, useEffect, useState} from 'react';
import {unstable_batchedUpdates as batchedUpdates} from 'react-dom';
import {ModalDialogContext} from './ModalDialog';
import {StoreContext} from './context';
import {UNSUPPORTED_VERSION_URL} from 'react-devtools-shared/src/constants';

import styles from './UnsupportedVersionDialog.css';

type DAILOG_STATE = 'dialog-not-shown' | 'show-dialog' | 'dialog-shown';

export default function UnsupportedVersionDialog(_: {||}) {
const {dispatch} = useContext(ModalDialogContext);
const store = useContext(StoreContext);
const [state, setState] = useState<DAILOG_STATE>('dialog-not-shown');

useEffect(
() => {
if (state === 'dialog-not-shown') {
const showDialog = () => {
batchedUpdates(() => {
setState('show-dialog');
dispatch({
canBeDismissed: true,
type: 'SHOW',
content: <DialogContent />,
});
});
};

if (store.unsupportedRendererVersionDetected) {
showDialog();
} else {
store.addListener('unsupportedRendererVersionDetected', showDialog);
return () => {
store.removeListener(
'unsupportedRendererVersionDetected',
showDialog,
);
};
}
}
},
[state, store],
);

return null;
}

function DialogContent(_: {||}) {
return (
<Fragment>
<div className={styles.Row}>
<div>
<div className={styles.Title}>Unsupported React version detected</div>
<p>
This version of React DevTools supports React DOM v15+ and React
Native v61+.
</p>
<p>
In order to use DevTools with an older version of React, you'll need
to{' '}
<a
className={styles.ReleaseNotesLink}
target="_blank"
rel="noopener noreferrer"
href={UNSUPPORTED_VERSION_URL}>
install an older version of the extension
</a>.
</p>
</div>
</div>
</Fragment>
);
}
1 change: 1 addition & 0 deletions packages/react-devtools-shell/src/devtools.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ inject('dist/app.js', () => {
browserTheme: 'light',
showTabBar: true,
warnIfLegacyBackendDetected: true,
warnIfUnsupportedVersionDetected: true,
}),
);
},
Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Fixed bug where Components panel was always empty for certain users. ([bvaughn](https://github.com/bvaughn) in [#16864](https://github.com/facebook/react/pull/16864))
* Fixed regression in DevTools editable hooks interface that caused primitive values to be shown as `undefined`. ([bvaughn](https://github.com/bvaughn) in [#16867](https://github.com/facebook/react/pull/16867))
* Fixed bug where DevTools showed stale values in props/state/hooks editing interface. ([bvaughn](https://github.com/bvaughn) in [#16878](https://github.com/facebook/react/pull/16878))
* Show unsupported version dialog with downgrade instructions. ([bvaughn](https://github.com/bvaughn) in [#16897](https://github.com/facebook/react/pull/16897))
</details>

## 4.1.0 (September 19, 2019)
Expand Down