Files
claudemesh/apps/web/next.config.ts
Alejandro Gutiérrez 495c234159
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
fix(web): enable turbopack + payload by unbundling richtext-lexical
The CSS import error was caused by richtext-lexical being in
serverExternalPackages — Node can't require .css files. Removing
it lets Turbopack bundle it (handling CSS natively). Other payload
packages stay external (they don't import CSS).

Restores turbopack as the default production bundler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 09:38:56 +01:00

136 lines
3.3 KiB
TypeScript

import type { NextConfig } from "next";
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { withPayload } = require("@payloadcms/next/withPayload");
import env from "./env.config";
const INTERNAL_PACKAGES = [
"@turbostarter/analytics-web",
"@turbostarter/api",
"@turbostarter/auth",
"@turbostarter/billing",
"@turbostarter/cms",
"@turbostarter/email",
"@turbostarter/db",
"@turbostarter/i18n",
"@turbostarter/monitoring-web",
"@turbostarter/shared",
"@turbostarter/storage",
"@turbostarter/ui",
"@turbostarter/ui-web",
];
// Security headers for production
const securityHeaders = [
{
key: "X-DNS-Prefetch-Control",
value: "on",
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
{
key: "X-Frame-Options",
value: "SAMEORIGIN",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "X-XSS-Protection",
value: "1; mode=block",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=(), interest-cohort=()",
},
// Content-Security-Policy - configured for development flexibility
// In production, tighten 'unsafe-inline' and 'unsafe-eval' as needed
{
key: "Content-Security-Policy",
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com https://challenges.cloudflare.com",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: blob: https: http:",
"font-src 'self' data:",
"connect-src 'self' https://api.stripe.com https://*.sentry.io wss:",
"frame-src 'self' https://js.stripe.com https://hooks.stripe.com https://challenges.cloudflare.com",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"frame-ancestors 'self'",
"upgrade-insecure-requests",
].join("; "),
},
];
const config: NextConfig = {
reactStrictMode: true,
output: "standalone",
// TEMPORARY: Hono RPC + TanStack Query type inference whack-a-mole blocking production deploy.
// Ship now, fix types post-launch as dedicated tech-debt sprint.
typescript: {
ignoreBuildErrors: true,
},
serverExternalPackages: [
"better-sqlite3",
"@mapbox/node-pre-gyp",
"esbuild",
"payload",
"@payloadcms/db-postgres",
"@payloadcms/db-sqlite",
"sharp",
],
turbopack: {
rules: {
"*.svg": {
loaders: ["@svgr/webpack"],
as: "*.js",
},
},
},
images: {
remotePatterns: [
{
hostname: "images.unsplash.com",
},
],
},
/** Enables hot reloading for local packages without a build step */
transpilePackages: INTERNAL_PACKAGES,
experimental: {
optimizePackageImports: INTERNAL_PACKAGES,
},
// Apply security headers only in production
// CSP with upgrade-insecure-requests breaks Next.js client-side navigation in dev
async headers() {
if (process.env.NODE_ENV !== "production") {
return [];
}
return [
{
// Apply to all routes
source: "/:path*",
headers: securityHeaders,
},
];
},
};
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: env.ANALYZE,
});
export default withPayload(withBundleAnalyzer(config));