diff --git a/.eslintrc.js b/.eslintrc.js index 036df09251..cb2d737a12 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -201,9 +201,11 @@ module.exports = { spyOnDev: true, spyOnDevAndProd: true, spyOnProd: true, - __PROFILE__: true, - __UMD__: true, __EXPERIMENTAL__: true, + __EXTENSION__: true, + __PROFILE__: true, + __TEST__: true, + __UMD__: true, __VARIANT__: true, gate: true, trustedTypes: true, diff --git a/packages/react-devtools-core/webpack.backend.js b/packages/react-devtools-core/webpack.backend.js index b0809234ff..f111d7330c 100644 --- a/packages/react-devtools-core/webpack.backend.js +++ b/packages/react-devtools-core/webpack.backend.js @@ -4,6 +4,7 @@ const { GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); +const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -39,17 +40,20 @@ module.exports = { resolve: { alias: { react: resolve(builtModulesDir, 'react'), - 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'), + 'react-devtools-feature-flags': resolveFeatureFlags('core/backend'), + 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-is': resolve(builtModulesDir, 'react-is'), scheduler: resolve(builtModulesDir, 'scheduler'), }, }, plugins: [ new DefinePlugin({ - __DEV__: true, - __PROFILE__: false, + __DEV__, __EXPERIMENTAL__: true, + __EXTENSION__: false, + __PROFILE__: false, + __TEST__: NODE_ENV === 'test', 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, }), diff --git a/packages/react-devtools-core/webpack.standalone.js b/packages/react-devtools-core/webpack.standalone.js index 4d00d0f2d3..64556ae658 100644 --- a/packages/react-devtools-core/webpack.standalone.js +++ b/packages/react-devtools-core/webpack.standalone.js @@ -4,6 +4,7 @@ const { GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); +const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -33,8 +34,9 @@ module.exports = { resolve: { alias: { react: resolve(builtModulesDir, 'react'), - 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'), + 'react-devtools-feature-flags': resolveFeatureFlags('core/standalone'), + 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-is': resolve(builtModulesDir, 'react-is'), scheduler: resolve(builtModulesDir, 'scheduler'), }, @@ -47,9 +49,11 @@ module.exports = { }, plugins: [ new DefinePlugin({ - __DEV__: false, - __PROFILE__: false, + __DEV__, __EXPERIMENTAL__: true, + __EXTENSION__: false, + __PROFILE__: false, + __TEST__: NODE_ENV === 'test', 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js index e2720ec240..1a406ccdaf 100644 --- a/packages/react-devtools-extensions/webpack.config.js +++ b/packages/react-devtools-extensions/webpack.config.js @@ -3,6 +3,7 @@ const {resolve} = require('path'); const {DefinePlugin} = require('webpack'); const {GITHUB_URL, getVersionString} = require('./utils'); +const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -39,6 +40,7 @@ module.exports = { alias: { react: resolve(builtModulesDir, 'react'), 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'), + 'react-devtools-feature-flags': resolveFeatureFlags('extension'), 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-is': resolve(builtModulesDir, 'react-is'), scheduler: resolve(builtModulesDir, 'scheduler'), @@ -49,9 +51,11 @@ module.exports = { }, plugins: [ new DefinePlugin({ - __DEV__: false, - __PROFILE__: false, + __DEV__, __EXPERIMENTAL__: true, + __EXTENSION__: true, + __PROFILE__: false, + __TEST__: NODE_ENV === 'test', 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, diff --git a/packages/react-devtools-inline/webpack.config.js b/packages/react-devtools-inline/webpack.config.js index 85c7da82ea..af829455c6 100644 --- a/packages/react-devtools-inline/webpack.config.js +++ b/packages/react-devtools-inline/webpack.config.js @@ -4,6 +4,7 @@ const { GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); +const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -11,7 +12,7 @@ if (!NODE_ENV) { process.exit(1); } -const __DEV__ = true; // NODE_ENV === 'development'; +const __DEV__ = NODE_ENV === 'development'; const DEVTOOLS_VERSION = getVersionString(); @@ -32,6 +33,7 @@ module.exports = { react: 'react', // TODO: Once this package is published, remove the external // 'react-debug-tools': 'react-debug-tools', + 'react-devtools-feature-flags': resolveFeatureFlags('inline'), 'react-dom': 'react-dom', 'react-is': 'react-is', scheduler: 'scheduler', @@ -42,8 +44,10 @@ module.exports = { plugins: [ new DefinePlugin({ __DEV__, - __PROFILE__: false, __EXPERIMENTAL__: true, + __EXTENSION__: false, + __PROFILE__: false, + __TEST__: NODE_ENV === 'test', 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.NODE_ENV': `"${NODE_ENV}"`, diff --git a/packages/react-devtools-shared/buildUtils.js b/packages/react-devtools-shared/buildUtils.js new file mode 100644 index 0000000000..d5f48d6342 --- /dev/null +++ b/packages/react-devtools-shared/buildUtils.js @@ -0,0 +1,33 @@ +/** + * 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 {resolve} = require('path'); + +function resolveFeatureFlags(target) { + let flagsPath; + switch (target) { + case 'core/backend': + case 'core/standalone': + case 'inline': + case 'shell': + flagsPath = 'DevToolsFeatureFlags.default'; + break; + case 'extension': + flagsPath = 'DevToolsFeatureFlags.extension'; + break; + default: + console.error(`Invalid target "${target}"`); + process.exit(1); + } + + return resolve(__dirname, 'src/config/', flagsPath); +} + +module.exports = { + resolveFeatureFlags, +}; diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js new file mode 100644 index 0000000000..9e2d09d630 --- /dev/null +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js @@ -0,0 +1,16 @@ +/** + * 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 + */ + +/************************************************************************ + * This file is forked between different DevTools implementations. + * It should never be imported directly! + * It should always be imported from "react-devtools-feature-flags". + ************************************************************************/ + +// TODO Add feature flags here... diff --git a/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension.js b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension.js new file mode 100644 index 0000000000..a224621bb7 --- /dev/null +++ b/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension.js @@ -0,0 +1,29 @@ +/** + * 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 + */ + +/************************************************************************ + * This file is forked between different DevTools implementations. + * It should never be imported directly! + * It should always be imported from "react-devtools-feature-flags". + ************************************************************************/ + +// TODO Add feature flags here... + +/************************************************************************ + * Do not edit the code below. + * It ensures this fork exports the same types as the default flags file. + ************************************************************************/ + +import typeof * as FeatureFlagsType from './DevToolsFeatureFlags.default'; +import typeof * as ExportsType from './DevToolsFeatureFlags.extension'; + +// eslint-disable-next-line no-unused-vars +type Check<_X, Y: _X, X: Y = _X> = null; +// eslint-disable-next-line no-unused-expressions +(null: Check); diff --git a/packages/react-devtools-shared/src/hook.js b/packages/react-devtools-shared/src/hook.js index f9f65df7fb..62234fdc46 100644 --- a/packages/react-devtools-shared/src/hook.js +++ b/packages/react-devtools-shared/src/hook.js @@ -172,7 +172,11 @@ export function installHook(target: any): DevToolsHook | null { // In that case, we'll patch later (when the frontend attaches). // // Don't patch in test environments because we don't want to interfere with Jest's own console overrides. - if (process.env.NODE_ENV !== 'test') { + // + // Note that because this function is inlined, this conditional check must only use static booleans. + // Otherwise the extension will throw with an undefined error. + // (See comments in the try/catch below for more context on inlining.) + if (!__EXTENSION__ && !__TEST__) { try { const appendComponentStack = window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ !== false; diff --git a/packages/react-devtools-shell/webpack.config.js b/packages/react-devtools-shell/webpack.config.js index 500fed2fb1..c61e885029 100644 --- a/packages/react-devtools-shell/webpack.config.js +++ b/packages/react-devtools-shell/webpack.config.js @@ -4,6 +4,7 @@ const { GITHUB_URL, getVersionString, } = require('react-devtools-extensions/utils'); +const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils'); const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { @@ -33,8 +34,9 @@ const config = { resolve: { alias: { react: resolve(builtModulesDir, 'react'), - 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'), + 'react-devtools-feature-flags': resolveFeatureFlags('shell'), + 'react-dom': resolve(builtModulesDir, 'react-dom'), 'react-is': resolve(builtModulesDir, 'react-is'), scheduler: resolve(builtModulesDir, 'scheduler'), }, @@ -45,8 +47,10 @@ const config = { plugins: [ new DefinePlugin({ __DEV__, - __PROFILE__: false, __EXPERIMENTAL__: true, + __EXTENSION__: false, + __PROFILE__: false, + __TEST__: NODE_ENV === 'test', 'process.env.GITHUB_URL': `"${GITHUB_URL}"`, 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`, }), diff --git a/scripts/flow/createFlowConfigs.js b/scripts/flow/createFlowConfigs.js index ff7bf1b9c6..62a54d1112 100644 --- a/scripts/flow/createFlowConfigs.js +++ b/scripts/flow/createFlowConfigs.js @@ -53,6 +53,7 @@ module.name_mapper='ReactServerStreamConfig$$' -> 'forks/ReactServerStreamConfig module.name_mapper='ReactServerFormatConfig$$' -> 'forks/ReactServerFormatConfig.${serverRenderer}' module.name_mapper='ReactFlightServerConfig$$' -> 'forks/ReactFlightServerConfig.${serverRenderer}' module.name_mapper='ReactFlightClientHostConfig$$' -> 'forks/ReactFlightClientHostConfig.${serverRenderer}' +module.name_mapper='react-devtools-feature-flags' -> 'react-devtools-shared/src/config/DevToolsFeatureFlags.default' `.trim(), ) .replace('%REACT_RENDERER_FLOW_IGNORES%', ignoredPaths.join('\n')); diff --git a/scripts/flow/react-devtools.js b/scripts/flow/react-devtools.js index bab0373511..c8a8789de4 100644 --- a/scripts/flow/react-devtools.js +++ b/scripts/flow/react-devtools.js @@ -7,4 +7,5 @@ * @flow */ -// No types +declare var __EXTENSION__: boolean; +declare var __TEST__: boolean; diff --git a/scripts/jest/config.build-devtools.js b/scripts/jest/config.build-devtools.js index 494cc4a8e7..7f1cd88559 100644 --- a/scripts/jest/config.build-devtools.js +++ b/scripts/jest/config.build-devtools.js @@ -26,6 +26,9 @@ const packages = readdirSync(packagesRoot).filter(dir => { // Create a module map to point React packages to the build output const moduleNameMapper = {}; +moduleNameMapper['react-devtools-feature-flags'] = + '/packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default'; + // Map packages to bundles packages.forEach(name => { // Root entry point diff --git a/scripts/jest/setupEnvironment.js b/scripts/jest/setupEnvironment.js index 456645cdda..2ba88b1561 100644 --- a/scripts/jest/setupEnvironment.js +++ b/scripts/jest/setupEnvironment.js @@ -5,6 +5,8 @@ if (NODE_ENV !== 'development' && NODE_ENV !== 'production') { throw new Error('NODE_ENV must either be set to development or production.'); } global.__DEV__ = NODE_ENV === 'development'; +global.__EXTENSION__ = false; +global.__TEST__ = NODE_ENV === 'test'; global.__PROFILE__ = NODE_ENV === 'development'; global.__UMD__ = false; diff --git a/scripts/jest/typescript/jest.d.ts b/scripts/jest/typescript/jest.d.ts index ef5ec332bb..ca68247fb9 100644 --- a/scripts/jest/typescript/jest.d.ts +++ b/scripts/jest/typescript/jest.d.ts @@ -1,5 +1,7 @@ declare var jasmine: any; declare var __DEV__: boolean; +declare var __TEST__: boolean; +declare var __EXTENSION__: boolean; declare function afterEach(fn: any): any; declare function beforeEach(fn: any): any;