diff --git a/shells/browser/shared/src/panel.js b/shells/browser/shared/src/panel.js index 67f0584dc0..c1e837ed4a 100644 --- a/shells/browser/shared/src/panel.js +++ b/shells/browser/shared/src/panel.js @@ -1,7 +1,7 @@ /* global chrome */ import { createElement } from 'react'; -import { render } from 'react-dom'; +import { render, unmountComponentAtNode } from 'react-dom'; import Bridge from 'src/bridge'; import Elements from 'src/devtools/views/Elements'; import inject from './inject'; @@ -36,27 +36,56 @@ if (IS_CHROME) { const node = ((document.getElementById('container'): any): HTMLElement); -inject(chrome.runtime.getURL('build/backend.js'), () => { - let disconnected = false; +function reloadDevTools() { + setTimeout(() => { + unmountComponentAtNode(node); - const port = chrome.runtime.connect({ - name: '' + chrome.devtools.inspectedWindow.tabId, - }); - port.onDisconnect.addListener(() => { - disconnected = true; - }); + node.innerHTML = ''; - const bridge = new Bridge({ - listen(fn) { - port.onMessage.addListener(message => fn(message)); - }, - send(event: string, payload: any, transferable?: Array) { - if (disconnected) { - return; - } - port.postMessage({ event, payload }, transferable); - }, - }); + injectAndInit(); + }, 100); +} - render(createElement(Elements, { bridge, browserName, themeName }), node); -}); +function injectAndInit() { + inject(chrome.runtime.getURL('build/backend.js'), () => { + let disconnected = false; + + const port = chrome.runtime.connect({ + name: '' + chrome.devtools.inspectedWindow.tabId, + }); + port.onDisconnect.addListener(() => { + disconnected = true; + }); + + const bridge = new Bridge({ + listen(fn) { + port.onMessage.addListener(message => fn(message)); + }, + send(event: string, payload: any, transferable?: Array) { + if (disconnected) { + return; + } + port.postMessage({ event, payload }, transferable); + }, + }); + + // Reload the DevTools extension when the user navigates to a new page. + function onNavigated() { + chrome.devtools.network.onNavigated.removeListener(onNavigated); + bridge.send('shutdown'); + reloadDevTools(); + } + chrome.devtools.network.onNavigated.addListener(onNavigated); + + render( + createElement(Elements, { + bridge, + browserName, + themeName, + }), + node + ); + }); +} + +injectAndInit(); diff --git a/src/backend/agent.js b/src/backend/agent.js index 6d7b1a3c03..d33a594321 100644 --- a/src/backend/agent.js +++ b/src/backend/agent.js @@ -24,6 +24,8 @@ export default class Agent extends EventEmitter { addBridge(bridge: Bridge) { this._bridge = bridge; + bridge.on('shutdown', () => this.emit('shutdown')); + // TODO Listen to bridge for things like selection. // bridge.on('...'), this...); } diff --git a/src/backend/index.js b/src/backend/index.js index a634b9c8aa..029bd655c4 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -43,6 +43,9 @@ export function initBackend(hook: Hook, agent: Agent): void { hook.reactDevtoolsAgent = agent; agent.addListener('shutdown', () => { subs.forEach(fn => fn()); + for (let id in hook.rendererInterfaces) { + hook.rendererInterfaces[id].cleanup(); + } hook.reactDevtoolsAgent = null; }); } diff --git a/src/devtools/views/Elements.js b/src/devtools/views/Elements.js index 60afcc048c..abf2829dae 100644 --- a/src/devtools/views/Elements.js +++ b/src/devtools/views/Elements.js @@ -14,7 +14,11 @@ export type Props = {| themeName: string, |}; -export default function Elements({ bridge, browserName, themeName }: Props) { +export default function Elements({ + bridge, + browserName, + themeName, +}: Props) { const store = useMemo(() => new Store(bridge), []); const [treeContext, setTreeContext] = useState({