@samitouri / QOS-React-2 / commits / 67f38366a5

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 }