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 5899c2e3f9c8a..2428105afccd3 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 79fba25e69ebe..700af5662dbcf 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 c3e908ca01c70..7755a36186259 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 19d85fee84005..9a72d6c9a02ff 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 4ccca52ab97e4..7956b1301f021 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 c9d66ef8924a1..084307294efa8 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 262c62e004ea8..7887c56f22b77 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 61659dc317308..da0cad706fb5c 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 22610ab6b06e4..1edca9abcedbe 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 &&