diff --git a/packages/react-devtools-core/webpack.standalone.js b/packages/react-devtools-core/webpack.standalone.js index 8f5b4e6dcac93..199e6e2c46620 100644 --- a/packages/react-devtools-core/webpack.standalone.js +++ b/packages/react-devtools-core/webpack.standalone.js @@ -18,6 +18,15 @@ const __DEV__ = NODE_ENV === 'development'; const DEVTOOLS_VERSION = getVersionString(); +const babelOptions = { + configFile: resolve( + __dirname, + '..', + 'react-devtools-shared', + 'babel.config.js', + ), +}; + module.exports = { mode: __DEV__ ? 'development' : 'production', devtool: __DEV__ ? 'cheap-module-eval-source-map' : 'source-map', @@ -62,17 +71,25 @@ module.exports = { ], module: { rules: [ + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + options: { + inline: 'no-fallback', + }, + }, + { + loader: 'babel-loader', + options: babelOptions, + }, + ], + }, { test: /\.js$/, loader: 'babel-loader', - options: { - configFile: resolve( - __dirname, - '..', - 'react-devtools-shared', - 'babel.config.js', - ), - }, + options: babelOptions, }, { test: /\.css$/, diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json index a97422cedf86d..44327c8566f74 100644 --- a/packages/react-devtools-extensions/firefox/manifest.json +++ b/packages/react-devtools-extensions/firefox/manifest.json @@ -32,7 +32,7 @@ "devtools_page": "main.html", - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", + "content_security_policy": "script-src 'self' 'unsafe-eval' blob:; object-src 'self'", "web_accessible_resources": [ "main.html", "panel.html", diff --git a/packages/react-devtools-extensions/package.json b/packages/react-devtools-extensions/package.json index da473f7613a68..d18f205c7c8a7 100644 --- a/packages/react-devtools-extensions/package.json +++ b/packages/react-devtools-extensions/package.json @@ -37,6 +37,7 @@ "chrome-launch": "^1.1.4", "crx": "^5.0.0", "css-loader": "^1.0.1", + "file-loader": "^6.1.0", "firefox-profile": "^1.0.2", "fs-extra": "^4.0.2", "jest-fetch-mock": "^3.0.3", @@ -55,7 +56,8 @@ "web-ext": "^3.0.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11", - "webpack-dev-server": "^3.10.3" + "webpack-dev-server": "^3.10.3", + "worker-loader": "^3.0.3" }, "dependencies": { "web-ext": "^4" diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index 94a12ebdd1118..45ea0c3ab767d 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -19,6 +19,15 @@ const DEVTOOLS_VERSION = getVersionString(); const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss'; +const babelOptions = { + configFile: resolve( + __dirname, + '..', + 'react-devtools-shared', + 'babel.config.js', + ), +}; + module.exports = { mode: __DEV__ ? 'development' : 'production', devtool: __DEV__ ? 'cheap-module-eval-source-map' : false, @@ -81,17 +90,25 @@ module.exports = { ], rules: [ + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + options: { + inline: 'no-fallback', + }, + }, + { + loader: 'babel-loader', + options: babelOptions, + }, + ], + }, { test: /\.js$/, loader: 'babel-loader', - options: { - configFile: resolve( - __dirname, - '..', - 'react-devtools-shared', - 'babel.config.js', - ), - }, + options: babelOptions, }, { test: /\.css$/, diff --git a/packages/react-devtools-inline/package.json b/packages/react-devtools-inline/package.json index a661fdf839957..21efaf2bbd9a3 100644 --- a/packages/react-devtools-inline/package.json +++ b/packages/react-devtools-inline/package.json @@ -34,10 +34,12 @@ "babel-loader": "^8.0.4", "cross-env": "^3.1.4", "css-loader": "^1.0.1", + "file-loader": "^6.1.0", "raw-loader": "^3.1.0", "style-loader": "^0.23.1", "webpack": "^4.43.0", "webpack-cli": "^3.3.11", - "webpack-dev-server": "^3.10.3" + "webpack-dev-server": "^3.10.3", + "worker-loader": "^3.0.3" } } diff --git a/packages/react-devtools-inline/webpack.config.js b/packages/react-devtools-inline/webpack.config.js index 7011e7151c760..0397d4358c567 100644 --- a/packages/react-devtools-inline/webpack.config.js +++ b/packages/react-devtools-inline/webpack.config.js @@ -16,6 +16,15 @@ const __DEV__ = NODE_ENV === 'development'; const DEVTOOLS_VERSION = getVersionString(); +const babelOptions = { + configFile: resolve( + __dirname, + '..', + 'react-devtools-shared', + 'babel.config.js', + ), +}; + module.exports = { mode: __DEV__ ? 'development' : 'production', devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map', @@ -65,17 +74,25 @@ module.exports = { ], module: { rules: [ + { + test: /\.worker\.js$/, + use: [ + { + loader: 'worker-loader', + options: { + inline: 'no-fallback', + }, + }, + { + loader: 'babel-loader', + options: babelOptions, + }, + ], + }, { test: /\.js$/, loader: 'babel-loader', - options: { - configFile: resolve( - __dirname, - '..', - 'react-devtools-shared', - 'babel.config.js', - ), - }, + options: babelOptions, }, { test: /\.css$/, diff --git a/packages/react-devtools-scheduling-profiler/buildUtils.js b/packages/react-devtools-scheduling-profiler/buildUtils.js deleted file mode 100644 index b0971c4861112..0000000000000 --- a/packages/react-devtools-scheduling-profiler/buildUtils.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * 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. - */ - -const {execSync} = require('child_process'); -const {readFileSync} = require('fs'); -const {resolve} = require('path'); - -function getGitCommit() { - try { - return execSync('git show -s --format=%h') - .toString() - .trim(); - } catch (error) { - // Mozilla runs this command from a git archive. - // In that context, there is no Git revision. - return null; - } -} - -function getVersionString() { - const packageVersion = JSON.parse( - readFileSync(resolve(__dirname, './package.json')), - ).version; - - const commit = getGitCommit(); - - return `${packageVersion}-${commit}`; -} - -module.exports = { - getVersionString, -}; diff --git a/packages/react-devtools-scheduling-profiler/package.json b/packages/react-devtools-scheduling-profiler/package.json index 705261279e304..e3b87c664fafd 100644 --- a/packages/react-devtools-scheduling-profiler/package.json +++ b/packages/react-devtools-scheduling-profiler/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "react-devtools-scheduling-profiler", - "version": "0.0.0", + "version": "4.14.0", "license": "MIT", "scripts": { "build": "cross-env NODE_ENV=production cross-env TARGET=remote webpack --config webpack.config.js", diff --git a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css index e16279192b83e..b5666e6bfca1e 100644 --- a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css +++ b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css @@ -1,21 +1,5 @@ -.SchedulingProfiler { - width: 100%; - height: 100%; - position: relative; - display: flex; - flex-direction: column; - font-family: var(--font-family-sans); - font-size: var(--font-size-sans-normal); - background-color: var(--color-background); - color: var(--color-text); -} - -.SchedulingProfiler, .SchedulingProfiler * { - box-sizing: border-box; - -webkit-font-smoothing: var(--font-smoothing); -} - .Content { + width: 100%; position: relative; flex: 1 1 auto; display: flex; @@ -51,58 +35,3 @@ font-size: var(--font-size-sans-large); margin-bottom: 0.5rem; } - -.Toolbar { - height: 2.25rem; - padding: 0 0.25rem; - flex: 0 0 auto; - display: flex; - align-items: center; - border-bottom: 1px solid var(--color-border); -} - -.VRule { - height: 20px; - width: 1px; - border-left: 1px solid var(--color-border); - padding-left: 0.25rem; - margin-left: 0.25rem; -} - -.Spacer { - flex: 1; -} - -.Link { - color: var(--color-button); -} - -.ScreenshotWrapper { - max-width: 30rem; - padding: 0 1rem; - margin-bottom: 2rem; -} - -.Screenshot { - width: 100%; - border-radius: 0.4em; - border: 2px solid var(--color-border); -} - -.AppName { - font-size: var(--font-size-sans-large); - margin-right: 0.5rem; - user-select: none; -} - -@media screen and (max-width: 350px) { - .AppName { - display: none; - } -} - -@media screen and (max-height: 600px) { - .ScreenshotWrapper { - display: none; - } -} \ No newline at end of file diff --git a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js index 2f232b6bbe183..2dfbb837de4dc 100644 --- a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js +++ b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js @@ -14,13 +14,11 @@ import type {ImportWorkerOutputData} from './import-worker/import.worker'; import * as React from 'react'; import {Suspense, useCallback, useState} from 'react'; import {createResource} from 'react-devtools-shared/src/devtools/cache'; -import ReactLogo from 'react-devtools-shared/src/devtools/views/ReactLogo'; import ImportButton from './ImportButton'; import CanvasPage from './CanvasPage'; import ImportWorker from './import-worker/import.worker'; -import profilerBrowser from './assets/profilerBrowser.png'; import styles from './SchedulingProfiler.css'; type DataResource = Resource; @@ -63,39 +61,23 @@ export function SchedulingProfiler(_: {||}) { }, []); return ( -
-
- - Concurrent Mode Profiler -
- -
-
-
- {dataResource ? ( - }> - - - ) : ( - - )} -
+
+ {dataResource ? ( + }> + + + ) : ( + + )}
); } const Welcome = ({onFileSelect}: {|onFileSelect: (file: File) => void|}) => (
-
- Profiler screenshot -
Welcome!
Click the import button diff --git a/packages/react-devtools-scheduling-profiler/src/assets/logo.svg b/packages/react-devtools-scheduling-profiler/src/assets/logo.svg deleted file mode 100644 index 2e5df0d3ab2f2..0000000000000 --- a/packages/react-devtools-scheduling-profiler/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png b/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png deleted file mode 100644 index b0282be2f6828..0000000000000 Binary files a/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png and /dev/null differ diff --git a/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg b/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg deleted file mode 100644 index 6b60c1042f58d..0000000000000 --- a/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js b/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js index b08d9bbbbb466..3b374aebbee79 100644 --- a/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js +++ b/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js @@ -175,15 +175,16 @@ export function useCanvasInteraction( return false; }; - document.addEventListener('mousemove', onDocumentMouseMove); - document.addEventListener('mouseup', onDocumentMouseUp); + const ownerDocument = canvas.ownerDocument; + ownerDocument.addEventListener('mousemove', onDocumentMouseMove); + ownerDocument.addEventListener('mouseup', onDocumentMouseUp); canvas.addEventListener('mousedown', onCanvasMouseDown); canvas.addEventListener('wheel', onCanvasWheel); return () => { - document.removeEventListener('mousemove', onDocumentMouseMove); - document.removeEventListener('mouseup', onDocumentMouseUp); + ownerDocument.removeEventListener('mousemove', onDocumentMouseMove); + ownerDocument.removeEventListener('mouseup', onDocumentMouseUp); canvas.removeEventListener('mousedown', onCanvasMouseDown); canvas.removeEventListener('wheel', onCanvasWheel); diff --git a/packages/react-devtools-scheduling-profiler/webpack.config.js b/packages/react-devtools-scheduling-profiler/webpack.config.js index e30d4fda13db2..683e4bb547b3e 100644 --- a/packages/react-devtools-scheduling-profiler/webpack.config.js +++ b/packages/react-devtools-scheduling-profiler/webpack.config.js @@ -4,7 +4,6 @@ const {resolve} = require('path'); const {DefinePlugin} = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); -const {getVersionString} = require('./buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -22,8 +21,6 @@ const shouldUseDevServer = TARGET === 'local'; const builtModulesDir = resolve(__dirname, '..', '..', 'build', 'node_modules'); -const DEVTOOLS_VERSION = getVersionString(); - const imageInlineSizeLimit = 10000; const babelOptions = { @@ -58,7 +55,6 @@ const config = { __PROFILE__: false, __EXPERIMENTAL__: true, __VARIANT__: false, - 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, }), new HtmlWebpackPlugin({ title: 'React Concurrent Mode Profiler', diff --git a/packages/react-devtools-shared/src/devtools/views/Icon.js b/packages/react-devtools-shared/src/devtools/views/Icon.js index ffa297610bdf5..c9ae931f5ee74 100644 --- a/packages/react-devtools-shared/src/devtools/views/Icon.js +++ b/packages/react-devtools-shared/src/devtools/views/Icon.js @@ -21,6 +21,7 @@ export type IconType = | 'flame-chart' | 'profiler' | 'ranked-chart' + | 'scheduling-profiler' | 'search' | 'settings' | 'store-as-global-variable' @@ -64,6 +65,9 @@ export default function Icon({className = '', type}: Props) { case 'ranked-chart': pathData = PATH_RANKED_CHART; break; + case 'scheduling-profiler': + pathData = PATH_SCHEDULING_PROFILER; + break; case 'search': pathData = PATH_SEARCH; break; @@ -136,6 +140,11 @@ const PATH_FLAME_CHART = ` const PATH_PROFILER = 'M5 9.2h3V19H5zM10.6 5h2.8v14h-2.8zm5.6 8H19v6h-2.8z'; +const PATH_SCHEDULING_PROFILER = ` + M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 + 16H5V9h14v10zm0-12H5V5h14v2zM7 11h5v5H7z +`; + const PATH_SEARCH = ` M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js index 9fda41499871e..c41b8f4fbf5cd 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js @@ -16,6 +16,7 @@ import ClearProfilingDataButton from './ClearProfilingDataButton'; import CommitFlamegraph from './CommitFlamegraph'; import CommitRanked from './CommitRanked'; import RootSelector from './RootSelector'; +import {SchedulingProfiler} from 'react-devtools-scheduling-profiler/src/SchedulingProfiler'; import RecordToggle from './RecordToggle'; import ReloadAndProfileButton from './ReloadAndProfileButton'; import ProfilingImportExportButtons from './ProfilingImportExportButtons'; @@ -42,7 +43,7 @@ function Profiler(_: {||}) { } = useContext(ProfilerContext); let view = null; - if (didRecordCommits) { + if (didRecordCommits || selectedTabID === 'scheduling-profiler') { switch (selectedTabID) { case 'flame-chart': view = ; @@ -50,6 +51,10 @@ function Profiler(_: {||}) { case 'ranked-chart': view = ; break; + case 'scheduling-profiler': + console.log('SchedulingProfiler:', SchedulingProfiler); + view = ; + break; default: break; } @@ -139,6 +144,13 @@ const tabs = [ label: 'Ranked', title: 'Ranked chart', }, + null, // Divider/separator + { + id: 'scheduling-profiler', + icon: 'scheduling-profiler', + label: 'Scheduling', + title: 'Scheduling Profiler', + }, ]; const NoProfilingData = () => ( diff --git a/packages/react-devtools-shared/src/devtools/views/TabBar.css b/packages/react-devtools-shared/src/devtools/views/TabBar.css index 57abadaecf557..96b30c3dbf550 100644 --- a/packages/react-devtools-shared/src/devtools/views/TabBar.css +++ b/packages/react-devtools-shared/src/devtools/views/TabBar.css @@ -85,6 +85,14 @@ .TabLabelSettings { } +.VRule { + height: 20px; + width: 1px; + border-left: 1px solid var(--color-border); + padding-left: 0.25rem; + margin-left: 0.25rem; +} + @media screen and (max-width: 525px) { .IconSizeNavigation { margin-right: 0; diff --git a/packages/react-devtools-shared/src/devtools/views/TabBar.js b/packages/react-devtools-shared/src/devtools/views/TabBar.js index 18664dae86b70..608c660293a86 100644 --- a/packages/react-devtools-shared/src/devtools/views/TabBar.js +++ b/packages/react-devtools-shared/src/devtools/views/TabBar.js @@ -29,7 +29,7 @@ export type Props = {| disabled?: boolean, id: string, selectTab: (tabID: any) => void, - tabs: Array, + tabs: Array, type: 'navigation' | 'profiler' | 'settings', |}; @@ -41,8 +41,9 @@ export default function TabBar({ tabs, type, }: Props) { - if (!tabs.some(tab => tab.id === currentTab)) { - selectTab(tabs[0].id); + if (!tabs.some(tab => tab !== null && tab.id === currentTab)) { + const firstTab = ((tabs.find(tab => tab !== null): any): TabInfo); + selectTab(firstTab.id); } const onChange = useCallback( @@ -88,7 +89,13 @@ export default function TabBar({ return ( - {tabs.map(({icon, id, label, title}) => { + {tabs.map(tab => { + if (tab === null) { + return
; + } + + const {icon, id, label, title} = tab; + let button = (