mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-26 20:45:37 +02:00
* fix(web): resolve upstream URLs at runtime * fix(web): keep unconfigured upstreams same-origin * fix(web): restore dev-only localhost fallbacks for API and docs upstreams `next dev` on a developer machine now falls back to the conventional http://localhost:8080 backend (honoring BACKEND_PORT) and http://localhost:4000 docs origin when nothing is configured, so a bare `pnpm dev:web` keeps proxying out of the box. Builds and the runtime proxy keep the strict resolvers, so prebuilt images still leave unset upstreams unproxied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
import type { NextConfig } from "next";
|
|
import { config } from "dotenv";
|
|
import { resolve } from "path";
|
|
import {
|
|
resolveDevDocsUrl,
|
|
resolveDevRemoteApiUrl,
|
|
resolveDocsUrl,
|
|
resolveRemoteApiUrl,
|
|
} from "./config/runtime-urls";
|
|
import { createMDX } from "fumadocs-mdx/next";
|
|
|
|
// Load root .env so local next.config.ts rewrites see REMOTE_API_URL / DOCS_URL.
|
|
// Production requests use proxy.ts runtime rewrites, which read process.env
|
|
// when the Next.js server runs instead of baking these URLs at build time.
|
|
config({ path: resolve(__dirname, "../../.env") });
|
|
|
|
// `next dev` falls back to the conventional localhost upstreams; builds use
|
|
// the strict resolvers so prebuilt images keep unset upstreams unproxied.
|
|
const isDev = process.env.NODE_ENV === "development";
|
|
const remoteApiUrl = isDev
|
|
? resolveDevRemoteApiUrl(process.env)
|
|
: resolveRemoteApiUrl(process.env);
|
|
const docsUrl = isDev
|
|
? resolveDevDocsUrl(process.env)
|
|
: resolveDocsUrl(process.env);
|
|
|
|
// Parse hostnames from CORS_ALLOWED_ORIGINS so that Next.js dev server
|
|
// allows cross-origin HMR / webpack requests (e.g. from Tailscale IPs).
|
|
const allowedDevOrigins = process.env.CORS_ALLOWED_ORIGINS
|
|
? process.env.CORS_ALLOWED_ORIGINS.split(",")
|
|
.map((origin) => {
|
|
try {
|
|
return new URL(origin.trim()).host;
|
|
} catch {
|
|
return origin.trim();
|
|
}
|
|
})
|
|
.filter(Boolean)
|
|
: undefined;
|
|
|
|
const nextConfig: NextConfig = {
|
|
...(process.env.STANDALONE === "true" ? { output: "standalone" as const } : {}),
|
|
transpilePackages: ["@multica/core", "@multica/ui", "@multica/views"],
|
|
...(allowedDevOrigins && allowedDevOrigins.length > 0
|
|
? { allowedDevOrigins }
|
|
: {}),
|
|
images: {
|
|
formats: ["image/avif", "image/webp"],
|
|
qualities: [75, 80, 85],
|
|
},
|
|
async rewrites() {
|
|
return {
|
|
// Run before file-system routes so /docs isn't shadowed by the
|
|
// [workspaceSlug] dynamic segment.
|
|
beforeFiles: docsUrl
|
|
? [
|
|
{
|
|
source: "/docs",
|
|
destination: `${docsUrl}/docs`,
|
|
},
|
|
{
|
|
source: "/docs/:path*",
|
|
destination: `${docsUrl}/docs/:path*`,
|
|
},
|
|
]
|
|
: [],
|
|
afterFiles: remoteApiUrl
|
|
? [
|
|
{
|
|
source: "/api/:path*",
|
|
destination: `${remoteApiUrl}/api/:path*`,
|
|
},
|
|
{
|
|
source: "/ws",
|
|
destination: `${remoteApiUrl}/ws`,
|
|
},
|
|
{
|
|
source: "/auth/:path*",
|
|
destination: `${remoteApiUrl}/auth/:path*`,
|
|
},
|
|
{
|
|
source: "/uploads/:path*",
|
|
destination: `${remoteApiUrl}/uploads/:path*`,
|
|
},
|
|
]
|
|
: [],
|
|
fallback: [],
|
|
};
|
|
},
|
|
};
|
|
|
|
// fumadocs-mdx@12 is incompatible with Next 16's Turbopack: its loader fails to
|
|
// dynamic-import `.source/source.config.mjs` under the Turbopack Node evaluator
|
|
// (see fumadocs#2658). `dev`/`build` scripts pass `--webpack` to opt out.
|
|
// Drop the flag once fumadocs-mdx ships a Turbopack-compatible loader.
|
|
const withMDX = createMDX() as (config: NextConfig) => NextConfig;
|
|
|
|
export default withMDX(nextConfig);
|