Files
convex-monorepo-payload/apps/next/next.config.js
T
Gabriel Brown f39376a887 Add PostHog, move Plausible to v4, and drop Sentry session replay
PostHog loads after the page is idle through a same-origin /ingest proxy and follows the signed-in Convex user. Plausible uses the per-site script through a /pa proxy, clear of Payload's /api routes. Sentry keeps errors and traces only. Pages load only the @gib/ui modules they import, and client code reads public env from publicEnv.ts so zod stays out of the browser.
2026-10-01 14:42:29 -04:00

106 lines
4.0 KiB
JavaScript

import { withPayload } from '@payloadcms/next/withPayload';
import { withSentryConfig } from '@sentry/nextjs';
import { createJiti } from 'jiti';
import { withPlausibleProxy } from 'next-plausible';
const jiti = createJiti(import.meta.url);
const { env } = /** @type {typeof import('./src/env')} */ (
await jiti.import('./src/env')
);
const { posthogScriptAliases } =
/** @type {typeof import('./src/lib/posthog-scripts')} */ (
await jiti.import('./src/lib/posthog-scripts')
);
/** @type {import("next").NextConfig} */
const baseConfig = {
output: 'standalone',
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '*.gbrown.org',
},
],
},
serverExternalPackages: ['require-in-the-middle'],
experimental: {
serverActions: {
bodySizeLimit: '10mb',
},
// Resolves `import { Button } from '@gib/ui'` to the button module alone,
// so marketing pages never pull in admin-only Radix widgets or Recharts.
// radix-ui is the umbrella package the shadcn components import from.
// lucide-react, date-fns and @tabler/icons-react are on Next's default list.
optimizePackageImports: ['@gib/ui', 'radix-ui'],
},
/** Enables hot reloading for local packages without a build step */
transpilePackages: ['@gib/backend', '@gib/ui'],
typescript: { ignoreBuildErrors: true },
// PostHog's capture paths end in a slash (/e/, /i/v0/e/), and Next's
// built-in trailing-slash redirect would answer those proxied POSTs with a
// redirect. It is turned off here and replaced by the redirect below, which
// strips trailing slashes everywhere except /ingest.
skipTrailingSlashRedirect: true,
redirects: async () => [
{
source: '/:path((?!ingest(?:/|$)).+)/',
destination: '/:path',
permanent: true,
},
],
// Same-origin proxy for PostHog, so blocklists that match the PostHog host
// never see the request. The aliased extension scripts (blocked by file
// name, see src/lib/posthog-scripts.ts) map back to their real files first.
rewrites: async () => {
const host = env.NEXT_PUBLIC_POSTHOG_HOST;
if (!host) return [];
return [
...Object.entries(posthogScriptAliases).map(([name, alias]) => ({
source: `/ingest/static/${alias}.js`,
destination: `${host}/static/${name}.js`,
})),
{ source: '/ingest/:path*', destination: `${host}/:path*` },
];
},
};
// Serves Plausible's per-site script from this origin so ad blockers see a
// first-party request. next-plausible 4 takes the full script URL. Its default
// event path is /api/event, which sits inside Payload's /api routes, so both
// paths move under /pa.
const config = env.NEXT_PUBLIC_PLAUSIBLE_SRC
? withPlausibleProxy({
src: env.NEXT_PUBLIC_PLAUSIBLE_SRC,
scriptPath: '/pa/script.js',
apiPath: '/pa/event',
})(baseConfig)
: baseConfig;
const sentryConfig = {
// For all available options, see:
// https://www.npmjs.com/package/@sentry/webpack-plugin#options
org: process.env.NEXT_PUBLIC_SENTRY_ORG,
project: process.env.NEXT_PUBLIC_SENTRY_PROJECT_NAME,
sentryUrl: process.env.NEXT_PUBLIC_SENTRY_URL,
authToken: process.env.SENTRY_AUTH_TOKEN,
// Only print logs for uploading source maps in CI
silent: !process.env.CI,
// For all available options, see:
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
// This can increase your server load as well as your hosting bill.
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
// side errors will fail.
tunnelRoute: '/monitoring',
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
// Capture React Component Names
reactComponentAnnotation: {
enabled: true,
},
};
export default withSentryConfig(withPayload(config), sentryConfig);