159 lines
4.6 KiB
TypeScript
159 lines
4.6 KiB
TypeScript
import type { NextConfig } from "next";
|
|
|
|
const nextConfig: NextConfig = {
|
|
// Enable standalone output for Docker/PM2 deployment
|
|
output: "standalone",
|
|
|
|
// Lock the file-tracing root to the project directory. Without this,
|
|
// Next.js 16 walks up from package.json looking for a lockfile, finds
|
|
// the homelab runner's stale `act` cache at
|
|
// /home/tyler/.cache/act/.../package-lock.json, and warns:
|
|
// "We detected multiple lockfiles and selected the directory of
|
|
// /home/tyler/package-lock.json as the root directory."
|
|
// The deploy runner's APP_DIR is /home/tyler/route-commerce, so
|
|
// resolving relative to the project root is correct both locally and
|
|
// in CI. We resolve to an absolute path to avoid the warning in
|
|
// Next.js 16 which prefers absolute paths here.
|
|
outputFileTracingRoot: __dirname,
|
|
|
|
// Enable strict mode
|
|
reactStrictMode: true,
|
|
|
|
// Optimize images
|
|
images: {
|
|
remotePatterns: [
|
|
{
|
|
protocol: "https",
|
|
hostname: "*.supabase.co",
|
|
},
|
|
{
|
|
protocol: "https",
|
|
hostname: "images.unsplash.com",
|
|
},
|
|
{
|
|
protocol: "https",
|
|
hostname: "picsum.photos",
|
|
},
|
|
],
|
|
formats: ["image/avif", "image/webp"],
|
|
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
|
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
|
},
|
|
|
|
// Security headers
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: "/:path*",
|
|
headers: [
|
|
{
|
|
key: "X-Content-Type-Options",
|
|
value: "nosniff",
|
|
},
|
|
{
|
|
key: "X-Frame-Options",
|
|
value: "DENY",
|
|
},
|
|
{
|
|
key: "X-XSS-Protection",
|
|
value: "1; mode=block",
|
|
},
|
|
{
|
|
key: "Referrer-Policy",
|
|
value: "strict-origin-when-cross-origin",
|
|
},
|
|
{
|
|
key: "Permissions-Policy",
|
|
value: "camera=(), microphone=(), geolocation=()",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
// API routes - more restrictive
|
|
source: "/api/:path*",
|
|
headers: [
|
|
{
|
|
key: "Access-Control-Allow-Methods",
|
|
value: "GET, POST, PUT, DELETE, OPTIONS",
|
|
},
|
|
{
|
|
key: "Access-Control-Allow-Headers",
|
|
value: "Content-Type, Authorization, X-API-Key",
|
|
},
|
|
{
|
|
key: "Access-Control-Max-Age",
|
|
value: "86400",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
source: "/_next/static/:path*",
|
|
headers: [
|
|
{ key: "Cache-Control", value: "public, max-age=31536000, immutable" },
|
|
],
|
|
},
|
|
{
|
|
source: "/icons/:path*",
|
|
headers: [
|
|
{ key: "Cache-Control", value: "public, max-age=31536000, immutable" },
|
|
],
|
|
},
|
|
{
|
|
source: "/screenshots/:path*",
|
|
headers: [
|
|
{ key: "Cache-Control", value: "public, max-age=604800" },
|
|
],
|
|
},
|
|
];
|
|
},
|
|
|
|
// Redirects
|
|
async redirects() {
|
|
return [
|
|
// Cutover (PR 6, Task 6.1): mobile-first admin lives at /admin/v2/*.
|
|
// Redirect the v1 list/detail paths to their v2 equivalents.
|
|
// Use `permanent: false` (307) so we can revert easily if a
|
|
// regression is caught in monitoring before the v1 files are
|
|
// removed in Task 6.2.
|
|
{ source: "/admin/orders", destination: "/admin/v2/orders", permanent: false },
|
|
{ source: "/admin/orders/:id", destination: "/admin/v2/orders/:id", permanent: false },
|
|
{ source: "/admin/stops", destination: "/admin/v2/stops", permanent: false },
|
|
{ source: "/admin/products", destination: "/admin/v2/products", permanent: false },
|
|
];
|
|
},
|
|
|
|
// Rewrites for API proxy
|
|
async rewrites() {
|
|
return [
|
|
// Add any necessary rewrites here
|
|
];
|
|
},
|
|
|
|
// Experimental features
|
|
experimental: {
|
|
// Enable optimizePackageImports for better bundle size
|
|
optimizePackageImports: ["lucide-react", "@radix-ui/react-icons", "framer-motion"],
|
|
// Enable React's <ViewTransition> and Next.js' automatic route
|
|
// transitions. Combined with the smooth-transition wrappers around
|
|
// page content (see src/components/transitions), navigation feels
|
|
// like a single continuous app rather than a sequence of page loads.
|
|
viewTransition: true,
|
|
},
|
|
|
|
// Compiler options
|
|
compiler: {
|
|
// Remove console.log in production
|
|
removeConsole: process.env.NODE_ENV === "production"
|
|
? { exclude: ["error", "warn"] }
|
|
: false,
|
|
},
|
|
|
|
// Logging
|
|
logging: {
|
|
fetches: {
|
|
fullUrl: process.env.NODE_ENV === "development",
|
|
},
|
|
},
|
|
};
|
|
|
|
export default nextConfig; |