codeflash-internal/js/cf-webapp/next.config.mjs
Kevin Turcios d7a8b8f227
perf: fix CI build + lazy-load heavy libs + parallelize DB queries (#2601)
## Summary
- **Fix CI build failure**: Auth0Client crashes during Next.js
prerendering when env vars aren't set. Returns a no-op stub (`getSession
→ null`) when domain is missing — semantically correct for static
generation
- **Lazy-load markdown libs (~260kb)**: ReactMarkdown, remarkGfm, and
react-syntax-highlighter were eagerly imported in monaco-diff-viewer but
only rendered when user expands "Generated Tests". Extracted into a
dynamic component
- **Parallelize repo detail query**: `getRepositoryById` ran the
activity count sequentially after the repo lookup. Since `repoId` is
already available, all three queries now run in parallel

## Test plan
- [ ] CI `build` check passes (was failing since #2598)
- [ ] Trace page still renders generated tests correctly when expanded
- [ ] Repository detail page loads correctly with activity status
2026-04-13 11:03:05 -05:00

181 lines
5.7 KiB
JavaScript

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))