-
Notifications
You must be signed in to change notification settings - Fork 47.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Console dimming on second StrictMode render forces string cast #24302
Comments
I don’t see why that wouldn’t be possible. I might be missing something but my guess is that it’s a simple mistake somewhere. Do you want to have a look? |
The dimming works by using the browser's console styling API (see the "Styling console output" section of this page) which only lets you apply colors to strings because it's done via directive, e.g.: console.log('%cfoo', 'color: blue') So the React implementation has to cast to a string:
( So I don't see any way to preserve the dimming but avoid the cast. (I guess you could apply the dimming conditionally, only to args that are strings? Not sure if that's more or less confusing, and the implementation would be a bit complex because, if I understood correctly, this is also the code path that formats component stacks.) |
Yes. I think that would be fine. |
I think this is doable, it just gets a bit tricky because the console API has a mixed interface that supports both string substitutions and multiple arguments. So you need to interact with other directives. For example: // userland code:
console.log('A %d %s', 1, 'B', 2, 'C')
// needs to be transformed to:
console.log('%cA %d %s %c%o %s', 'color: grey', 1, 'B', 'color: grey', 2, 'C') Happy to try a PR. Are you confident enough in this behavior that I should get started, or do you want to discuss with anyone first? I do have one question about the existing implementation. Currently, React re-implements the directive substitutions while casting all of the args to a single string: react/packages/react-devtools-shared/src/hook.js Lines 175 to 210 in f56dfe9
I see why this is necessary when dimming the entire line, but I think it might be avoidable otherwise. So I just wondered if this has any other purpose (behavior in Node or other browser envs?) before I remove it. Didn't see anything in the implementing PR. |
I was thinking in the realm of changing react/packages/react-devtools-shared/src/hook.js Lines 293 to 294 in f56dfe9
to something like if (color) {
if (typeof args[0] === 'string') {
originalMethod(`%c${format(...args)}`, `color: ${color}`);
} else {
originalMethod(...args);
} |
Oh I see, you'd need to check all of them... I think as a first approximation it's ok to opt out if any of them are non-strings. But what you're suggesting is preferable to that. Yeah I think you can stake a stab at this. |
(This is incorrect.)
|
Seems like it would be nice to get rid of the substitution code anyway because it's a bit buggy and probably hard to get perfectly right. e.g., |
Ah sorry I misunderstood the console API: you can only specify directives in the first argument. I understand the current React implementation better now. That means the approach we discussed won't work (because of cases like |
Put up a WIP #24306 with a basic working implementation. Needs tests, callsite updates, etc. Not sure when I'll have time to continue so if anyone's eager and wants to take it over from there, feel free. |
I think the rough logic flow for this could be something like?
|
@bvaughn I've done something similar in #24306, not sure if you had a chance to look at that. I'm a bit confused by your proposal, though. If I'm understanding you correctly:
Do you mean something like:
Can you clarify how you're suggesting we'd transform
Can you clarify how you're suggesting we'd transform |
Ooops. Haven't looked at the PR yet, sorry, but just realized I accidentally swapped my "%c" and "%s" args above. |
My concern with us formatting a string that's already been formatted is that the result is unpredictable.
// [1, 'A']
console.log("%c%s %s", "color: gray", 1, "A");
// ['A', 1]
console.log("%cA %s", "color: gray;", 1); |
Seems like an accidental close? The bug is there. |
Yikes. Yes, definitely accidental. Thanks. |
Ohh, everything makes sense now. 😅 Let me respond after inverting them:
Edit: realized that the user might use
I mostly agree but However, (Could also use
I agree, aside from the same |
😱 TIL about |
@billyjanitsch Are you still working on this PR? If not, I can take it over (giving you credit of course!) Thanks so much regardless for helping us come up with a strategy to avoid string casting objects! |
@lunaruan that sounds great, thanks! Sorry I didn't wrap up the work, caught a cold over the weekend. 🙂 |
Fixes #24302 based on #24306. --- The current implementation for strict mode double logging stringiness and dims the second log. However, because we stringify everything, including objects, this causes objects to be logged as `[object Object]` etc. This PR creates a new function that formats console log arguments with a specified style. It does this by: 1. The first param is a string that contains %c: Bail out and return the args without modifying the styles. We don't want to affect styles that the developer deliberately set. 2. The first param is a string that doesn't contain %c but contains string formatting: `[`%c${args[0]}`, style, ...args.slice(1)]` Note: we assume that the string formatting that the developer uses is correct. 3. The first param is a string that doesn't contain string formatting OR is not a string: Create a formatting string where: - boolean, string, symbol -> %s - number -> %f OR %i depending on if it's an int or float - default -> %o --- Co-authored-by: Billy Janitsch <[email protected]>
Fixes facebook#24302 based on facebook#24306. --- The current implementation for strict mode double logging stringiness and dims the second log. However, because we stringify everything, including objects, this causes objects to be logged as `[object Object]` etc. This PR creates a new function that formats console log arguments with a specified style. It does this by: 1. The first param is a string that contains %c: Bail out and return the args without modifying the styles. We don't want to affect styles that the developer deliberately set. 2. The first param is a string that doesn't contain %c but contains string formatting: `[`%c${args[0]}`, style, ...args.slice(1)]` Note: we assume that the string formatting that the developer uses is correct. 3. The first param is a string that doesn't contain string formatting OR is not a string: Create a formatting string where: - boolean, string, symbol -> %s - number -> %f OR %i depending on if it's an int or float - default -> %o --- Co-authored-by: Billy Janitsch <[email protected]>
Fixes #24302 based on #24306. --- The current implementation for strict mode double logging stringiness and dims the second log. However, because we stringify everything, including objects, this causes objects to be logged as `[object Object]` etc. This PR creates a new function that formats console log arguments with a specified style. It does this by: 1. The first param is a string that contains %c: Bail out and return the args without modifying the styles. We don't want to affect styles that the developer deliberately set. 2. The first param is a string that doesn't contain %c but contains string formatting: `[`%c${args[0]}`, style, ...args.slice(1)]` Note: we assume that the string formatting that the developer uses is correct. 3. The first param is a string that doesn't contain string formatting OR is not a string: Create a formatting string where: - boolean, string, symbol -> %s - number -> %f OR %i depending on if it's an int or float - default -> %o --- Co-authored-by: Billy Janitsch <[email protected]>
React version: 18.0.0 (congrats on the release☺️ )
Steps To Reproduce
console.log(new Set())
).StrictMode
.Link to code example: https://codesandbox.io/s/magical-roman-wyeud7?file=/src/App.js
Note that the console dimming isn't applied to the inline CodeSandbox dev tools, so to see the issue, you need to visit the "fullscreen view" here: https://wyeud7.csb.app
The current behavior
In Chrome:
As expected, there are two console logs, one dimmed. Unfortunately, the way that the dimming works forces the second log to be serialized to a string. This has two issues:
console.log
call.You can kind of work around the second issue by writing your own string cast at the log callsite, but you lose the DX of introspection, which is pretty unfortunate especially in the case of large/deeply-nested objects, etc. Easier to compare two native console values than two
JSON.stringify
dumps.The expected behavior
While there is a new (appreciated!) dev tools option to suppress logging for the second render entirely, there is no way to disable the dimming feature.
Any of the following options would solve the issue:
Thanks for considering.
The text was updated successfully, but these errors were encountered: