Skip to content

Commit

Permalink
Merge pull request facebook#33 from bvaughn/portals
Browse files Browse the repository at this point in the history
Experimenting with portals [WIP]
  • Loading branch information
bvaughn authored Mar 18, 2019
2 parents d3ee02c + 5f154b3 commit 9b6ee0b
Show file tree
Hide file tree
Showing 23 changed files with 381 additions and 312 deletions.
8 changes: 1 addition & 7 deletions shells/browser/chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,7 @@
"devtools_page": "main.html",

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"web_accessible_resources": [
"elements.html",
"main.html",
"profiler.html",
"settings.html",
"build/backend.js"
],
"web_accessible_resources": ["main.html", "panel.html", "build/backend.js"],

"background": {
"scripts": ["build/background.js"],
Expand Down
8 changes: 1 addition & 7 deletions shells/browser/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,7 @@
"devtools_page": "main.html",

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"web_accessible_resources": [
"elements.html",
"main.html",
"profiler.html",
"settings.html",
"build/backend.js"
],
"web_accessible_resources": ["main.html", "panel.html", "build/backend.js"],

"background": {
"scripts": ["build/background.js"],
Expand Down
9 changes: 1 addition & 8 deletions shells/browser/shared/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ const { join } = require('path');

// These files are copied along with Webpack-bundled files
// to produce the final web extension
const STATIC_FILES = [
'icons',
'popups',
'elements.html',
'main.html',
'profiler.html',
'settings.html',
];
const STATIC_FILES = ['icons', 'popups', 'main.html', 'panel.html'];

const preProcess = async (destinationPath, tempPath) => {
await remove(destinationPath); // Clean up from previously completed builds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@
<body>
<!-- main react mount point -->
<div id="container">Unable to find React on the page.</div>
<script src="./build/elements.js"></script>
<script src="./build/panel.js"></script>
</body>
</html>
32 changes: 0 additions & 32 deletions shells/browser/shared/profiler.html

This file was deleted.

32 changes: 0 additions & 32 deletions shells/browser/shared/settings.html

This file was deleted.

151 changes: 92 additions & 59 deletions shells/browser/shared/src/main.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
/* global chrome */

import { createElement } from 'react';
import { unstable_createRoot as createRoot, flushSync } from 'react-dom';
import Bridge from 'src/bridge';
import Store from 'src/devtools/Store';
import inject from './inject';
import {
createViewElementSource,
getBrowserName,
getBrowserTheme,
} from './utils';
import DevTools from 'src/devtools/views/DevTools';

let panelCreated = false;

Expand All @@ -24,9 +32,15 @@ function createPanelIfReactLoaded() {

let bridge = null;
let store = null;
let elementsPanel = null;
let profilerPanel = null;
let settingsPanel = null;

let elementsPortalContainer = null;
let profilerPortalContainer = null;
let settingsPortalContainer = null;

let cloneStyleTags = null;
let mostRecentOverrideTab = null;
let render = null;
let root = null;

function initBridgeAndStore() {
let hasPortBeenDisconnected = false;
Expand Down Expand Up @@ -54,77 +68,96 @@ function createPanelIfReactLoaded() {
// Otherwise the Store may miss important initial tree op codes.
inject(chrome.runtime.getURL('build/backend.js'));

if (elementsPanel !== null) {
elementsPanel.injectBridgeAndStore(bridge, store);
}
if (profilerPanel !== null) {
profilerPanel.injectBridgeAndStore(bridge, store);
}
if (settingsPanel !== null) {
settingsPanel.injectBridgeAndStore(bridge, store);
}
const viewElementSource = createViewElementSource(bridge, store);

root = createRoot(document.createElement('div'));

render = (overrideTab = mostRecentOverrideTab) => {
mostRecentOverrideTab = overrideTab;

root.render(
createElement(DevTools, {
bridge,
browserName: getBrowserName(),
browserTheme: getBrowserTheme(),
elementsPortalContainer,
overrideTab,
profilerPortalContainer,
settingsPortalContainer,
showTabBar: false,
store,
viewElementSource,
})
);
};

render();
}

initBridgeAndStore();

chrome.devtools.panels.create(
'⚛ Elements',
'',
'elements.html',
panel => {
panel.onShown.addListener(panel => {
if (elementsPanel === null) {
panel.injectBridgeAndStore(bridge, store);
cloneStyleTags = () => {
const linkTags = [];
for (let linkTag of document.getElementsByTagName('link')) {
if (linkTag.rel === 'stylesheet') {
const newLinkTag = document.createElement('link');
for (let attribute of linkTag.attributes) {
newLinkTag.setAttribute(attribute.nodeName, attribute.nodeValue);
}
linkTags.push(newLinkTag);
}
}
return linkTags;
};

elementsPanel = panel;
initBridgeAndStore();

// TODO: When the user switches to the panel, check for an Elements tab selection.
});
panel.onHidden.addListener(() => {
// TODO: Stop highlighting and stuff.
});
}
);
chrome.devtools.panels.create('⚛ Elements', '', 'panel.html', panel => {
panel.onShown.addListener(panel => {
elementsPortalContainer = panel.container;
if (elementsPortalContainer != null) {
elementsPortalContainer.innerHTML = '';
render('elements');
panel.injectStyles(cloneStyleTags);
}

// TODO (profiling) Is there a way to detect profiling support and conditionally register this panel?
chrome.devtools.panels.create(
'⚛ Profiler',
'',
'profiler.html',
panel => {
panel.onShown.addListener(panel => {
if (settingsPanel === null) {
panel.injectBridgeAndStore(bridge, store);
}
// TODO: When the user switches to the panel, check for an Elements tab selection.
});
panel.onHidden.addListener(() => {
// TODO: Stop highlighting and stuff.
});
});

profilerPanel = panel;
});
}
);

chrome.devtools.panels.create(
'⚛ Settings',
'',
'settings.html',
panel => {
panel.onShown.addListener(panel => {
if (settingsPanel === null) {
panel.injectBridgeAndStore(bridge, store);
}
// TODO (profiling) Is there a way to detect profiling support and conditionally register this panel?
chrome.devtools.panels.create('⚛ Profiler', '', 'panel.html', panel => {
panel.onShown.addListener(panel => {
profilerPortalContainer = panel.container;
if (profilerPortalContainer != null) {
profilerPortalContainer.innerHTML = '';
render('profiler');
panel.injectStyles(cloneStyleTags);
}
});
});

settingsPanel = panel;
});
}
);
chrome.devtools.panels.create('⚛ Settings', '', 'panel.html', panel => {
panel.onShown.addListener(panel => {
settingsPortalContainer = panel.container;
if (settingsPortalContainer != null) {
settingsPortalContainer.innerHTML = '';
render('settings');
panel.injectStyles(cloneStyleTags);
}
});
});

chrome.devtools.network.onNavigated.removeListener(checkPageForReact);

// Shutdown bridge and re-initialize DevTools panel when a new page is loaded.
chrome.devtools.network.onNavigated.addListener(function onNavigated() {
bridge.send('shutdown');

initBridgeAndStore();
// It's easiest to recreate the DevTools panel (to clean up potential stale state).
// We can revisit this in the future as a small optimization.
flushSync(() => root.unmount(initBridgeAndStore));
});
}
);
Expand Down
18 changes: 18 additions & 0 deletions shells/browser/shared/src/panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Portal target container.
window.container = document.getElementById('container');

let hasInjectedStyles = false;

// DevTools styles are injected into the top-level document head (where the main React app is rendered).
// This method copies those styles to the child window where each panel (e.g. Elements, Profiler) is portaled.
window.injectStyles = getLinkTags => {
if (!hasInjectedStyles) {
hasInjectedStyles = true;

const linkTags = getLinkTags();

for (let linkTag of linkTags) {
document.head.appendChild(linkTag);
}
}
};
3 changes: 0 additions & 3 deletions shells/browser/shared/src/panels/elements.js

This file was deleted.

3 changes: 0 additions & 3 deletions shells/browser/shared/src/panels/profiler.js

This file was deleted.

3 changes: 0 additions & 3 deletions shells/browser/shared/src/panels/settings.js

This file was deleted.

Loading

0 comments on commit 9b6ee0b

Please sign in to comment.