import bundleAnalyzer from "@next/bundle-analyzer" import { dirname, resolve } from "path" import { fileURLToPath } from "url" const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === "true", }) const __dirname = dirname(fileURLToPath(import.meta.url)) /** @type {import("next").NextConfig} */ const nextConfig = { cacheComponents: true, cacheLife: { dashboard: { stale: 60, // 1 minute — serve stale while revalidating revalidate: 300, // 5 minutes — background revalidation interval expire: 3600, // 1 hour — hard expiry }, frequent: { stale: 30, // 30 seconds revalidate: 60, // 1 minute expire: 600, // 10 minutes }, }, transpilePackages: ["@codeflash-ai/common"], webpack: (config, { isServer }) => { config.watchOptions = { poll: 1000, aggregateTimeout: 300, } // Suppress known-harmless "Critical dependency" warnings from OpenTelemetry // and require-in-the-middle. These packages use dynamic require() for runtime // monkey-patching — webpack can't statically analyze them but they work fine. // Root cause: @sentry/nextjs → @sentry/node → @opentelemetry/instrumentation. config.ignoreWarnings = [ ...(config.ignoreWarnings || []), { module: /@opentelemetry\/instrumentation/ }, { module: /require-in-the-middle/ }, ] // Handle web-tree-sitter's Node.js module imports in browser. // fallback handles static require(); alias handles dynamic import() if (!isServer) { config.resolve.fallback = { ...config.resolve.fallback, fs: false, "fs/promises": false, path: false, module: false, } config.resolve.alias = { ...config.resolve.alias, module: false, } } return config }, turbopack: { root: __dirname, resolveAlias: { // Stub Node.js built-ins that web-tree-sitter tries to import in the browser. // Uses { browser: ... } so aliases only apply to client bundles, not SSR. 'fs': { browser: './src/lib/empty-shim.js' }, 'fs/promises': { browser: './src/lib/empty-shim.js' }, 'path': { browser: './src/lib/empty-shim.js' }, 'module': { browser: './src/lib/empty-shim.js' }, }, }, serverExternalPackages: [ "@anthropic-ai/sdk", "sharp", "posthog-node", "@opentelemetry/api", "@opentelemetry/sdk-node", "@opentelemetry/auto-instrumentations-node", "@opentelemetry/instrumentation", "@prisma/instrumentation", "@sentry/opentelemetry", "@sentry/node", "require-in-the-middle", "@fastify/otel", ], experimental: { // Tree-shake barrel exports for these heavy packages. Without this, // importing a single icon from lucide-react or a single component from // chart.js pulls the entire library into the bundle. optimizePackageImports: [ "lucide-react", "date-fns", "react-syntax-highlighter", "chart.js", "react-chartjs-2", "motion", "zod", "react-hook-form", "@hookform/resolvers", "react-markdown", "remark-gfm", "sonner", "react-resizable-panels", "@radix-ui/react-dialog", "@radix-ui/react-select", "@radix-ui/react-tabs", "@radix-ui/react-tooltip", "@radix-ui/react-toast", "chartjs-plugin-datalabels", "marked", "prism-react-renderer", ], serverActions: { allowedOrigins: ["app.codeflash.ai", "localhost:3000"], bodySizeLimit: '5mb', // Increased from default 1mb to handle large PR creation payloads }, // NOTE: turbopackRemoveUnused{Imports,Exports} are NOT enabled — they // break @opentelemetry/api barrel re-exports and Next.js internal ESM // modules (same class of bug as turbopackTreeShaking + @sentry/core below). // turbopackRemoveUnusedImports requires turbopackRemoveUnusedExports. turbopackInferModuleSideEffects: true, // Scope hoisting: collapses module wrappers for smaller output turbopackScopeHoisting: true, // NOTE: turbopackTreeShaking is NOT enabled — it fragments modules into // "internal parts" which breaks @sentry/core's ESM cross-references // (withScope, withErrorInstrumentation exports disappear). Re-test when // Turbopack or Sentry fixes the incompatibility. // Persist compiled artifacts between CI builds turbopackFileSystemCacheForBuild: true, // Client-side router cache: avoid refetching on back-navigation staleTimes: { dynamic: 30, static: 180, }, }, typescript: { // Type-checking is split into a separate `npm run type-check` step. // This cuts ~16s off `next build` (was 60% of build time). ignoreBuildErrors: true, }, // Optimize for production stability poweredByHeader: false, compress: true, images: { remotePatterns: [ { protocol: "https", hostname: "avatars.githubusercontent.com", }, { protocol: "https", hostname: "github.com", }, ], formats: ['image/avif', 'image/webp'], }, } import { withSentryConfig } from "@sentry/nextjs" // Only upload source maps when SENTRY_AUTH_TOKEN is set (CI/deploy). // Skipping this shaves significant time off local builds. const withSentry = process.env.SENTRY_AUTH_TOKEN ? (config) => withSentryConfig( config, { silent: true, org: "codeflash-ai", project: "webapp", }, { widenClientFileUpload: true, tunnelRoute: "/monitoring", hideSourceMaps: true, disableLogger: true, automaticVercelMonitors: false, }, ) : (config) => config export default withBundleAnalyzer(withSentry(nextConfig))