-
Notifications
You must be signed in to change notification settings - Fork 27k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an example for styled-jsx with content security policy (#23021)
This is an example on how to use styled-jsx with content security policy.
- Loading branch information
1 parent
0ec58c6
commit c1b2b3f
Showing
6 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
|
||
# vercel | ||
.vercel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Styled-JSX with Content Security Policy | ||
|
||
This example showcases how you can use `nonce` for `style-src` directive in `Content Security Policy` with `styled-jsx`. | ||
|
||
Checkout the [demo](https://styled-jsx-with-csp.vercel.app/) and notice the following, | ||
|
||
- `style-src` directive in `Content-Security-Policy` response header. | ||
- `meta` tag to pass on the `nonce` to styled-jsx for client-side rendering. | ||
- `style` tags with `nonce` attributes. | ||
|
||
## Deploy your own | ||
|
||
Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example): | ||
|
||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/styled-jsx-with-csp&project-name=styled-jsx-with-csp&repository-name=styled-jsx-with-csp) | ||
|
||
## How to use | ||
|
||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: | ||
|
||
```bash | ||
npx create-next-app --example styled-jsx-with-csp styled-jsx-with-csp-app | ||
# or | ||
yarn create next-app --example styled-jsx-with-csp styled-jsx-with-csp-app | ||
``` | ||
|
||
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "styled-jsx-with-csp", | ||
"version": "1.0.0", | ||
"private": true, | ||
"scripts": { | ||
"dev": "next dev", | ||
"build": "next build", | ||
"start": "next start" | ||
}, | ||
"dependencies": { | ||
"nanoid": "3.1.21", | ||
"next": "10.0.8", | ||
"react": "17.0.1", | ||
"react-dom": "17.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const CustomApp = ({ Component, pageProps }) => <Component {...pageProps} /> | ||
|
||
// Disable static optimization to always server render, making nonce unique on every request | ||
CustomApp.getInitialProps = () => ({}) | ||
|
||
export default CustomApp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import Document, { Html, Head, Main, NextScript } from 'next/document' | ||
import flush from 'styled-jsx/server' | ||
|
||
import { nanoid } from 'nanoid' | ||
|
||
class CustomDocument extends Document { | ||
static async getInitialProps(ctx) { | ||
const nonce = nanoid() | ||
|
||
// https://github.com/vercel/next.js/blob/canary/packages/next/pages/_document.tsx#L89 | ||
const { html, head } = await ctx.renderPage() | ||
|
||
// Adds `nonce` to style tags on Server Side Rendering | ||
const styles = [...flush({ nonce })] | ||
|
||
let contentSecurityPolicy = '' | ||
if (process.env.NODE_ENV === 'production') { | ||
contentSecurityPolicy = `default-src 'self'; style-src 'nonce-${nonce}';` | ||
} else { | ||
// react-refresh needs 'unsafe-eval' | ||
// Next.js needs 'unsafe-inline' during development https://github.com/vercel/next.js/blob/canary/packages/next/client/dev/fouc.js | ||
// Specifying 'nonce' makes a modern browsers ignore 'unsafe-inline' | ||
contentSecurityPolicy = `default-src 'self'; style-src 'unsafe-inline'; script-src 'self' 'unsafe-eval';` | ||
} | ||
|
||
ctx.res.setHeader('Content-Security-Policy', contentSecurityPolicy) | ||
|
||
return { styles, html, head, nonce } | ||
} | ||
|
||
render() { | ||
return ( | ||
<Html> | ||
<Head> | ||
{/* Styled-JSX will add this `nonce` to style tags on Client Side Rendering */} | ||
{/* https://github.com/vercel/styled-jsx/blob/master/src/lib/stylesheet.js#L31 */} | ||
{/* https://github.com/vercel/styled-jsx/blob/master/src/lib/stylesheet.js#L240 */} | ||
<meta property="csp-nonce" content={this.props.nonce} /> | ||
</Head> | ||
<body> | ||
<Main /> | ||
<NextScript /> | ||
</body> | ||
</Html> | ||
) | ||
} | ||
} | ||
|
||
export default CustomDocument |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { useState } from 'react' | ||
|
||
const ClientSideComponent = () => ( | ||
<> | ||
<style jsx> | ||
{` | ||
.title { | ||
font-size: 24px; | ||
color: green; | ||
} | ||
`} | ||
</style> | ||
<p className="title">This is rendered on client-side</p> | ||
</> | ||
) | ||
|
||
const Home = () => { | ||
const [isVisible, setVisibility] = useState(false) | ||
|
||
const toggleVisibility = () => { | ||
setVisibility((prevState) => !prevState) | ||
} | ||
|
||
return ( | ||
<> | ||
<style jsx> | ||
{` | ||
.title { | ||
font-size: 24px; | ||
} | ||
`} | ||
</style> | ||
<p className="title">Styled-JSX with Content Security Policy</p> | ||
<button onClick={toggleVisibility}>Toggle</button> | ||
{isVisible ? <ClientSideComponent /> : null} | ||
</> | ||
) | ||
} | ||
|
||
export default Home |