From e50f7a9e09ba27cc6d78de5a3a1777796b7bc3c7 Mon Sep 17 00:00:00 2001 From: Karthikeyan Ranasthala Date: Fri, 12 Mar 2021 22:39:14 +0530 Subject: [PATCH 1/3] Add example for styled-jsx-with-csp --- examples/styled-jsx-with-csp/.gitignore | 34 +++++++++++++ examples/styled-jsx-with-csp/README.md | 27 ++++++++++ examples/styled-jsx-with-csp/package.json | 20 ++++++++ examples/styled-jsx-with-csp/pages/_app.jsx | 5 ++ .../styled-jsx-with-csp/pages/_document.jsx | 49 +++++++++++++++++++ examples/styled-jsx-with-csp/pages/index.jsx | 40 +++++++++++++++ 6 files changed, 175 insertions(+) create mode 100644 examples/styled-jsx-with-csp/.gitignore create mode 100644 examples/styled-jsx-with-csp/README.md create mode 100644 examples/styled-jsx-with-csp/package.json create mode 100644 examples/styled-jsx-with-csp/pages/_app.jsx create mode 100644 examples/styled-jsx-with-csp/pages/_document.jsx create mode 100644 examples/styled-jsx-with-csp/pages/index.jsx diff --git a/examples/styled-jsx-with-csp/.gitignore b/examples/styled-jsx-with-csp/.gitignore new file mode 100644 index 0000000000000..1437c53f70bc2 --- /dev/null +++ b/examples/styled-jsx-with-csp/.gitignore @@ -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 diff --git a/examples/styled-jsx-with-csp/README.md b/examples/styled-jsx-with-csp/README.md new file mode 100644 index 0000000000000..edc94955763f6 --- /dev/null +++ b/examples/styled-jsx-with-csp/README.md @@ -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)). diff --git a/examples/styled-jsx-with-csp/package.json b/examples/styled-jsx-with-csp/package.json new file mode 100644 index 0000000000000..b58768e03b273 --- /dev/null +++ b/examples/styled-jsx-with-csp/package.json @@ -0,0 +1,20 @@ +{ + "name": "styled-jsx-with-csp", + "version": "1.0.0", + "private": true, + "author": { + "name": "Karthikeyan Ranasthala", + "email": "hello@karthikeyan.sh" + }, + "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" + } +} diff --git a/examples/styled-jsx-with-csp/pages/_app.jsx b/examples/styled-jsx-with-csp/pages/_app.jsx new file mode 100644 index 0000000000000..8dfa2c769e87e --- /dev/null +++ b/examples/styled-jsx-with-csp/pages/_app.jsx @@ -0,0 +1,5 @@ +const CustomApp = ({ Component, pageProps }) => + +CustomApp.getInitialProps = () => ({}) + +export default CustomApp diff --git a/examples/styled-jsx-with-csp/pages/_document.jsx b/examples/styled-jsx-with-csp/pages/_document.jsx new file mode 100644 index 0000000000000..d56dbb3891489 --- /dev/null +++ b/examples/styled-jsx-with-csp/pages/_document.jsx @@ -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 ( + + + {/* 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 */} + + + +
+ + + + ) + } +} + +export default CustomDocument diff --git a/examples/styled-jsx-with-csp/pages/index.jsx b/examples/styled-jsx-with-csp/pages/index.jsx new file mode 100644 index 0000000000000..706b06db05cc4 --- /dev/null +++ b/examples/styled-jsx-with-csp/pages/index.jsx @@ -0,0 +1,40 @@ +import { useState } from 'react' + +const ClientSideComponent = () => ( + <> + +

This is rendered on client-side

+ +) + +const Home = () => { + const [isVisible, setVisibility] = useState(false) + + const toggleVisibility = () => { + setVisibility((prevState) => !prevState) + } + + return ( + <> + +

Styled-JSX with Content Security Policy

+ + {isVisible ? : null} + + ) +} + +export default Home From 022acda789653c3086dd29665fd6decf4e4cf858 Mon Sep 17 00:00:00 2001 From: Karthikeyan Ranasthala Date: Fri, 12 Mar 2021 23:32:54 +0530 Subject: [PATCH 2/3] Remove author from package.json Co-authored-by: Lee Robinson --- examples/styled-jsx-with-csp/package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/styled-jsx-with-csp/package.json b/examples/styled-jsx-with-csp/package.json index b58768e03b273..6cc609d415341 100644 --- a/examples/styled-jsx-with-csp/package.json +++ b/examples/styled-jsx-with-csp/package.json @@ -2,10 +2,6 @@ "name": "styled-jsx-with-csp", "version": "1.0.0", "private": true, - "author": { - "name": "Karthikeyan Ranasthala", - "email": "hello@karthikeyan.sh" - }, "scripts": { "dev": "next dev", "build": "next build", From 68ffd013e3e77b58e13c83f0339868d94fd5bc2d Mon Sep 17 00:00:00 2001 From: Lee Robinson Date: Fri, 12 Mar 2021 12:50:29 -0600 Subject: [PATCH 3/3] Update examples/styled-jsx-with-csp/pages/_app.jsx --- examples/styled-jsx-with-csp/pages/_app.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/styled-jsx-with-csp/pages/_app.jsx b/examples/styled-jsx-with-csp/pages/_app.jsx index 8dfa2c769e87e..3e51080c46ad9 100644 --- a/examples/styled-jsx-with-csp/pages/_app.jsx +++ b/examples/styled-jsx-with-csp/pages/_app.jsx @@ -1,5 +1,6 @@ const CustomApp = ({ Component, pageProps }) => +// Disable static optimization to always server render, making nonce unique on every request CustomApp.getInitialProps = () => ({}) export default CustomApp