import { realpathSync } from "node:fs"; import path from "node:path"; import type { NextConfig } from "next"; /** * While onvif is linked to a local checkout outside this project (e.g. the fork, installed * with `npm install ../onvif --no-save`), Turbopack only resolves files inside its root, so * the root must contain both (Next docs, 03-api-reference/08-turbopack.md "Root directory"). * Returns undefined for a normal install, leaving the auto-detected root alone. */ function linkedPackagesRoot(project: string, packages: string[]): string | undefined { let root = project; for (const name of packages) { let target: string; try { target = realpathSync(path.join(project, "node_modules", name)); } catch { continue; } while (path.relative(root, target).startsWith("..")) root = path.dirname(root); } return root === project ? undefined : root; } const project = process.cwd(); const turbopackRoot = linkedPackagesRoot(project, ["onvif"]); const nextConfig: NextConfig = { // A build and a dev server sharing .next fight over it; NEXT_DIST_DIR lets a build run // to one side while someone is working. ...(process.env.NEXT_DIST_DIR && { distDir: process.env.NEXT_DIST_DIR }), // What gets published: a minimal server plus only the files it needs, so installing the // package doesn't drag in Next and React (vrek iss-ej4ahga). output: "standalone", // Runtime data and the downloaded MediaMTX binary are not part of the app. outputFileTracingExcludes: { "/*": ["bin/**/*", ".data/**/*", "node_modules/@img/**/*", "node_modules/sharp/**/*"] }, // next/image is unused, and leaving it on pulls sharp's platform binaries (tens of MB). images: { unoptimized: true }, // onvif uses Node's dgram/os modules; load it with native require instead of bundling. // onvif is bundled rather than listed in serverExternalPackages. Externalizing it made // Turbopack emit require("onvif-") — a name that exists nowhere — because the // dependency comes from a git URL, which broke the published package (vrek iss-9zcawn7). // Bundled, discovery (dgram) and camera reads work from an installed copy. ...(turbopackRoot && { turbopack: { root: turbopackRoot } }), }; export default nextConfig;