perf: fix PageSpeed Insights issues (WebGL errors, bfcache, redirects, a11y)
All checks were successful
Gitea CI / test-build (push) Successful in 11m38s

- Add WebGL support detection in ShaderGradientBackground to prevent console errors
- Add .catch() fallback to ShaderGradientBackground dynamic import
- Remove hardcoded aria-label from consent banner minimize button (fixes label-content-name-mismatch)
- Use rewrite instead of redirect for root locale routing (eliminates one redirect hop)
- Change n8n API cache headers from no-store to no-cache (enables bfcache)
- Add three and @react-three/fiber to optimizePackageImports for better tree-shaking

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-04 01:29:32 +01:00
parent 0f7ea8ca4d
commit f62db69289
5 changed files with 27 additions and 11 deletions

View File

@@ -15,7 +15,7 @@ const BackgroundBlobs = dynamic(() => import("@/components/BackgroundBlobs").cat
});
const ShaderGradientBackground = dynamic(
() => import("./ShaderGradientBackground"),
() => import("./ShaderGradientBackground").catch(() => ({ default: () => null })),
{ ssr: false, loading: () => null }
);

View File

@@ -54,8 +54,6 @@ export default function ConsentBanner() {
type="button"
onClick={() => setMinimized(true)}
className="shrink-0 text-xs text-stone-500 hover:text-stone-900 transition-colors"
aria-label="Minimize privacy banner"
title="Minimize"
>
{s.hide}
</button>

View File

@@ -1,9 +1,23 @@
"use client";
import React from "react";
import React, { useEffect, useState } from "react";
import { ShaderGradientCanvas, ShaderGradient } from "@shadergradient/react";
const ShaderGradientBackground = () => {
const [supported, setSupported] = useState(true);
useEffect(() => {
try {
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!gl) setSupported(false);
} catch {
setSupported(false);
}
}, []);
if (!supported) return null;
return (
<div
style={{

View File

@@ -88,11 +88,15 @@ export function middleware(request: NextRequest) {
return addHeaders(request, res);
}
// Redirect bare routes to locale-prefixed ones
// Add locale prefix: rewrite root path (avoids redirect roundtrip), redirect others
const preferred = pickLocaleFromHeader(request.headers.get("accept-language"));
const redirectTarget =
pathname === "/" ? `/${preferred}` : `/${preferred}${pathname}${search || ""}`;
responseUrl.pathname = redirectTarget;
if (pathname === "/") {
responseUrl.pathname = `/${preferred}`;
const res = NextResponse.rewrite(responseUrl);
res.cookies.set("NEXT_LOCALE", preferred, { path: "/" });
return addHeaders(request, res);
}
responseUrl.pathname = `/${preferred}${pathname}${search || ""}`;
const res = NextResponse.redirect(responseUrl);
res.cookies.set("NEXT_LOCALE", preferred, { path: "/" });
return addHeaders(request, res);

View File

@@ -34,7 +34,7 @@ const nextConfig: NextConfig = {
experimental:
process.env.NODE_ENV === "production"
? {
optimizePackageImports: ["lucide-react", "framer-motion"],
optimizePackageImports: ["lucide-react", "framer-motion", "three", "@react-three/fiber"],
}
: {
// In development, enable webpack build worker for faster builds
@@ -167,12 +167,12 @@ const nextConfig: NextConfig = {
],
},
{
// Only prevent caching for real-time/sensitive API routes
// Allow bfcache for n8n routes: use no-cache (revalidate) instead of no-store
source: "/api/n8n/(.*)",
headers: [
{
key: "Cache-Control",
value: "no-store, no-cache, must-revalidate, proxy-revalidate",
value: "no-cache, must-revalidate",
},
],
},