nibtime / next-safe-middleware

Strict CSP (Content-Security-Policy) for Next.js hybrid apps https://web.dev/strict-csp/
https://next-safe-middleware.vercel.app
MIT License
78 stars 20 forks source link

next/dynamic error #88

Open baktiaditya opened 1 year ago

baktiaditya commented 1 year ago

How to make middleware work with Next.js dynamic import? Thanks

console error image

middleware.ts

import {
  chainMatch,
  csp,
  isPageRequest,
  nextSafe,
  strictDynamic,
  strictInlineStyles,
} from '@next-safe/middleware';

type HostNameScheme = `${string}.${string}` | 'localhost';
type HostProtocolSchemes = `${string}://` | '';
type PortScheme = `:${number}` | '' | ':*';
type HostSource = `${HostProtocolSchemes}${HostNameScheme}${PortScheme}`;

const adminUrl = process.env.NEXT_PUBLIC_ADMIN_URL as HostSource;

const securityMiddleware = [
  nextSafe({
    disableCsp: true,
    permissionsPolicy: false,
  }),
  csp({
    directives: {
      'img-src': ['self', 'data:'],
      'font-src': ['self', 'data:'],
      'media-src': ['self', 'blob:', adminUrl],
      'style-src': ['self'],
    },
  }),
  strictDynamic(),
  strictInlineStyles(),
];

export default chainMatch(isPageRequest)(...securityMiddleware);

_document.tsx

import React from 'react';
import { createStylesServer, ServerStyles } from '@mantine/next';
import {
  getCspInitialProps,
  provideComponents,
} from '@next-safe/middleware/dist/document';
import Document, {
  DocumentContext,
  DocumentInitialProps,
  Html,
  Main,
} from 'next/document';

const stylesServer = createStylesServer();

export default class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext,
  ): Promise<DocumentInitialProps> {
    const initialProps = await getCspInitialProps({
      ctx,
      trustifyStyles: true,
      hashRawCss: [
        (initialProps) => [
          stylesServer.extractCritical(initialProps.html).css,
          ...stylesServer
            .extractCriticalToChunks(initialProps.html)
            .styles.map((s) => s.css),
        ],
      ],
    });

    initialProps.styles = (
      <>
        {initialProps.styles}
        <ServerStyles html={initialProps.html} server={stylesServer} />
      </>
    );

    return initialProps;
  }

  render() {
    const { Head, NextScript } = provideComponents(this.props);
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

next.config.js

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  crossOrigin: 'anonymous',
  async headers() {
    return [
      {
        source: '/:all*(svg|jpg|jpeg|png|woff2)',
        locale: false,
        headers: [
          {
            key: 'Cache-Control',
            value: 'public, max-age=31536000, stale-while-revalidate',
          },
        ],
      },
    ];
  },
};

module.exports = withBundleAnalyzer(nextConfig);

package.json

"@emotion/react": "^11.10.5",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.5",
"@mantine/next": "^5.10.3",
"@next-safe/middleware": "0.10.0",
"next": "13.1.5",
"react": "18.2.0",
"tailwindcss": "^3.2.4",
"twin.macro": "^3.1.0",
barticus commented 1 year ago

I am also experiencing this.. In develop there is no error, but when building in prod mode I believe dynamic is making it tricky to create a proper SHA.