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. 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.
This commit is contained in:
Gabriel Brown committed 2026-10-01 14:55:11 -04:00
1 parent 818b41fb21
commit 55b253257b
14 files changed
+318 -102

No files matched your search

+52 -5
View File
@@ -3,12 +3,16 @@ import { createJiti } from 'jiti';
import { withPlausibleProxy } from 'next-plausible';
const jiti = createJiti(import.meta.url);
await jiti.import('./src/env');
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 config = withPlausibleProxy({
customDomain: process.env.NEXT_PUBLIC_PLAUSIBLE_URL,
})({
const baseConfig = {
output: 'standalone',
images: {
remotePatterns: [
@@ -23,11 +27,54 @@ const config = withPlausibleProxy({
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: