next-mdx-remote evaluates MDX at runtime with a different React version than Next.js 16's internal canary, causing build failures. Switch to @next/mdx which compiles MDX through Next.js's own bundler pipeline. - Replace next-mdx-remote with @next/mdx, @mdx-js/mdx, @mdx-js/loader - Use dynamic imports for blog MDX files instead of MDXRemote - Add remark-frontmatter so compiler skips YAML frontmatter blocks - Gate cache/CSP headers to production only (immutable dev chunks were poisoning browser cache) Made-with: Cursor
86 lines
2.2 KiB
JavaScript
86 lines
2.2 KiB
JavaScript
import createMDX from "@next/mdx";
|
|
|
|
const isProd = process.env.NODE_ENV === "production";
|
|
|
|
/** @type {import('next').NextConfig} */
|
|
const nextConfig = {
|
|
pageExtensions: ["ts", "tsx", "md", "mdx"],
|
|
allowedDevOrigins: ["*.ngrok-free.dev"],
|
|
experimental: {
|
|
optimizePackageImports: ["framer-motion", "motion", "gsap", "@gsap/react"],
|
|
optimizeCss: true,
|
|
},
|
|
images: {
|
|
// Serve AVIF to supporting browsers (better compression than WebP),
|
|
// falling back to WebP. Next.js negotiates via Accept header automatically.
|
|
// formats: ["image/avif", "image/webp"],
|
|
},
|
|
async headers() {
|
|
if (!isProd) return [];
|
|
|
|
return [
|
|
{
|
|
source: "/_next/static/(.*)",
|
|
headers: [
|
|
{
|
|
key: "Cache-Control",
|
|
value: "public, max-age=31536000, immutable",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
source: "/animation/(.*)",
|
|
headers: [
|
|
{
|
|
key: "Cache-Control",
|
|
value: "public, max-age=31536000, immutable",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
source: "/images/(.*)",
|
|
headers: [
|
|
{
|
|
key: "Cache-Control",
|
|
value: "public, max-age=604800, stale-while-revalidate=86400",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
source: "/(.*)",
|
|
headers: [
|
|
{
|
|
key: "Content-Security-Policy",
|
|
value: [
|
|
"default-src 'self'",
|
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://vercel.live",
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src 'self' data: blob:",
|
|
"font-src 'self' data:",
|
|
"media-src 'self'",
|
|
"connect-src 'self' https://*.vercel.app https://vitals.vercel-insights.com",
|
|
"frame-ancestors 'none'",
|
|
].join("; "),
|
|
},
|
|
{
|
|
key: "Cross-Origin-Opener-Policy",
|
|
value: "same-origin",
|
|
},
|
|
{
|
|
key: "X-Frame-Options",
|
|
value: "DENY",
|
|
},
|
|
],
|
|
},
|
|
];
|
|
},
|
|
};
|
|
|
|
const withMDX = createMDX({
|
|
options: {
|
|
remarkPlugins: ["remark-frontmatter"],
|
|
},
|
|
});
|
|
|
|
export default withMDX(nextConfig);
|