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

feat: __webpack_nonce__ support in SSR + Browser contexts #1022

Merged
merged 4 commits into from
Jul 23, 2017

Conversation

quantizor
Copy link
Contributor

Closes #887

html += '>'

/* eslint-disable */
const css = Object.keys(this.components).reduce((styles, key) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

was able to remove an array iteration here

const css = format(sheet.getStyleTags())

expect(html).toEqual('<h1 class="sc-a b" data-reactroot="" data-reactid="1" data-react-checksum="197727696">Hello SSR!</h1>')
expect(css).toEqual(format(`
Copy link
Contributor Author

@quantizor quantizor Jul 22, 2017

Choose a reason for hiding this comment

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

@mxstbr would you guys be open to switching these to snapshot tests? I think it might simplify things a bit.

Copy link
Member

Choose a reason for hiding this comment

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

Let's open an issue/another PR for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do. I added some new tests for previously uncovered code which use snaps but I'll do a separate PR to convert existing tests where it makes sense.

@quantizor
Copy link
Contributor Author

Not really sure why rollup is failing. The error seems to indicate the JSX isn't being transformed?

.map(key => this.components[key].css)
.join('')
const attrs = [
'type="text/css"',
Copy link
Contributor Author

@quantizor quantizor Jul 22, 2017

Choose a reason for hiding this comment

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

I think style elements don't actually need this anymore.

Copy link
Member

Choose a reason for hiding this comment

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

Let's still keep it for completeness sake. We don't control what kind of HTML type this renders in. A bit redundant in 2017, but better than having people nitpick it.

Copy link
Member

@mxstbr mxstbr left a comment

Choose a reason for hiding this comment

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

LGTM, @jollife does this fix your issue?

const css = format(sheet.getStyleTags())

expect(html).toEqual('<h1 class="sc-a b" data-reactroot="" data-reactid="1" data-react-checksum="197727696">Hello SSR!</h1>')
expect(css).toEqual(format(`
Copy link
Member

Choose a reason for hiding this comment

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

Let's open an issue/another PR for that?

Copy link
Member

@kitten kitten left a comment

Choose a reason for hiding this comment

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

Some minor nits.

But another small thing; We'll have to check that using the global keyword is fine when it runs through rollup, and if it does, we have to check whether it causes any issues when it's not bundled using webpack. i.e. do we have to add a typeof check as well instead. Any best practices that we can refer to instead of blindly testing all these cases, as I'm a little unsure about some of them?


return `<style type="text/css" ${namesAttr} ${localAttr}>\n${css}\n</style>`
return `<style ${attrs.join(' ')}>${css}</style>`
}

toReactElement(key: string) {
Copy link
Member

Choose a reason for hiding this comment

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

The same props will need to be added to this method down here

`${LOCAL_ATTR}="${this.isLocal ? 'true' : 'false'}"`,
]

/* eslint-disable no-underscore-dangle */
Copy link
Member

Choose a reason for hiding this comment

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

Can you instead just disable this globally for this file. Shouldn't be an issue.

Also what does the disabled eslint down below prevent from throwing an error? Seems like a bad idea to just disable everything without a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It was complaining about using a comma and I guess there's an eslint rule that all arrow functions have to be one-liners without curlies?

Copy link
Member

Choose a reason for hiding this comment

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

Ok, in that case, just apply the suggestion below and it should become unnecessary ;)


/* eslint-disable */
const css = Object.keys(this.components).reduce((styles, key) => {
return (styles += this.components[key].css), styles
Copy link
Member

Choose a reason for hiding this comment

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

you can just return styles + this.components[key].css and even turn it into an arrow functions. Gets rid of the mutation and is easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I actually ended up making this into a reusable function since the same thing happens in toReactElement

@quantizor
Copy link
Contributor Author

Looking into the rollup thing - might need to add this plugin: https://www.npmjs.com/package/rollup-plugin-node-globals

@quantizor
Copy link
Contributor Author

quantizor commented Jul 22, 2017

Okay I found a way around it, using this seems to work without modifying rollup:

if (typeof __webpack_nonce__ !== 'undefined') {
    attrs.push(`nonce="${__webpack_nonce__}"`)
}

Basically just letting it implicitly refer to global scope

@quantizor
Copy link
Contributor Author

@philpl addressed your comments

@quantizor
Copy link
Contributor Author

quantizor commented Jul 22, 2017

Nvm the lack of global keyword seems to only work in node 8 - looking for other solutions... fixed - had to do with the rollup commonjs plugin, see 00a9e54


expect(elements).toHaveLength(2);

expect(elements[0].props).toMatchSnapshot()
Copy link
Member

Choose a reason for hiding this comment

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

I have yet another small nit here, sorry 😉

This test is basically the same as the above one, but we care about the nonce being present and set to
the global above. So we should probably just check for this directly instead of duplicating the above snapshots and having to check manually 😄

@kitten
Copy link
Member

kitten commented Jul 23, 2017

@probablyup Awesome work! I've only got one small nit left (see above comment)

@quantizor
Copy link
Contributor Author

quantizor commented Jul 23, 2017 via email

@kitten
Copy link
Member

kitten commented Jul 23, 2017

@probablyup that's a good default testing strategy, but in this case we don't care about anything but the nonce there. We're only testing:

  • Premise: A nonce is set as a global
  • Assumption: A nonce attr/prop is present

Nothing about the rest of the output. The two concerns don't overlap :)

@quantizor
Copy link
Contributor Author

@philpl done

@kitten kitten merged commit 96e7663 into styled-components:master Jul 23, 2017
@johannesnagl
Copy link

@mxstbr sorry for Not giving any feedback. But my github handle is unfortunately Not @jollife.

Will investigate this Next week!

@mxstbr
Copy link
Member

mxstbr commented Jul 23, 2017

Oh no worries, please try it out and let us know if it works!

@johannesnagl
Copy link

Hi guys,

I tested this together with @stnwk and we found out the following:

  1. Implementation is working
  2. Nevertheless, the implementation is not using the correct __webpack_nonce__.

screen shot 2017-07-24 at 13 29 42

Clarification:

You're looking for window.__webpack_nonce__ or global.__webpack_nonce__. In our tests, when setting these values, the code is working fine. Although, WebPack itself is using the magic variable __webpack_nonce__, which is not a window or global variable.

See here:
https://github.com/webpack/webpack/blob/ab2270263e9af5b0dd83e454c20ab3aa1797424a/lib/APIPlugin.js#L26

It's getting replaced as a simple string.

So, the correct implementation would be the following:

    if (typeof __webpack_nonce__ !== 'undefined' && __webpack_nonce__) {
      this.el.setAttribute('nonce', __webpack_nonce__)
    }

We still have a problem with injectGlobal, where it's not being correctly set, but we haven't yet fully understand if it's a problem on our side or within styled-components.

@stnwk
Copy link

stnwk commented Jul 24, 2017

For the injectGlobal issue I think the following might be the reason:

In injectGlobal.js#L14 we are calling the function
inject(componentId, false, stringifyRules(rules)) on StyleSheet.js#L84 - which actually takes a forth and a fifth parameter (hash and name). But we are not passing either one of them.

In the case of being on the client-side, e.g. using BrowserStyleSheet this means the following function is called: BrowserStyleSheet.js#L61.

In this function we check wether the name parameter was passed before setting the nonce attribute, which isn't set when calling injectGlobal, because we are not passing it.

I'm not sure wether the check for the name parameter is on purpose there,
but that's the culprit I think.

Would also suggest to add a test for this specific case using injectGlobal.

Cheers :)

@kitten
Copy link
Member

kitten commented Jul 24, 2017

@probablyup are you open to creating a new PR with the above changes? :)

Fixing injectGlobal should be corrected by moving the nonce setAttribute logic out of the surrounding if-name clause, right?

@quantizor
Copy link
Contributor Author

quantizor commented Jul 24, 2017 via email

@stnwk
Copy link

stnwk commented Jul 24, 2017

Maybe taking a look at how webpack tests magic variables helps? @probablyup

@quantizor
Copy link
Contributor Author

quantizor commented Jul 24, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants