Files
petfeed/next.config.ts
T
admin 1f177c5e88 perf(landing): inline render-blocking CSS, fix LCP image fetchpriority
Two follow-ups from a fresh PageSpeed Insights run (mobile 87/100/100/100):

1. next.config.ts: enable experimental.inlineCss. Removes a ~342ms
   render-blocking CSS request (globals.css, ~21.6 KiB gzip -- shared by
   every route since Tailwind bundles the whole app's utilities into one
   file). Officially documented, dependency-free, and explicitly
   recommended for small atomic-CSS bundles like ours. Applies globally
   (can't be scoped per route), so hard/full page loads lose cross-page
   CSS caching -- soft client-side navigations are unaffected.

2. page.tsx hero image: `priority` was deprecated in Next.js 16 in favor
   of `fetchPriority`/`loading` as separate props -- it still emitted a
   <link rel=preload> but no longer set fetchpriority="high" on the <img>
   itself. Replaced with loading="eager" fetchPriority="high" per the
   bundled Next.js 16 docs.

SpeedUp-Plan, Gitea #28.
2026-08-21 06:43:22 +02:00

67 lines
2.7 KiB
TypeScript

import type { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin";
import { withSentryConfig } from "@sentry/nextjs";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
function getSupabaseHostname(): string {
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
if (url) {
try { return new URL(url).hostname; } catch { /* fall through */ }
}
return "*.supabase.co";
}
const nextConfig: NextConfig = {
output: "standalone",
allowedDevOrigins: ["192.168.1.92"],
experimental: {
// Inlines every route's CSS into <head><style> instead of a render-blocking
// <link>. Officially recommended for atomic CSS (Tailwind) with a small
// per-page bundle -- our globals.css is ~21 KiB gzipped, all of it shared
// by every route since Tailwind bundles the whole app's utilities into one
// file. Trade-off: no cross-page CSS caching on a hard/full page load
// (soft client-side navigations are unaffected, since they don't re-fetch
// <head> at all). SpeedUp-Plan (Gitea #28): removes a ~342ms render-blocking
// CSS request measured on throttled mobile.
inlineCss: true,
},
images: {
remotePatterns: [
{ protocol: "https", hostname: getSupabaseHostname() },
],
},
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
// HSTS intentionally NOT set here — Cloudflare (in front of the origin) already
// sends a stronger one (max-age=63072000; preload). Setting both resulted in two
// Strict-Transport-Security headers on every response; browsers only honor the
// first, so the app's weaker one was pure noise. If Cloudflare is ever removed
// from the path, re-add this header at the edge/proxy layer, not here.
],
},
];
},
};
export default withSentryConfig(withNextIntl(nextConfig), {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
// Sourcemap upload currently fails against GlitchTip with a CSRF 403 on
// the releases API (confirmed server-side issue, not a build config
// problem — see commit history around 2026-08-14). Keeping silent so this
// known, non-fatal failure doesn't spam every build log; re-enable
// debug:true if investigating further.
silent: true,
sourcemaps: { disable: !process.env.SENTRY_AUTH_TOKEN },
disableLogger: true,
});