Skip to content

Commit 41e269c

Browse files
committed
[Flight] Warn once if eval is disabled in dev environment
1 parent da64117 commit 41e269c

26 files changed

+274
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
let hasConfirmedEval = false;
11+
export function checkEvalAvailabilityOnceDev(): void {
12+
if (__DEV__) {
13+
if (!hasConfirmedEval) {
14+
hasConfirmedEval = true;
15+
try {
16+
// eslint-disable-next-line no-eval
17+
(0, eval)('null');
18+
} catch {
19+
console.error(
20+
'eval() not supported in this environment. ' +
21+
'If this page was served with a `Content-Security-Policy`, ' +
22+
'make sure that `unsafe-eval` is included. ' +
23+
'React requires eval() in development mode for various debugging features ' +
24+
'like reconstructing callstacks from a different environment.\n' +
25+
'React will never use eval() in production mode',
26+
);
27+
}
28+
}
29+
} else {
30+
// These errors should never make it into a build so we don't need to encode them in codes.json
31+
// eslint-disable-next-line react-internal/prod-error-codes
32+
throw new Error(
33+
'checkEvalAvailabilityOnceDev should never be called in production mode. This is a bug in React.',
34+
);
35+
}
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
let hasConfirmedEval = false;
11+
export function checkEvalAvailabilityOnceDev(): void {
12+
if (__DEV__) {
13+
if (!hasConfirmedEval) {
14+
hasConfirmedEval = true;
15+
try {
16+
// eslint-disable-next-line no-eval
17+
(0, eval)('null');
18+
} catch {
19+
console.error(
20+
'eval() not supported in this environment. ' +
21+
'This can happen if you started the Node.js process with --disallow-code-generation-from-strings, ' +
22+
'or if `eval` was patched by other means. ' +
23+
'React requires eval() in development mode for various debugging features ' +
24+
'like reconstructing callstacks from a different environment.\n' +
25+
'React will never use eval() in production mode',
26+
);
27+
}
28+
}
29+
} else {
30+
// These errors should never make it into a build so we don't need to encode them in codes.json
31+
// eslint-disable-next-line react-internal/prod-error-codes
32+
throw new Error(
33+
'checkEvalAvailabilityOnceDev should never be called in production mode. This is a bug in React.',
34+
);
35+
}
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
let hasConfirmedEval = false;
11+
export function checkEvalAvailabilityOnceDev(): void {
12+
if (__DEV__) {
13+
if (!hasConfirmedEval) {
14+
hasConfirmedEval = true;
15+
try {
16+
// eslint-disable-next-line no-eval
17+
(0, eval)('null');
18+
} catch {
19+
console.error(
20+
'eval() is not supported in this environment. ' +
21+
'React requires eval() in development mode for various debugging features ' +
22+
'like reconstructing callstacks from a different environment.\n' +
23+
'React will never use eval() in production mode',
24+
);
25+
}
26+
}
27+
} else {
28+
// These errors should never make it into a build so we don't need to encode them in codes.json
29+
// eslint-disable-next-line react-internal/prod-error-codes
30+
throw new Error(
31+
'checkEvalAvailabilityOnceDev should never be called in production mode. This is a bug in React.',
32+
);
33+
}
34+
}

packages/react-client/src/ReactFlightClient.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
bindToConsole,
6262
rendererVersion,
6363
rendererPackageName,
64+
checkEvalAvailabilityOnceDev,
6465
} from './ReactFlightClientConfig';
6566

6667
import {
@@ -2768,6 +2769,12 @@ export function createResponse(
27682769
debugEndTime: void | number, // DEV-only
27692770
debugChannel: void | DebugChannel, // DEV-only
27702771
): WeakResponse {
2772+
// We use eval to create fake function stacks which includes Component stacks.
2773+
// A warning would be noise if you used Flight without Components and don't encounter
2774+
// errors. We're warning eagerly so that you configure your environment accordingly
2775+
// before you encounter an error.
2776+
checkEvalAvailabilityOnceDev();
2777+
27712778
return getWeakResponse(
27722779
// $FlowFixMe[invalid-constructor]: the shapes are exact here but Flow doesn't like constructors
27732780
new ResponseInstance(

packages/react-client/src/__tests__/ReactFlight-test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3715,6 +3715,12 @@ describe('ReactFlight', () => {
37153715
'\n in b (at **)' +
37163716
'\n in a (at **)',
37173717
);
3718+
assertConsoleErrorDev([
3719+
'eval() is not supported in this environment. ' +
3720+
'React requires eval() in development mode for various debugging features ' +
3721+
'like reconstructing callstacks from a different environment.\n' +
3722+
'React will never use eval() in production mode',
3723+
]);
37183724
} else {
37193725
expect(receivedError.message).toEqual(
37203726
'An error occurred in the Server Components render. The specific message is omitted in production builds to avoid leaking sensitive details. A digest property is included on this error instance which may provide additional details about the nature of the error.',

packages/react-client/src/forks/ReactFlightClientConfig.custom.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,5 @@ export const bindToConsole = $$$config.bindToConsole;
5353

5454
export const rendererVersion = $$$config.rendererVersion;
5555
export const rendererPackageName = $$$config.rendererPackageName;
56+
57+
export const checkEvalAvailabilityOnceDev = $$$config.checkEvalAvailabilityOnceDev;

packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-esm.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const rendererPackageName = 'react-server-dom-esm';
1212

1313
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
1414
export * from 'react-client/src/ReactClientConsoleConfigBrowser';
15+
export * from 'react-client/src/ReactClientDebugConfigBrowser';
1516
export * from 'react-server-dom-esm/src/client/ReactFlightClientConfigBundlerESM';
1617
export * from 'react-server-dom-esm/src/client/ReactFlightClientConfigTargetESMBrowser';
1718
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-parcel.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const rendererPackageName = 'react-server-dom-parcel';
1212

1313
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
1414
export * from 'react-client/src/ReactClientConsoleConfigBrowser';
15+
export * from 'react-client/src/ReactClientDebugConfigBrowser';
1516
export * from 'react-server-dom-parcel/src/client/ReactFlightClientConfigBundlerParcel';
1617
export * from 'react-server-dom-parcel/src/client/ReactFlightClientConfigTargetParcelBrowser';
1718
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

packages/react-client/src/forks/ReactFlightClientConfig.dom-browser-turbopack.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const rendererPackageName = 'react-server-dom-turbopack';
1212

1313
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
1414
export * from 'react-client/src/ReactClientConsoleConfigBrowser';
15+
export * from 'react-client/src/ReactClientDebugConfigBrowser';
1516
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopack';
1617
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigBundlerTurbopackBrowser';
1718
export * from 'react-server-dom-turbopack/src/client/ReactFlightClientConfigTargetTurbopackBrowser';

packages/react-client/src/forks/ReactFlightClientConfig.dom-browser.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const rendererPackageName = 'react-server-dom-webpack';
1212

1313
export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
1414
export * from 'react-client/src/ReactClientConsoleConfigBrowser';
15+
export * from 'react-client/src/ReactClientDebugConfigBrowser';
1516
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpack';
1617
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigBundlerWebpackBrowser';
1718
export * from 'react-server-dom-webpack/src/client/ReactFlightClientConfigTargetWebpackBrowser';

0 commit comments

Comments
 (0)