Files
flatrender/next.config.mjs
T
soroush.asadi 8b716a173c fix(images): allow MinIO host in next/image remotePatterns (broken uploads)
next.config had no images.remotePatterns, so the optimizer rejected every remote
URL with HTTP 400 → all MinIO-hosted images (avatars, template art) showed broken.
Add remotePatterns derived from NEXT_PUBLIC_MINIO_URL + dev hosts (172.28.144.1/
localhost/minio :9000). Verified /_next/image → 200 image/jpeg.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 23:19:39 +03:30

83 lines
2.5 KiB
JavaScript

import createNextIntlPlugin from "next-intl/plugin";
const withNextIntl = createNextIntlPlugin("./src/i18n/request.ts");
/**
* Hosts the Next.js image optimizer is allowed to fetch from. Without these, every
* remote <Image> (MinIO uploads/avatars/template art) returns HTTP 400. Derived from
* NEXT_PUBLIC_MINIO_URL (baked at build) plus the dev MinIO hosts.
*/
function imageRemotePatterns() {
const patterns = [];
const seen = new Set();
const add = (protocol, hostname, port) => {
if (!hostname) return;
const key = `${protocol}//${hostname}:${port}`;
if (seen.has(key)) return;
seen.add(key);
patterns.push({ protocol, hostname, port: port || "", pathname: "/**" });
};
const url = process.env.NEXT_PUBLIC_MINIO_URL;
if (url) {
try {
const u = new URL(url);
add(u.protocol.replace(":", ""), u.hostname, u.port);
} catch {
/* ignore malformed env */
}
}
// dev / docker fallbacks
add("http", "172.28.144.1", "9000");
add("http", "localhost", "9000");
add("http", "minio", "9000");
return patterns;
}
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
webpack: (config, { isServer, webpack }) => {
if (!isServer) {
config.output.globalObject = "self";
}
// react-konva / konva must not load the Node `canvas` package in the browser bundle
config.resolve.alias = {
...config.resolve.alias,
canvas: false,
};
config.plugins.push(
new webpack.IgnorePlugin({
resourceRegExp: /^canvas$/,
})
);
return config;
},
images: {
// Allow the image optimizer to fetch MinIO uploads (avatars, template art, …).
remotePatterns: imageRemotePatterns(),
// Placeholder art is now a same-origin SVG from /api/placeholder (offline-safe).
// dangerouslyAllowSVG only ever serves our own generated gradients — never user
// uploads — and the CSP + attachment disposition neutralise any script content.
dangerouslyAllowSVG: true,
contentDispositionType: "attachment",
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
// Required for ffmpeg.wasm (SharedArrayBuffer needs COOP + COEP headers)
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "Cross-Origin-Opener-Policy", value: "same-origin" },
{ key: "Cross-Origin-Embedder-Policy", value: "require-corp" },
],
},
];
},
};
export default withNextIntl(nextConfig);