Skip to content
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

Allow nonce to be used on hoistable styles #32461

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link
Contributor

fixes #32449

This is my first time touching this code. There are multiple systems in place here and I wouldn't be surprised to learn that this has to be handled in some other areas too. I have found some other style-related code areas but I had no time yet to double-check them.

cc @gnoff

@react-sizebot
Copy link

react-sizebot commented Feb 23, 2025

Comparing: 9b042f9...8b79d87

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js = 6.68 kB 6.68 kB = 1.83 kB 1.83 kB
oss-stable/react-dom/cjs/react-dom-client.production.js = 515.71 kB 515.71 kB = 92.09 kB 92.09 kB
oss-experimental/react-dom/cjs/react-dom.production.js = 6.69 kB 6.69 kB = 1.83 kB 1.83 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js = 565.64 kB 565.64 kB = 100.84 kB 100.84 kB
facebook-www/ReactDOM-prod.classic.js = 636.70 kB 636.70 kB = 112.08 kB 112.08 kB
facebook-www/ReactDOM-prod.modern.js = 627.02 kB 627.02 kB = 110.50 kB 110.49 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable-semver/react-dom/cjs/react-dom-server.browser.development.js +0.29% 377.39 kB 378.49 kB +0.25% 67.79 kB 67.95 kB
oss-stable/react-dom/cjs/react-dom-server.browser.development.js +0.29% 377.46 kB 378.57 kB +0.25% 67.84 kB 68.00 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.development.js +0.29% 378.17 kB 379.28 kB +0.24% 67.94 kB 68.10 kB
oss-stable/react-dom/cjs/react-dom-server.edge.development.js +0.29% 378.24 kB 379.35 kB +0.24% 67.99 kB 68.15 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.development.js +0.29% 322.09 kB 323.01 kB +0.25% 62.58 kB 62.73 kB
oss-stable/react-dom/cjs/react-dom-server.bun.development.js +0.29% 322.17 kB 323.09 kB +0.25% 62.61 kB 62.76 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.development.js +0.28% 373.93 kB 374.99 kB +0.25% 67.16 kB 67.33 kB
oss-stable/react-dom/cjs/react-dom-server.node.development.js +0.28% 374.00 kB 375.06 kB +0.25% 67.22 kB 67.38 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.production.js +0.28% 230.00 kB 230.63 kB +0.32% 41.13 kB 41.27 kB
oss-stable/react-dom/cjs/react-dom-server.browser.production.js +0.28% 230.07 kB 230.71 kB +0.33% 41.16 kB 41.29 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.production.js +0.27% 235.19 kB 235.83 kB +0.26% 43.11 kB 43.23 kB
oss-stable/react-dom/cjs/react-dom-server.edge.production.js +0.27% 235.27 kB 235.91 kB +0.26% 43.14 kB 43.25 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.development.js +0.27% 412.03 kB 413.14 kB +0.24% 71.39 kB 71.56 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.development.js +0.27% 412.81 kB 413.92 kB +0.24% 71.57 kB 71.75 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.development.js +0.27% 345.73 kB 346.65 kB +0.24% 65.48 kB 65.64 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.development.js +0.26% 361.70 kB 362.66 kB +0.25% 65.63 kB 65.79 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.26% 361.71 kB 362.66 kB +0.25% 65.63 kB 65.79 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.development.js +0.26% 361.73 kB 362.68 kB +0.25% 65.66 kB 65.82 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.26% 361.73 kB 362.69 kB +0.25% 65.66 kB 65.82 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.production.js +0.26% 231.72 kB 232.33 kB +0.29% 42.11 kB 42.24 kB
oss-stable/react-dom/cjs/react-dom-server.node.production.js +0.26% 231.80 kB 232.40 kB +0.29% 42.14 kB 42.26 kB
oss-experimental/react-dom/cjs/react-dom-server.node.development.js +0.26% 407.97 kB 409.03 kB +0.24% 70.84 kB 71.01 kB
facebook-www/ReactDOMServer-dev.modern.js +0.26% 372.75 kB 373.70 kB +0.24% 67.11 kB 67.27 kB
facebook-www/ReactDOMServer-dev.classic.js +0.25% 379.60 kB 380.55 kB +0.24% 68.12 kB 68.28 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.js +0.25% 256.40 kB 257.04 kB +0.29% 44.21 kB 44.34 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.development.js +0.25% 386.95 kB 387.91 kB +0.24% 68.54 kB 68.71 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.25% 386.96 kB 387.91 kB +0.24% 68.54 kB 68.71 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.js +0.24% 262.20 kB 262.83 kB +0.27% 46.30 kB 46.43 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js +0.24% 364.45 kB 365.31 kB +0.24% 65.83 kB 65.99 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.js +0.24% 258.23 kB 258.84 kB +0.25% 45.37 kB 45.48 kB
oss-experimental/react-markup/cjs/react-markup.development.js +0.23% 357.49 kB 358.33 kB +0.23% 64.09 kB 64.24 kB
test_utils/ReactAllWarnings.js +0.23% 63.51 kB 63.66 kB +0.20% 15.89 kB 15.92 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.production.js +0.21% 215.32 kB 215.76 kB +0.20% 39.64 kB 39.72 kB
oss-stable/react-dom/cjs/react-dom-server.bun.production.js +0.21% 215.39 kB 215.84 kB +0.20% 39.67 kB 39.75 kB

