From bc32edada7dd92276b7ce0fa2a7863a69fc4eea7 Mon Sep 17 00:00:00 2001 From: jackpope Date: Fri, 3 May 2024 14:52:18 +0000 Subject: [PATCH] Add flag to test fast jsx (#28816) Following #28768, add a path to testing Fast JSX on www. We want to measure the impact of Fast JSX and enable a path to testing before string refs are completely removed in www (which is a work in progress). Without `disableStringRefs`, we need to copy any object with a `ref` key so we can pass it through `coerceStringRef()` and copy it into the object. This de-opt path is what is gated behind `enableFastJSXWithStringRefs`. The additional checks should have no perf impact in OSS as the flags remain true there and the build output is not changed. For www, I've benchmarked the addition of the boolean checks with values cached at module scope. There is no significant change observed from our benchmarks and any latency will apply to test and control branches evenly. This added experiment complexity is temporary. We should be able to clean it up, along with the flag checks for `enableRefAsProp` and `disableStringRefs` shortly. DiffTrain build for [1beb73de0f7c3261a0de37620453b102caaa6236](https://github.com/facebook/react/commit/1beb73de0f7c3261a0de37620453b102caaa6236) --- .../facebook-www/JSXDEVRuntime-dev.classic.js | 9 ++++--- .../facebook-www/JSXDEVRuntime-dev.modern.js | 9 ++++--- compiled/facebook-www/REVISION | 2 +- compiled/facebook-www/React-dev.classic.js | 11 +++++--- compiled/facebook-www/React-dev.modern.js | 11 +++++--- compiled/facebook-www/React-prod.classic.js | 25 +++++++++++++------ compiled/facebook-www/React-prod.modern.js | 25 +++++++++++++------ .../facebook-www/React-profiling.classic.js | 25 +++++++++++++------ .../facebook-www/React-profiling.modern.js | 25 +++++++++++++------ 9 files changed, 95 insertions(+), 47 deletions(-) diff --git a/compiled/facebook-www/JSXDEVRuntime-dev.classic.js b/compiled/facebook-www/JSXDEVRuntime-dev.classic.js index 5899c2e3f9..2428105afc 100644 --- a/compiled/facebook-www/JSXDEVRuntime-dev.classic.js +++ b/compiled/facebook-www/JSXDEVRuntime-dev.classic.js @@ -25,8 +25,8 @@ var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing, enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing, enableRenderableContext = dynamicFeatureFlags.enableRenderableContext, enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, - disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses; - // On WWW, false is used for a new modern build. + disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX; // On WWW, false is used for a new modern build. // because JSX is an extremely hot path. var disableStringRefs = false; @@ -941,6 +941,9 @@ var didWarnAboutElementRef; didWarnAboutElementRef = {}; } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp; +var enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && disableStringRefs; + function hasValidRef(config) { { if (hasOwnProperty.call(config, 'ref')) { @@ -1289,7 +1292,7 @@ function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { var props; - if (enableRefAsProp && disableStringRefs && !('key' in config)) { + if ((enableFastJSXWithoutStringRefs || enableFastJSXWithStringRefs && !('ref' in config)) && !('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, diff --git a/compiled/facebook-www/JSXDEVRuntime-dev.modern.js b/compiled/facebook-www/JSXDEVRuntime-dev.modern.js index 79fba25e69..700af5662d 100644 --- a/compiled/facebook-www/JSXDEVRuntime-dev.modern.js +++ b/compiled/facebook-www/JSXDEVRuntime-dev.modern.js @@ -25,8 +25,8 @@ var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing, enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing, enableRenderableContext = dynamicFeatureFlags.enableRenderableContext, enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, - disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses; - // On WWW, true is used for a new modern build. + disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX; // On WWW, true is used for a new modern build. // because JSX is an extremely hot path. var disableStringRefs = false; @@ -944,6 +944,9 @@ var didWarnAboutElementRef; didWarnAboutElementRef = {}; } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp; +var enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && disableStringRefs; + function hasValidRef(config) { { if (hasOwnProperty.call(config, 'ref')) { @@ -1292,7 +1295,7 @@ function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { var props; - if (enableRefAsProp && disableStringRefs && !('key' in config)) { + if ((enableFastJSXWithoutStringRefs || enableFastJSXWithStringRefs && !('ref' in config)) && !('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, diff --git a/compiled/facebook-www/REVISION b/compiled/facebook-www/REVISION index c3e908ca01..7755a36186 100644 --- a/compiled/facebook-www/REVISION +++ b/compiled/facebook-www/REVISION @@ -1 +1 @@ -73bcdfbae57545aa8f88ecdf67426275610b5573 +1beb73de0f7c3261a0de37620453b102caaa6236 diff --git a/compiled/facebook-www/React-dev.classic.js b/compiled/facebook-www/React-dev.classic.js index 19d85fee84..9a72d6c9a0 100644 --- a/compiled/facebook-www/React-dev.classic.js +++ b/compiled/facebook-www/React-dev.classic.js @@ -25,7 +25,7 @@ if ( ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = '19.0.0-www-classic-e0403cc2'; + var ReactVersion = '19.0.0-www-classic-f1929680'; // Re-export dynamic flags from the www version. var dynamicFeatureFlags = require('ReactFeatureFlags'); @@ -34,8 +34,8 @@ var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing, enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing, enableRenderableContext = dynamicFeatureFlags.enableRenderableContext, enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, - disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses; - // On WWW, false is used for a new modern build. + disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX; // On WWW, false is used for a new modern build. // because JSX is an extremely hot path. var disableStringRefs = false; @@ -1224,6 +1224,9 @@ var didWarnAboutOldJSXRuntime; didWarnAboutElementRef = {}; } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp; +var enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && disableStringRefs; + function hasValidRef(config) { { if (hasOwnProperty.call(config, 'ref')) { @@ -1596,7 +1599,7 @@ function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { var props; - if (enableRefAsProp && disableStringRefs && !('key' in config)) { + if ((enableFastJSXWithoutStringRefs || enableFastJSXWithStringRefs && !('ref' in config)) && !('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, diff --git a/compiled/facebook-www/React-dev.modern.js b/compiled/facebook-www/React-dev.modern.js index 4ccca52ab9..7956b1301f 100644 --- a/compiled/facebook-www/React-dev.modern.js +++ b/compiled/facebook-www/React-dev.modern.js @@ -25,7 +25,7 @@ if ( ) { __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error()); } - var ReactVersion = '19.0.0-www-modern-65139682'; + var ReactVersion = '19.0.0-www-modern-1ac5c7b0'; // Re-export dynamic flags from the www version. var dynamicFeatureFlags = require('ReactFeatureFlags'); @@ -34,8 +34,8 @@ var enableDebugTracing = dynamicFeatureFlags.enableDebugTracing, enableTransitionTracing = dynamicFeatureFlags.enableTransitionTracing, enableRenderableContext = dynamicFeatureFlags.enableRenderableContext, enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, - disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses; - // On WWW, true is used for a new modern build. + disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX; // On WWW, true is used for a new modern build. // because JSX is an extremely hot path. var disableStringRefs = false; @@ -1227,6 +1227,9 @@ var didWarnAboutOldJSXRuntime; didWarnAboutElementRef = {}; } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp; +var enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && disableStringRefs; + function hasValidRef(config) { { if (hasOwnProperty.call(config, 'ref')) { @@ -1599,7 +1602,7 @@ function jsxDEV$1(type, config, maybeKey, isStaticChildren, source, self) { var props; - if (enableRefAsProp && disableStringRefs && !('key' in config)) { + if ((enableFastJSXWithoutStringRefs || enableFastJSXWithStringRefs && !('ref' in config)) && !('key' in config)) { // If key was not spread in, we can reuse the original props object. This // only works for `jsx`, not `createElement`, because `jsx` is a compiler // target and the compiler always passes a new object. For `createElement`, diff --git a/compiled/facebook-www/React-prod.classic.js b/compiled/facebook-www/React-prod.classic.js index c9d66ef892..084307294e 100644 --- a/compiled/facebook-www/React-prod.classic.js +++ b/compiled/facebook-www/React-prod.classic.js @@ -17,6 +17,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"), enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), @@ -93,6 +94,8 @@ function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp, + enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && !1; function ReactElement(type, key, _ref, self, source, owner, props) { enableRefAsProp && ((_ref = props.ref), (_ref = void 0 !== _ref ? _ref : null)); @@ -113,13 +116,19 @@ function jsxProd(type, config, maybeKey) { void 0 === config.ref || enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, getOwner(), type))); - maybeKey = {}; - for (var propName in config) - "key" === propName || - (!enableRefAsProp && "ref" === propName) || - (enableRefAsProp && "ref" === propName - ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) - : (maybeKey[propName] = config[propName])); + if ( + (!enableFastJSXWithoutStringRefs && + (!enableFastJSXWithStringRefs || "ref" in config)) || + "key" in config + ) { + maybeKey = {}; + for (var propName in config) + "key" === propName || + (!enableRefAsProp && "ref" === propName) || + (enableRefAsProp && "ref" === propName + ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) + : (maybeKey[propName] = config[propName])); + } else maybeKey = config; if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { config = type.defaultProps; for (var propName$0 in config) @@ -675,4 +684,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-www-classic-8ffd6973"; +exports.version = "19.0.0-www-classic-af056f91"; diff --git a/compiled/facebook-www/React-prod.modern.js b/compiled/facebook-www/React-prod.modern.js index 262c62e004..7887c56f22 100644 --- a/compiled/facebook-www/React-prod.modern.js +++ b/compiled/facebook-www/React-prod.modern.js @@ -17,6 +17,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"), enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), @@ -93,6 +94,8 @@ function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp, + enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && !1; function ReactElement(type, key, _ref, self, source, owner, props) { enableRefAsProp && ((_ref = props.ref), (_ref = void 0 !== _ref ? _ref : null)); @@ -113,13 +116,19 @@ function jsxProd(type, config, maybeKey) { void 0 === config.ref || enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, getOwner(), type))); - maybeKey = {}; - for (var propName in config) - "key" === propName || - (!enableRefAsProp && "ref" === propName) || - (enableRefAsProp && "ref" === propName - ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) - : (maybeKey[propName] = config[propName])); + if ( + (!enableFastJSXWithoutStringRefs && + (!enableFastJSXWithStringRefs || "ref" in config)) || + "key" in config + ) { + maybeKey = {}; + for (var propName in config) + "key" === propName || + (!enableRefAsProp && "ref" === propName) || + (enableRefAsProp && "ref" === propName + ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) + : (maybeKey[propName] = config[propName])); + } else maybeKey = config; if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { config = type.defaultProps; for (var propName$0 in config) @@ -675,4 +684,4 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-www-modern-8ffd6973"; +exports.version = "19.0.0-www-modern-af056f91"; diff --git a/compiled/facebook-www/React-profiling.classic.js b/compiled/facebook-www/React-profiling.classic.js index 61659dc317..da0cad706f 100644 --- a/compiled/facebook-www/React-profiling.classic.js +++ b/compiled/facebook-www/React-profiling.classic.js @@ -21,6 +21,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"), enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), @@ -97,6 +98,8 @@ function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp, + enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && !1; function ReactElement(type, key, _ref, self, source, owner, props) { enableRefAsProp && ((_ref = props.ref), (_ref = void 0 !== _ref ? _ref : null)); @@ -117,13 +120,19 @@ function jsxProd(type, config, maybeKey) { void 0 === config.ref || enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, getOwner(), type))); - maybeKey = {}; - for (var propName in config) - "key" === propName || - (!enableRefAsProp && "ref" === propName) || - (enableRefAsProp && "ref" === propName - ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) - : (maybeKey[propName] = config[propName])); + if ( + (!enableFastJSXWithoutStringRefs && + (!enableFastJSXWithStringRefs || "ref" in config)) || + "key" in config + ) { + maybeKey = {}; + for (var propName in config) + "key" === propName || + (!enableRefAsProp && "ref" === propName) || + (enableRefAsProp && "ref" === propName + ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) + : (maybeKey[propName] = config[propName])); + } else maybeKey = config; if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { config = type.defaultProps; for (var propName$0 in config) @@ -679,7 +688,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-www-classic-c1be9b80"; +exports.version = "19.0.0-www-classic-cb3c2ab2"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && diff --git a/compiled/facebook-www/React-profiling.modern.js b/compiled/facebook-www/React-profiling.modern.js index 22610ab6b0..1edca9abce 100644 --- a/compiled/facebook-www/React-profiling.modern.js +++ b/compiled/facebook-www/React-profiling.modern.js @@ -21,6 +21,7 @@ var dynamicFeatureFlags = require("ReactFeatureFlags"), enableRefAsProp = dynamicFeatureFlags.enableRefAsProp, disableDefaultPropsExceptForClasses = dynamicFeatureFlags.disableDefaultPropsExceptForClasses, + enableFastJSX = dynamicFeatureFlags.enableFastJSX, REACT_LEGACY_ELEMENT_TYPE = Symbol.for("react.element"), REACT_PORTAL_TYPE = Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = Symbol.for("react.fragment"), @@ -97,6 +98,8 @@ function getOwner() { var dispatcher = ReactSharedInternals.A; return null === dispatcher ? null : dispatcher.getOwner(); } +var enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp, + enableFastJSXWithoutStringRefs = enableFastJSXWithStringRefs && !1; function ReactElement(type, key, _ref, self, source, owner, props) { enableRefAsProp && ((_ref = props.ref), (_ref = void 0 !== _ref ? _ref : null)); @@ -117,13 +120,19 @@ function jsxProd(type, config, maybeKey) { void 0 === config.ref || enableRefAsProp || ((ref = config.ref), (ref = coerceStringRef(ref, getOwner(), type))); - maybeKey = {}; - for (var propName in config) - "key" === propName || - (!enableRefAsProp && "ref" === propName) || - (enableRefAsProp && "ref" === propName - ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) - : (maybeKey[propName] = config[propName])); + if ( + (!enableFastJSXWithoutStringRefs && + (!enableFastJSXWithStringRefs || "ref" in config)) || + "key" in config + ) { + maybeKey = {}; + for (var propName in config) + "key" === propName || + (!enableRefAsProp && "ref" === propName) || + (enableRefAsProp && "ref" === propName + ? (maybeKey.ref = coerceStringRef(config[propName], getOwner(), type)) + : (maybeKey[propName] = config[propName])); + } else maybeKey = config; if (!disableDefaultPropsExceptForClasses && type && type.defaultProps) { config = type.defaultProps; for (var propName$0 in config) @@ -679,7 +688,7 @@ exports.useSyncExternalStore = function ( exports.useTransition = function () { return ReactSharedInternals.H.useTransition(); }; -exports.version = "19.0.0-www-modern-c1be9b80"; +exports.version = "19.0.0-www-modern-cb3c2ab2"; "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&