245 lines
7.4 KiB
JavaScript
245 lines
7.4 KiB
JavaScript
const withNextIntl = require('next-intl/plugin')()
|
|
|
|
/** @type {import('next').NextConfig} */
|
|
// ============================================
|
|
// Next.js 16 Configuration
|
|
// ============================================
|
|
// This configuration is optimized for Next.js 16
|
|
// Deprecated options have been removed (swcMinify, reactStrictMode)
|
|
// SWC minification is now default in Next.js 16
|
|
|
|
// Production-ready Next.js configuration with standalone output
|
|
// This configuration is optimized for Docker deployment with minimal image size
|
|
//
|
|
// Key features:
|
|
// - Standalone output mode (includes only necessary dependencies)
|
|
// - Image optimization with modern formats
|
|
// - Static Site Generation (SSG) for all blog posts
|
|
// - Production-grade caching and performance settings
|
|
//
|
|
// Usage:
|
|
// 1. Copy this file to project root: cp next.config.js.production next.config.js
|
|
// 2. Build application: npm run build
|
|
// 3. The .next/standalone directory will contain everything needed to run the app
|
|
|
|
const nextConfig = {
|
|
// ============================================
|
|
// Standalone Output Mode
|
|
// ============================================
|
|
// This is REQUIRED for Docker deployment
|
|
// Outputs a minimal server with only necessary dependencies
|
|
// Reduces Docker image size from ~1GB to ~150MB
|
|
output: 'standalone',
|
|
|
|
// ============================================
|
|
// Image Optimization
|
|
// ============================================
|
|
images: {
|
|
// Modern image formats (smaller file sizes)
|
|
formats: ['image/avif', 'image/webp'],
|
|
|
|
// Device sizes for responsive images
|
|
// Next.js will generate optimized images for these widths
|
|
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
|
|
|
// Image sizes for <Image> component size prop
|
|
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
|
|
// Cache optimized images for 30 days
|
|
minimumCacheTTL: 60 * 60 * 24 * 30,
|
|
|
|
// Allow SVG rendering (with security measures)
|
|
dangerouslyAllowSVG: true,
|
|
contentDispositionType: 'attachment',
|
|
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
|
|
|
|
// Disable image optimization during build (optional)
|
|
// Uncomment if build times are too long
|
|
// unoptimized: false,
|
|
|
|
// External image domains (if loading images from CDN)
|
|
// Uncomment and add domains if needed
|
|
// remotePatterns: [
|
|
// {
|
|
// protocol: 'https',
|
|
// hostname: 'cdn.example.com',
|
|
// },
|
|
// ],
|
|
},
|
|
|
|
// ============================================
|
|
// Performance Optimization
|
|
// ============================================
|
|
|
|
// Compress static pages (reduces bandwidth)
|
|
compress: true,
|
|
|
|
// ============================================
|
|
// Production Settings
|
|
// ============================================
|
|
|
|
// Disable X-Powered-By header for security
|
|
poweredByHeader: false,
|
|
|
|
// Generate ETags for caching
|
|
generateEtags: true,
|
|
|
|
// ============================================
|
|
// Static Generation Settings
|
|
// ============================================
|
|
|
|
// Automatically generate static pages at build time
|
|
// This is the default behavior for Next.js App Router
|
|
// All markdown blog posts will be pre-rendered
|
|
|
|
// ============================================
|
|
// TypeScript Settings
|
|
// ============================================
|
|
|
|
// Type checking during build
|
|
// Set to false to skip type checking (not recommended)
|
|
typescript: {
|
|
// ignoreBuildErrors: false,
|
|
},
|
|
|
|
// ============================================
|
|
// ESLint Settings
|
|
// ============================================
|
|
|
|
// ESLint during build
|
|
// Set to false to skip linting (not recommended)
|
|
|
|
// ============================================
|
|
// Experimental Features (Next.js 16)
|
|
// ============================================
|
|
|
|
experimental: {
|
|
// Enable optimistic client cache
|
|
// Improves navigation performance
|
|
staleTimes: {
|
|
dynamic: 30,
|
|
static: 180,
|
|
},
|
|
|
|
// Optimize package imports for smaller bundles
|
|
optimizePackageImports: ['react-markdown', 'rehype-raw', 'rehype-sanitize', 'remark-gfm'],
|
|
|
|
// Enable PPR (Partial Prerendering) - Next.js 16 feature
|
|
// Uncomment to enable (currently in beta)
|
|
// ppr: false,
|
|
},
|
|
|
|
// ============================================
|
|
// Security Headers (PRODUCTION READY)
|
|
// ============================================
|
|
// Comprehensive security headers for public deployment
|
|
// Note: Caddy reverse proxy may also set these as backup
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: '/:path*',
|
|
headers: [
|
|
// Prevent MIME type sniffing
|
|
{
|
|
key: 'X-Content-Type-Options',
|
|
value: 'nosniff',
|
|
},
|
|
// Prevent clickjacking
|
|
{
|
|
key: 'X-Frame-Options',
|
|
value: 'DENY',
|
|
},
|
|
// XSS Protection (legacy browsers)
|
|
{
|
|
key: 'X-XSS-Protection',
|
|
value: '1; mode=block',
|
|
},
|
|
// HSTS - Force HTTPS for 1 year
|
|
{
|
|
key: 'Strict-Transport-Security',
|
|
value: 'max-age=31536000; includeSubDomains; preload',
|
|
},
|
|
// Referrer Policy - Protect user privacy
|
|
{
|
|
key: 'Referrer-Policy',
|
|
value: 'strict-origin-when-cross-origin',
|
|
},
|
|
// Permissions Policy - Disable unnecessary browser features
|
|
{
|
|
key: 'Permissions-Policy',
|
|
value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
|
|
},
|
|
// Content Security Policy - Restrict resource loading
|
|
// Note: Next.js requires 'unsafe-inline' for styled-jsx
|
|
{
|
|
key: 'Content-Security-Policy',
|
|
value: [
|
|
"default-src 'self'",
|
|
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src 'self' data: https:",
|
|
"font-src 'self' data:",
|
|
"connect-src 'self'",
|
|
"frame-ancestors 'none'",
|
|
"base-uri 'self'",
|
|
"form-action 'self'",
|
|
].join('; '),
|
|
},
|
|
],
|
|
},
|
|
// Aggressive caching for static assets
|
|
{
|
|
source: '/_next/static/:path*',
|
|
headers: [
|
|
{
|
|
key: 'Cache-Control',
|
|
value: 'public, max-age=31536000, immutable',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
source: '/images/:path*',
|
|
headers: [
|
|
{
|
|
key: 'Cache-Control',
|
|
value: 'public, max-age=31536000, immutable',
|
|
},
|
|
],
|
|
},
|
|
]
|
|
},
|
|
|
|
// ============================================
|
|
// Redirects (Optional)
|
|
// ============================================
|
|
// Add permanent redirects for old URLs
|
|
// Uncomment and add your redirects
|
|
//
|
|
// async redirects() {
|
|
// return [
|
|
// {
|
|
// source: '/old-blog/:slug',
|
|
// destination: '/blog/:slug',
|
|
// permanent: true,
|
|
// },
|
|
// ]
|
|
// },
|
|
|
|
// ============================================
|
|
// Rewrites (Optional)
|
|
// ============================================
|
|
// Add URL rewrites for API proxying or URL masking
|
|
// Uncomment and add your rewrites
|
|
//
|
|
// async rewrites() {
|
|
// return [
|
|
// {
|
|
// source: '/api/:path*',
|
|
// destination: 'https://api.example.com/:path*',
|
|
// },
|
|
// ]
|
|
// },
|
|
}
|
|
|
|
module.exports = withNextIntl(nextConfig)
|