Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,105 @@ This will require a new hash to be set in your CSP during each deployment.
To use a CSP with a project initialized as a Create React App, you will need to set the `INLINE_RUNTIME_CHUNK=false` variable in the `.env` file used for your production build.
This will import the runtime script as usual instead of embedding it, avoiding the need to set a new hash during each deployment.

### NextJS Page Router

For NextJS using Page Router, after [setting up a nonce](https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy#nonces), you can pass it to the emotion cache which you'll do it in two places:


First in the `_document.tsx`
```tsx
import {
DocumentHeadTags,
documentGetInitialProps,
createEmotionCache,
} from '@mui/material-nextjs/v15-pagesRouter';
// other imports

type Props = DocumentInitialProps & DocumentHeadTagsProps & { nonce?: string };

export default function MyDocument(props: Props) {
const { nonce } = props;

return (
<Html lang="en" className={roboto.className}>
<Head>
{ /*...*/ }
<meta name="csp-nonce" content={nonce} />
<DocumentHeadTags {...props} nonce={nonce} />
</Head>
<body>
{ /*...*/ }
<NextScript nonce={nonce} />
</body>
</Html>
);
}

MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const { req } = ctx;
const nonce = req?.headers["x-nonce"];
if (typeof nonce !== "string") {
throw new Error('"nonce" header is missing');
}

const emotionCache = createEmotionCache({ nonce });
const finalProps = await documentGetInitialProps(ctx, {
emotionCache,
});

return { ...finalProps, nonce };
};
```

And then in `_app.tsx` if you're setting up the `AppCacheProvider`

```tsx
import {
createEmotionCache,
} from '@mui/material-nextjs/v15-pagesRouter';
// other imports

export default function MyApp(props: AppProps & { nonce: string }) {
const { Component, pageProps, nonce } = props;

const emotionCache = useMemo(() => {
const nonce = props.nonce || getNonce();

return createEmotionCache({ nonce });
}, [props.nonce]);

return (
<AppCacheProvider {...props} emotionCache={emotionCache}>
{/* ... */}
</AppCacheProvider>
);
}

function getNonce(headers?: Record<string, string | string[] | undefined>) {
if (headers) {
return headers['x-nonce'] as string;
}

if (typeof document !== 'undefined') {
const nonceMeta = document.querySelector('meta[name="csp-nonce"]');
if (nonceMeta) {
return nonceMeta.getAttribute('content') || undefined;
}
}

return undefined;
}

MyApp.getInitialProps = async (appContext: AppContext) => {
const nonce = getNonce(appContext.ctx?.req?.headers);
if (typeof nonce !== "string") {
throw new Error('"nonce" header is missing');
}

return { ...otherProps, nonce };
};
```

### styled-components

The configuration of the nonce is not straightforward, but you can follow [this issue](https://github.com/styled-components/styled-components/issues/2363) for more insights.
Loading