import { fileURLToPath } from "node:url"; import tailwindcss from "@tailwindcss/vite"; import { siteConfig } from "./shared/config/site"; import { categorySlugs } from "./shared/data/categories"; /** Unmatched path rendered through error.vue at build time and saved as out/404.html */ const NOT_FOUND_ROUTE = "/__not-found"; export default defineNuxtConfig({ compatibilityDate: "2026-10-01", ssr: true, devtools: { enabled: false }, modules: ["@pinia/nuxt"], css: ["~/assets/css/main.css", "~/assets/css/antd-overrides.css"], app: { head: { htmlAttrs: { lang: siteConfig.lang, dir: siteConfig.dir }, bodyAttrs: { class: "relative min-h-screen bg-bg font-sans text-ink antialiased", }, charset: "utf-8", viewport: "width=device-width, initial-scale=1", link: [ { rel: "preload", href: "/fonts/IRANSansWebFaNum.woff2", as: "font", type: "font/woff2", crossorigin: "", }, { rel: "preload", href: "/fonts/IRANSansWebFaNum_Bold.woff2", as: "font", type: "font/woff2", crossorigin: "", }, { rel: "icon", type: "image/svg+xml", href: siteConfig.favicon }, { rel: "manifest", href: "/manifest.webmanifest" }, ], }, }, vite: { plugins: [tailwindcss()], ssr: { noExternal: ["ant-design-vue", "@ant-design/icons-vue"] }, }, // Static export (`npm run build` → ./out), served by nginx in Docker — same flow as the Next build. nitro: { output: { publicDir: fileURLToPath(new URL("./out", import.meta.url)) }, prerender: { crawlLinks: false, routes: [ "/", "/robots.txt", "/sitemap.xml", "/manifest.webmanifest", NOT_FOUND_ROUTE, ...categorySlugs.map((s) => `/categories/${s}`), ], }, hooks: { // Nuxt's own /404.html is an empty SPA shell. Replace it with a server-rendered error.vue // (real content + noindex in the static HTML) produced by prerendering an unmatched route. "prerender:generate"(route) { if (route.route === "/404.html") route.skip = true; if (route.route === NOT_FOUND_ROUTE && route.error?.statusCode === 404) { route.error = undefined; route.fileName = "/404.html"; } }, }, }, typescript: { strict: true }, });