import { defineConfig, type Plugin } from "vite"; import react from "@vitejs/plugin-react"; import tailwindcss from "@tailwindcss/vite"; import path from "path"; import type { IncomingMessage, ServerResponse } from "node:http"; import { createMenuPreviewProxy, getMenuSiteTargetUrl, shouldProxyMenuSlugRequest } from "./menuPreviewProxy"; const PREVIEW_NO_CACHE_HEADERS = { "cache-control": "no-store, no-cache, must-revalidate", pragma: "no-cache", expires: "0", } as const; const menuSlugPreviewPlugin = (): Plugin => ({ name: "menu-slug-preview", configureServer(server) { server.middlewares.use(async (req: IncomingMessage, res: ServerResponse, next) => { if (!shouldProxyMenuSlugRequest(req.url)) { next(); return; } const targetUrl = getMenuSiteTargetUrl(req.url ?? ""); if (!targetUrl) { next(); return; } try { const response = await fetch(targetUrl, { cache: "no-store", headers: { accept: req.headers.accept ?? "*/*", "accept-language": req.headers["accept-language"] ?? "fa", "cache-control": "no-cache", pragma: "no-cache", }, }); res.statusCode = response.status; Object.entries(PREVIEW_NO_CACHE_HEADERS).forEach(([key, value]) => { res.setHeader(key, value); }); response.headers.forEach((value, key) => { const lowerKey = key.toLowerCase(); if ( lowerKey === "x-frame-options" || lowerKey === "content-security-policy" || lowerKey === "content-encoding" || lowerKey === "cache-control" || lowerKey === "etag" || lowerKey === "last-modified" || lowerKey === "expires" || lowerKey === "pragma" ) { return; } res.setHeader(key, value); }); const body = Buffer.from(await response.arrayBuffer()); res.end(body); } catch { next(); } }); }, }); // https://vite.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss(), menuSlugPreviewPlugin()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, server: { proxy: createMenuPreviewProxy(), }, });