Stop exporting dev-only methods in OSS production builds (#32200)

This commit is contained in:
Sebastian "Sebbie" Silbermann
2025-02-13 18:26:36 +01:00
committed by GitHub
parent c6a7e18636
commit ed8b68dd17
9 changed files with 96 additions and 29 deletions

View File

@@ -779,13 +779,5 @@ function runActTests(render, unmount, rerender) {
});
}
});
describe('throw in prod mode', () => {
// @gate !__DEV__
it('warns if you try to use act() in prod mode', () => {
expect(() => act(() => {})).toThrow(
'act(...) is not supported in production builds of React',
);
});
});
});
}

View File

@@ -50,6 +50,18 @@ describe('isomorphic act()', () => {
return text;
}
it('behavior in production', () => {
if (!__DEV__) {
if (gate('fb')) {
expect(() => act(() => {})).toThrow(
'act(...) is not supported in production builds of React',
);
} else {
expect(React).not.toHaveProperty('act');
}
}
});
// @gate __DEV__
it('bypasses queueMicrotask', async () => {
const root = ReactNoop.createRoot();

View File

@@ -31,6 +31,16 @@ describe('ReactOwnerStacks', () => {
);
}
it('behavior in production', () => {
if (!__DEV__) {
if (gate('fb')) {
expect(React).toHaveProperty('captureOwnerStack', undefined);
} else {
expect(React).not.toHaveProperty('captureOwnerStack');
}
}
});
// @gate __DEV__ && enableOwnerStacks
it('can get the component owner stacks during rendering in dev', async () => {
let stack;

View File

@@ -23,8 +23,6 @@ export type ElementRef<C> = React$ElementRef<C>;
export type Config<Props, DefaultProps> = React$Config<Props, DefaultProps>;
export type ChildrenArray<+T> = $ReadOnlyArray<ChildrenArray<T>> | T;
// Export all exports so that they're available in tests.
// We can't use export * from in Flow for some reason.
export {
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
__COMPILER_RUNTIME,

View File

@@ -0,0 +1,51 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
export {
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
__COMPILER_RUNTIME,
Children,
Component,
Fragment,
Profiler,
PureComponent,
StrictMode,
Suspense,
cloneElement,
createContext,
createElement,
createRef,
use,
forwardRef,
isValidElement,
lazy,
memo,
cache,
unstable_useCacheRefresh,
startTransition,
useId,
useCallback,
useContext,
useDebugValue,
useDeferredValue,
useEffect,
useImperativeHandle,
useInsertionEffect,
useLayoutEffect,
useMemo,
useReducer,
useOptimistic,
useRef,
useState,
useSyncExternalStore,
useTransition,
useActionState,
version,
act, // DEV-only
} from './src/ReactClient';

View File

@@ -10,7 +10,6 @@
export {
__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,
__COMPILER_RUNTIME,
act,
Children,
Component,
Fragment,

View File

@@ -78,6 +78,7 @@ function getTestFlags() {
classic: releaseChannel === 'classic',
source: !process.env.IS_BUILD,
www,
fb: www || xplat,
// These aren't flags, just a useful aliases for tests.
enableActivity: releaseChannel === 'experimental' || www || xplat,

View File

@@ -43,9 +43,9 @@ function resolveEntryFork(resolvedEntry, isFBBundle) {
}
resolvedEntry = nodePath.join(resolvedEntry, '..', entrypoint);
const developmentEntry = resolvedEntry.replace('.js', '.development.js');
if (fs.existsSync(developmentEntry)) {
return developmentEntry;
const devEntry = resolvedEntry.replace('.js', '.development.js');
if (__DEV__ && fs.existsSync(devEntry)) {
return devEntry;
}
if (fs.existsSync(resolvedEntry)) {
return resolvedEntry;
@@ -60,13 +60,20 @@ function resolveEntryFork(resolvedEntry, isFBBundle) {
__EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js'
);
const devFBEntry = resolvedFBEntry.replace('.js', '.development.js');
if (fs.existsSync(devFBEntry)) {
if (__DEV__ && fs.existsSync(devFBEntry)) {
return devFBEntry;
}
if (fs.existsSync(resolvedFBEntry)) {
return resolvedFBEntry;
}
const resolvedGenericFBEntry = resolvedEntry.replace('.js', '.fb.js');
const devGenericFBEntry = resolvedGenericFBEntry.replace(
'.js',
'.development.js'
);
if (__DEV__ && fs.existsSync(devGenericFBEntry)) {
return devGenericFBEntry;
}
if (fs.existsSync(resolvedGenericFBEntry)) {
return resolvedGenericFBEntry;
}
@@ -77,14 +84,14 @@ function resolveEntryFork(resolvedEntry, isFBBundle) {
__EXPERIMENTAL__ ? '.experimental.js' : '.stable.js'
);
const devForkedEntry = resolvedForkedEntry.replace('.js', '.development.js');
if (fs.existsSync(devForkedEntry)) {
if (__DEV__ && fs.existsSync(devForkedEntry)) {
return devForkedEntry;
}
if (fs.existsSync(resolvedForkedEntry)) {
return resolvedForkedEntry;
}
const plainDevEntry = resolvedEntry.replace('.js', '.development.js');
if (fs.existsSync(plainDevEntry)) {
if (__DEV__ && fs.existsSync(plainDevEntry)) {
return plainDevEntry;
}
// Just use the plain .js one.

View File

@@ -571,7 +571,7 @@ function shouldSkipBundle(bundle, bundleType) {
return false;
}
function resolveEntryFork(resolvedEntry, isFBBundle) {
function resolveEntryFork(resolvedEntry, isFBBundle, isDev) {
// Pick which entry point fork to use:
// .modern.fb.js
// .classic.fb.js
@@ -586,23 +586,20 @@ function resolveEntryFork(resolvedEntry, isFBBundle) {
'.js',
__EXPERIMENTAL__ ? '.modern.fb.js' : '.classic.fb.js'
);
const developmentFBEntry = resolvedFBEntry.replace(
'.js',
'.development.js'
);
if (fs.existsSync(developmentFBEntry)) {
return developmentFBEntry;
const devFBEntry = resolvedFBEntry.replace('.js', '.development.js');
if (isDev && fs.existsSync(devFBEntry)) {
return devFBEntry;
}
if (fs.existsSync(resolvedFBEntry)) {
return resolvedFBEntry;
}
const resolvedGenericFBEntry = resolvedEntry.replace('.js', '.fb.js');
const developmentGenericFBEntry = resolvedGenericFBEntry.replace(
const devGenericFBEntry = resolvedGenericFBEntry.replace(
'.js',
'.development.js'
);
if (fs.existsSync(developmentGenericFBEntry)) {
return developmentGenericFBEntry;
if (isDev && fs.existsSync(devGenericFBEntry)) {
return devGenericFBEntry;
}
if (fs.existsSync(resolvedGenericFBEntry)) {
return resolvedGenericFBEntry;
@@ -614,7 +611,7 @@ function resolveEntryFork(resolvedEntry, isFBBundle) {
__EXPERIMENTAL__ ? '.experimental.js' : '.stable.js'
);
const devForkedEntry = resolvedForkedEntry.replace('.js', '.development.js');
if (fs.existsSync(devForkedEntry)) {
if (isDev && fs.existsSync(devForkedEntry)) {
return devForkedEntry;
}
if (fs.existsSync(resolvedForkedEntry)) {
@@ -633,7 +630,7 @@ async function createBundle(bundle, bundleType) {
const {isFBWWWBundle, isFBRNBundle} = getBundleTypeFlags(bundleType);
let resolvedEntry = resolveEntryFork(
const resolvedEntry = resolveEntryFork(
require.resolve(bundle.entry),
isFBWWWBundle || isFBRNBundle,
!isProductionBundleType(bundleType)