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.
This commit is contained in:
Jack Pope
2024-05-03 10:47:13 -04:00
committed by GitHub
parent 1d618a9cf3
commit 1beb73de0f
10 changed files with 26 additions and 6 deletions
@@ -375,9 +375,8 @@ describe('ReactJSXRuntime', () => {
expect(didCall).toBe(false);
});
// @gate enableRefAsProp
// @gate disableStringRefs
it('does not clone props object if key is not spread', async () => {
// @gate enableFastJSX && enableRefAsProp
it('does not clone props object if key and ref is not spread', async () => {
const config = {
foo: 'foo',
bar: 'bar',
@@ -386,7 +385,7 @@ describe('ReactJSXRuntime', () => {
const element = __DEV__
? JSXDEVRuntime.jsxDEV('div', config)
: JSXRuntime.jsx('div', config);
expect(element.props).toBe(config);
expect(Object.is(element.props, config)).toBe(true);
const configWithKey = {
foo: 'foo',
+15 -2
View File
@@ -22,6 +22,7 @@ import {
enableRefAsProp,
disableStringRefs,
disableDefaultPropsExceptForClasses,
enableFastJSX,
} from 'shared/ReactFeatureFlags';
import {checkPropStringCoercion} from 'shared/CheckStringCoercion';
import {ClassComponent} from 'react-reconciler/src/ReactWorkTags';
@@ -51,6 +52,10 @@ if (__DEV__) {
didWarnAboutElementRef = {};
}
const enableFastJSXWithStringRefs = enableFastJSX && enableRefAsProp;
const enableFastJSXWithoutStringRefs =
enableFastJSXWithStringRefs && disableStringRefs;
function hasValidRef(config) {
if (__DEV__) {
if (hasOwnProperty.call(config, 'ref')) {
@@ -355,7 +360,11 @@ export function jsxProd(type, config, maybeKey) {
}
let 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`,
@@ -578,7 +587,11 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
}
let 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`,
+1
View File
@@ -185,6 +185,7 @@ export const enableInfiniteRenderLoopDetection = true;
// during element creation.
export const enableRefAsProp = true;
export const disableStringRefs = true;
export const enableFastJSX = true;
// Warn on any usage of ReactTestRenderer
export const enableReactTestRendererWarning = true;
@@ -98,6 +98,7 @@ export const enableServerComponentLogs = true;
// because JSX is an extremely hot path.
export const enableRefAsProp = false;
export const disableStringRefs = false;
export const enableFastJSX = false;
export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;
@@ -20,6 +20,7 @@ import typeof * as ExportsType from './ReactFeatureFlags.native-oss';
const __TODO_NEXT_RN_MAJOR__ = false;
export const enableRefAsProp = __TODO_NEXT_RN_MAJOR__;
export const disableStringRefs = __TODO_NEXT_RN_MAJOR__;
export const enableFastJSX = __TODO_NEXT_RN_MAJOR__;
export const disableLegacyMode = __TODO_NEXT_RN_MAJOR__;
export const disableDOMTestUtils = __TODO_NEXT_RN_MAJOR__;
export const useModernStrictMode = __TODO_NEXT_RN_MAJOR__;
@@ -91,6 +91,7 @@ export const renameElementSymbol = true;
// const __NEXT_MAJOR__ = __EXPERIMENTAL__;
export const enableRefAsProp = true;
export const disableStringRefs = true;
export const enableFastJSX = true;
export const disableLegacyMode = true;
export const disableLegacyContext = true;
export const disableDOMTestUtils = true;
@@ -82,6 +82,7 @@ export const enableServerComponentLogs = true;
export const enableRefAsProp = false;
export const disableStringRefs = false;
export const enableFastJSX = false;
export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;
@@ -82,6 +82,7 @@ export const enableInfiniteRenderLoopDetection = false;
export const enableRefAsProp = false;
export const disableStringRefs = false;
export const enableFastJSX = false;
export const enableReactTestRendererWarning = false;
export const disableLegacyMode = false;
@@ -24,6 +24,7 @@ export const enableDO_NOT_USE_disableStrictPassiveEffect = __VARIANT__;
export const enableUseDeferredValueInitialArg = __VARIANT__;
export const enableRenderableContext = __VARIANT__;
export const enableRefAsProp = __VARIANT__;
export const enableFastJSX = __VARIANT__;
export const enableRetryLaneExpiration = __VARIANT__;
export const favorSafetyOverHydrationPerf = __VARIANT__;
export const disableDefaultPropsExceptForClasses = __VARIANT__;
@@ -36,6 +36,7 @@ export const {
disableDefaultPropsExceptForClasses,
enableNoCloningMemoCache,
enableAddPropertiesFastPath,
enableFastJSX,
} = dynamicFeatureFlags;
// On WWW, __EXPERIMENTAL__ is used for a new modern build.