Add consoleManagedByDevToolsDuringStrictMode feature flag in DevTools #22215
Luna Ruan committed
Aug 30, 2021 at 15:16 UTC
67f38366a570f292d51614ffa450af10628f6681
7 files changed
+144
-124
packages/react-devtools-shared/src/backend/console.js
+2
-1
@@ -14,6 +14,7 @@ import {format} from './utils';
14
15
import {getInternalReactConstants} from './renderer';
16
import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack';
17
+import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags';
18
19
const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn', 'log'];
20
const DIMMED_NODE_CONSOLE_COLOR = '\x1b[2m%s\x1b[0m';
@@ -240,7 +241,7 @@ export function patch({
241
debugger;
242
}
243
243
- if (isInStrictMode) {
244
+ if (consoleManagedByDevToolsDuringStrictMode && isInStrictMode) {
245
if (!consoleSettingsRef.hideConsoleLogsInStrictMode) {
246
// Dim the text color of the double logs if we're not
247
// hiding them.
packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-fb.js
+2
@@ -16,6 +16,8 @@
16
export const enableProfilerChangedHookIndices = true;
17
export const isInternalFacebookBuild = true;
18
19
+export const consoleManagedByDevToolsDuringStrictMode = false;
20
+
21
/************************************************************************
22
* Do not edit the code below.
23
* It ensures this fork exports the same types as the default flags file.
packages/react-devtools-shared/src/config/DevToolsFeatureFlags.core-oss.js
+2
@@ -16,6 +16,8 @@
16
export const enableProfilerChangedHookIndices = false;
17
export const isInternalFacebookBuild = false;
18
19
+export const consoleManagedByDevToolsDuringStrictMode = false;
20
+
21
/************************************************************************
22
* Do not edit the code below.
23
* It ensures this fork exports the same types as the default flags file.
packages/react-devtools-shared/src/config/DevToolsFeatureFlags.default.js
+2
@@ -15,3 +15,5 @@
15
16
export const enableProfilerChangedHookIndices = false;
17
export const isInternalFacebookBuild = false;
18
+
19
+export const consoleManagedByDevToolsDuringStrictMode = true;
packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-fb.js
+2
@@ -16,6 +16,8 @@
16
export const enableProfilerChangedHookIndices = true;
17
export const isInternalFacebookBuild = true;
18
19
+export const consoleManagedByDevToolsDuringStrictMode = true;
20
+
21
/************************************************************************
22
* Do not edit the code below.
23
* It ensures this fork exports the same types as the default flags file.
packages/react-devtools-shared/src/config/DevToolsFeatureFlags.extension-oss.js
+2
@@ -16,6 +16,8 @@
16
export const enableProfilerChangedHookIndices = true;
17
export const isInternalFacebookBuild = false;
18
19
+export const consoleManagedByDevToolsDuringStrictMode = true;
20
+
21
/************************************************************************
22
* Do not edit the code below.
23
* It ensures this fork exports the same types as the default flags file.
packages/react-devtools-shared/src/hook.js
+132
-123
@@ -16,6 +16,7 @@ import {
16
patch as patchConsole,
17
registerRenderer as registerRendererWithConsole,
18
} from './backend/console';
19
+import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags';
20
21
import type {DevToolsHook} from 'react-devtools-shared/src/backend/types';
22
@@ -162,56 +163,60 @@ export function installHook(target: any): DevToolsHook | null {
163
maybeMessage: any,
164
...inputArgs: $ReadOnlyArray<any>
165
): string {
165
- const args = inputArgs.slice();
166
-
167
- // Symbols cannot be concatenated with Strings.
168
- let formatted: string =
169
- typeof maybeMessage === 'symbol'
170
- ? maybeMessage.toString()
171
- : '' + maybeMessage;
166
+ if (consoleManagedByDevToolsDuringStrictMode) {
167
+ const args = inputArgs.slice();
168
+
169
+ // Symbols cannot be concatenated with Strings.
170
+ let formatted: string =
171
+ typeof maybeMessage === 'symbol'
172
+ ? maybeMessage.toString()
173
+ : '' + maybeMessage;
174
+
175
+ // If the first argument is a string, check for substitutions.
176
+ if (typeof maybeMessage === 'string') {
177
+ if (args.length) {
178
+ const REGEXP = /(%?)(%([jds]))/g;
179
+
180
+ formatted = formatted.replace(REGEXP, (match, escaped, ptn, flag) => {
181
+ let arg = args.shift();
182
+ switch (flag) {
183
+ case 's':
184
+ arg += '';
185
+ break;
186
+ case 'd':
187
+ case 'i':
188
+ arg = parseInt(arg, 10).toString();
189
+ break;
190
+ case 'f':
191
+ arg = parseFloat(arg).toString();
192
+ break;
193
+ }
194
+ if (!escaped) {
195
+ return arg;
196
+ }
197
+ args.unshift(arg);
198
+ return match;
199
+ });
200
+ }
201
+ }
202
173
- // If the first argument is a string, check for substitutions.
174
- if (typeof maybeMessage === 'string') {
203
+ // Arguments that remain after formatting.
204
if (args.length) {
176
- const REGEXP = /(%?)(%([jds]))/g;
177
-
178
- formatted = formatted.replace(REGEXP, (match, escaped, ptn, flag) => {
179
- let arg = args.shift();
180
- switch (flag) {
181
- case 's':
182
- arg += '';
183
- break;
184
- case 'd':
185
- case 'i':
186
- arg = parseInt(arg, 10).toString();
187
- break;
188
- case 'f':
189
- arg = parseFloat(arg).toString();
190
- break;
191
- }
192
- if (!escaped) {
193
- return arg;
194
- }
195
- args.unshift(arg);
196
- return match;
197
- });
205
+ for (let i = 0; i < args.length; i++) {
206
+ const arg = args[i];
207
+
208
+ // Symbols cannot be concatenated with Strings.
209
+ formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : arg);
210
+ }
211
}
199
- }
212
201
- // Arguments that remain after formatting.
202
- if (args.length) {
203
- for (let i = 0; i < args.length; i++) {
204
- const arg = args[i];
213
+ // Update escaped %% values.
214
+ formatted = formatted.replace(/%{2,2}/g, '%');
215
206
- // Symbols cannot be concatenated with Strings.
207
- formatted += ' ' + (typeof arg === 'symbol' ? arg.toString() : arg);
208
- }
216
+ return '' + formatted;
217
}
218
211
- // Update escaped %% values.
212
- formatted = formatted.replace(/%{2,2}/g, '%');
213
-
214
- return '' + formatted;
219
+ return '';
220
}
221
222
// NOTE: KEEP IN SYNC with src/backend/console.js:patch
@@ -222,90 +227,92 @@ export function installHook(target: any): DevToolsHook | null {
227
browserTheme,
228
}: {hideConsoleLogsInStrictMode: boolean, browserTheme: BrowserTheme},
229
): void {
225
- const overrideConsoleMethods = ['error', 'trace', 'warn', 'log'];
226
-
227
- if (__EXTENSION__) {
228
- const targetConsole = console;
229
-
230
- const originalConsoleMethods = {};
231
-
232
- overrideConsoleMethods.forEach(method => {
233
- try {
234
- const originalMethod = (originalConsoleMethods[
235
- method
236
- ] = targetConsole[method].__REACT_DEVTOOLS_ORIGINAL_METHOD__
237
- ? targetConsole[method].__REACT_DEVTOOLS_ORIGINAL_METHOD__
238
- : targetConsole[method]);
239
-
240
- const overrideMethod = (...args) => {
241
- let isInStrictMode = false;
242
-
243
- // Search for the first renderer that has a current Fiber.
244
- // We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?)
245
- const {getCurrentFiber, getIsStrictMode} = renderer;
246
- if (typeof getCurrentFiber !== 'function') {
247
- return;
248
- }
249
-
250
- const current: ?Fiber = getCurrentFiber();
251
- if (current != null) {
252
- try {
253
- if (
254
- typeof getIsStrictMode === 'function' &&
255
- getIsStrictMode()
256
- ) {
257
- isInStrictMode = true;
258
- }
259
- } catch (error) {
260
- // Don't let a DevTools or React internal error interfere with logging.
230
+ if (consoleManagedByDevToolsDuringStrictMode) {
231
+ const overrideConsoleMethods = ['error', 'trace', 'warn', 'log'];
232
+
233
+ if (__EXTENSION__) {
234
+ const targetConsole = console;
235
+
236
+ const originalConsoleMethods = {};
237
+
238
+ overrideConsoleMethods.forEach(method => {
239
+ try {
240
+ const originalMethod = (originalConsoleMethods[
241
+ method
242
+ ] = targetConsole[method].__REACT_DEVTOOLS_ORIGINAL_METHOD__
243
+ ? targetConsole[method].__REACT_DEVTOOLS_ORIGINAL_METHOD__
244
+ : targetConsole[method]);
245
+
246
+ const overrideMethod = (...args) => {
247
+ let isInStrictMode = false;
248
+
249
+ // Search for the first renderer that has a current Fiber.
250
+ // We don't handle the edge case of stacks for more than one (e.g. interleaved renderers?)
251
+ const {getCurrentFiber, getIsStrictMode} = renderer;
252
+ if (typeof getCurrentFiber !== 'function') {
253
+ return;
254
}
262
- }
255
264
- if (isInStrictMode) {
265
- if (!hideConsoleLogsInStrictMode) {
266
- // Dim the text color of the double logs if we're not
267
- // hiding them.
268
- let color;
269
- switch (method) {
270
- case 'warn':
271
- color =
272
- browserTheme === 'light'
273
- ? process.env.LIGHT_MODE_DIMMED_WARNING_COLOR
274
- : process.env.DARK_MODE_DIMMED_WARNING_COLOR;
275
- break;
276
- case 'error':
277
- color =
278
- browserTheme === 'light'
279
- ? process.env.LIGHT_MODE_DIMMED_ERROR_COLOR
280
- : process.env.DARK_MODE_DIMMED_ERROR_COLOR;
281
- break;
282
- case 'log':
283
- default:
284
- color =
285
- browserTheme === 'light'
286
- ? process.env.LIGHT_MODE_DIMMED_LOG_COLOR
287
- : process.env.DARK_MODE_DIMMED_LOG_COLOR;
288
- break;
256
+ const current: ?Fiber = getCurrentFiber();
257
+ if (current != null) {
258
+ try {
259
+ if (
260
+ typeof getIsStrictMode === 'function' &&
261
+ getIsStrictMode()
262
+ ) {
263
+ isInStrictMode = true;
264
+ }
265
+ } catch (error) {
266
+ // Don't let a DevTools or React internal error interfere with logging.
267
}
268
+ }
269
291
- if (color) {
292
- originalMethod(`%c${format(...args)}`, `color: ${color}`);
293
- } else {
294
- throw Error('Console color is not defined');
270
+ if (isInStrictMode) {
271
+ if (!hideConsoleLogsInStrictMode) {
272
+ // Dim the text color of the double logs if we're not
273
+ // hiding them.
274
+ let color;
275
+ switch (method) {
276
+ case 'warn':
277
+ color =
278
+ browserTheme === 'light'
279
+ ? process.env.LIGHT_MODE_DIMMED_WARNING_COLOR
280
+ : process.env.DARK_MODE_DIMMED_WARNING_COLOR;
281
+ break;
282
+ case 'error':
283
+ color =
284
+ browserTheme === 'light'
285
+ ? process.env.LIGHT_MODE_DIMMED_ERROR_COLOR
286
+ : process.env.DARK_MODE_DIMMED_ERROR_COLOR;
287
+ break;
288
+ case 'log':
289
+ default:
290
+ color =
291
+ browserTheme === 'light'
292
+ ? process.env.LIGHT_MODE_DIMMED_LOG_COLOR
293
+ : process.env.DARK_MODE_DIMMED_LOG_COLOR;
294
+ break;
295
+ }
296
+
297
+ if (color) {
298
+ originalMethod(`%c${format(...args)}`, `color: ${color}`);
299
+ } else {
300
+ throw Error('Console color is not defined');
301
+ }
302
}
303
+ } else {
304
+ originalMethod(...args);
305
}
297
- } else {
298
- originalMethod(...args);
299
- }
300
- };
306
+ };
307
302
- overrideMethod.__REACT_DEVTOOLS_ORIGINAL_METHOD__ = originalMethod;
303
- originalMethod.__REACT_DEVTOOLS_OVERRIDE_METHOD__ = overrideMethod;
308
+ overrideMethod.__REACT_DEVTOOLS_ORIGINAL_METHOD__ = originalMethod;
309
+ originalMethod.__REACT_DEVTOOLS_OVERRIDE_METHOD__ = overrideMethod;
310
305
- // $FlowFixMe property error|warn is not writable.
306
- targetConsole[method] = overrideMethod;
307
- } catch (error) {}
308
- });
311
+ // $FlowFixMe property error|warn is not writable.
312
+ targetConsole[method] = overrideMethod;
313
+ } catch (error) {}
314
+ });
315
+ }
316
}
317
}
318
@@ -365,10 +372,12 @@ export function installHook(target: any): DevToolsHook | null {
372
browserTheme,
373
});
374
} else {
368
- patchConsoleForInitialRenderInExtension(renderer, {
369
- hideConsoleLogsInStrictMode,
370
- browserTheme,
371
- });
375
+ if (consoleManagedByDevToolsDuringStrictMode) {
376
+ patchConsoleForInitialRenderInExtension(renderer, {
377
+ hideConsoleLogsInStrictMode,
378
+ browserTheme,
379
+ });
380
+ }
381
}
382
} catch (error) {}
383
}