[Flight] Log error if prod elements are rendered (#34189)

This commit is contained in:
Sebastian "Sebbie" Silbermann 2025-08-13 08:47:09 +02:00 committed by GitHub
parent 14c50e344c
commit 0032b2a3ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 1 deletions

View File

@ -355,7 +355,7 @@ export function createLogAssertion(
let argIndex = 0;
// console.* could have been called with a non-string e.g. `console.error(new Error())`
// eslint-disable-next-line react-internal/safe-string-coercion
String(format).replace(/%s|%c/g, () => argIndex++);
String(format).replace(/%s|%c|%o/g, () => argIndex++);
if (argIndex !== args.length) {
if (format.includes('%c%s')) {
// We intentionally use mismatching formatting when printing badging because we don't know

View File

@ -3354,6 +3354,27 @@ function renderModelDestructive(
task.debugOwner = element._owner;
task.debugStack = element._debugStack;
task.debugTask = element._debugTask;
if (
element._owner === undefined ||
element._debugStack === undefined ||
element._debugTask === undefined
) {
let key = '';
if (element.key !== null) {
key = ' key="' + element.key + '"';
}
console.error(
'Attempted to render <%s%s> without development properties. ' +
'This is not supported. It can happen if:' +
'\n- The element is created with a production version of React but rendered in development.' +
'\n- The element was cloned with a custom function instead of `React.cloneElement`.\n' +
'The props of this element may help locate this element: %o',
element.type,
key,
element.props,
);
}
// TODO: Pop this. Since we currently don't have a point where we can pop the stack
// this debug information will be used for errors inside sibling properties that
// are not elements. Leading to the wrong attribution on the server. We could fix

View File

@ -36,6 +36,7 @@ let ReactNoopFlightServer;
let Scheduler;
let advanceTimersByTime;
let assertLog;
let assertConsoleErrorDev;
describe('ReactFlight', () => {
beforeEach(() => {
@ -64,6 +65,7 @@ describe('ReactFlight', () => {
Scheduler = require('scheduler');
const InternalTestUtils = require('internal-test-utils');
assertLog = InternalTestUtils.assertLog;
assertConsoleErrorDev = InternalTestUtils.assertConsoleErrorDev;
});
afterEach(() => {
@ -175,4 +177,26 @@ describe('ReactFlight', () => {
stackTwo: '\n in OwnerStackDelayed (at **)' + '\n in App (at **)',
});
});
it('logs an error when prod elements are rendered', async () => {
const element = ReactServer.createElement('span', {
key: 'one',
children: 'Free!',
});
ReactNoopFlightServer.render(
// bad clone
{...element},
);
assertConsoleErrorDev([
[
'Attempted to render <span key="one"> without development properties. This is not supported. It can happen if:' +
'\n- The element is created with a production version of React but rendered in development.' +
'\n- The element was cloned with a custom function instead of `React.cloneElement`.\n' +
"The props of this element may help locate this element: { children: 'Free!', [key]: [Getter] }",
{withoutStack: true},
],
"TypeError: Cannot read properties of undefined (reading 'stack')",
]);
});
});