Generated by 🚫 dangerJS against cf5d7dd

Comment on lines +2767 to +2770
if (!('nonce' in styleQueue)) {
// `styleQueue` could have been created by `preinit` where `nonce` is not required
styleQueue.nonce = nonce && stringToChunk(escapeTextForBrowser(nonce));
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should just consult the the one from the renderState? I'm not sure if it's a user requirement to pass nonce to renderToPipeableStream though and then maintain the consistency across the tree .

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've thought about whether we should auto-nonce styles and scripts but have held off b/c you aren't necessarily in control of every tag you emit and so it's a little safer to still require the author pass these nonces around. However it's not really great protection b/c if you have a compromised package you are probably in trouble in many other ways too.

That said the nonce argument is implied to be for scripts and while rare it's technically possible for the nonce for styles to be different than the nonce for scripts so we'd have to expose another new option. Worth considering perhaps but I think making it just work with rendered props is the way to go

Copy link
Collaborator

@gnoff gnoff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look very promising. left some notes for you. lmk if you have any questions

Comment on lines +2767 to +2770
if (!('nonce' in styleQueue)) {
// `styleQueue` could have been created by `preinit` where `nonce` is not required
styleQueue.nonce = nonce && stringToChunk(escapeTextForBrowser(nonce));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we've thought about whether we should auto-nonce styles and scripts but have held off b/c you aren't necessarily in control of every tag you emit and so it's a little safer to still require the author pass these nonces around. However it's not really great protection b/c if you have a compromised package you are probably in trouble in many other ways too.

That said the nonce argument is implied to be for scripts and while rare it's technically possible for the nonce for styles to be different than the nonce for scripts so we'd have to expose another new option. Worth considering perhaps but I think making it just work with rendered props is the way to go

@@ -5534,6 +5561,7 @@ export type StyleQueue = {
rules: Array<Chunk | PrecomputedChunk>,
hrefs: Array<Chunk | PrecomputedChunk>,
sheets: Map<string, StylesheetResource>,
nonce?: ?Chunk,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make the property required. fewer hidden class lookups when the nonce is added later

};
renderState.styles.set(precedence, styleQueue);
} else {
if (!('nonce' in styleQueue)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The nonce should be known early even if using preinitStyle. we can assume whatever nonce was used at styleQueue creation time is sufficient for all other style rules and don't need this lazy nonce check.

We can separately add a dev only warning which indicates when you are passing incompatible nonces to style tags. You would do this by having a dev only extra property like

const styleQueue = {
  ...
}
if (__DEV__) {
  styleQueue.__nonceString = nonce
}

It wouldn't be part of the type and you'd have to type cast to any when you read it

styleQueue.nonce = nonce && stringToChunk(escapeTextForBrowser(nonce));
}
if (__DEV__) {
if (nonce !== styleQueue.nonce) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this won't work b/c Chunks are sometimes objects (typed arrays). But if you do what I suggested above you can use a dev only string version of the nonce to determine if this warning is necessary

if (nonce !== styleQueue.nonce) {
console.error(
'React encountered a hoistable style tag with "%s" nonce. It doesn\'t match the previously encountered nonce "%s". They have to be the same',
nonce && stringToChunk(escapeTextForBrowser(nonce)),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to log a chunk here, it could be a typed array.

);
});

// @gate __DEV__
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the right way to assert warnings is to use assertConsoleErrorDev inside a test that isn't gated specifically on dev environment.

In this case you might want to assert the existed behavior that both rules are included in the final output style tag regardless of the bad nonce and that in dev you get a warning for it. In this case you're not actually asserting that the program output any styles at all so while I suspect it works it'd be good to encode the expected semantic even when the test is about the warning

@facebook facebook deleted a comment from Alexectramagneta Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

nonce is dropped from style tags that use precedence
4 participants