Files

101 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** @type {import('next').NextConfig} */
import bundleAnalyzer from "@next/bundle-analyzer";
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === "true",
});
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
minimumCacheTTL: 3600,
formats: ["image/avif", "image/webp"],
// 预设头像库使用本地 SVG(/avatars/*.svg),需放行 SVG 走优化器,否则 next/image 返回 400
dangerouslyAllowSVG: true,
// SVG 以 sandbox 方式渲染,禁用脚本,防止恶意 SVG 执行
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
compress: true,
poweredByHeader: false,
reactStrictMode: true,
webpack: (config, { isServer }) => {
config.watchOptions = {
...config.watchOptions,
ignored: [
"**/node_modules/**",
"**/.git/**",
"**/System Volume Information/**",
"**/DumpStack.log.tmp",
"**/pagefile.sys",
],
poll: false,
};
return config;
},
onDemandEntries: {
maxInactiveAge: 60 * 1000,
pagesBufferLength: 5,
},
experimental: {
optimizeCss: false,
},
headers: async () => {
const isDev = process.env.NODE_ENV === "development";
const headers = [
{
source: "/api/:path*",
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
},
{
source: "/:path*",
headers: [
{ key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains; preload" },
{ key: "Content-Security-Policy", value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data: blob:; font-src 'self' data:; connect-src 'self' https: wss:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=(), payment=()" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
},
{
source: "/logos/:path*",
headers: [
{ key: "Cache-Control", value: isDev ? "no-cache" : "public, max-age=86400, immutable" },
],
},
];
if (isDev) {
headers.push({
source: "/(.*)",
headers: [
{ key: "Cache-Control", value: "no-store, no-cache, must-revalidate, proxy-revalidate" },
],
});
} else {
headers.push({
source: "/_next/static/:path*",
headers: [
{ key: "Cache-Control", value: "public, max-age=31536000, immutable" },
],
});
}
return headers;
},
};
export default withBundleAnalyzer(nextConfig);