import express, { type Express } from "express"; import fs from "fs"; import { type Server } from "http"; import { nanoid } from "nanoid"; import path from "path"; import { fileURLToPath } from "url"; import { createServer as createViteServer } from "vite"; import viteConfig from "../../vite.config"; const SERVER_ROOT = path.dirname(fileURLToPath(import.meta.url)); export async function setupVite(app: Express, server: Server) { const serverOptions = { middlewareMode: true, // Reuse the app HTTP server for HMR so SSH forwarding only needs the app port. hmr: { server }, allowedHosts: true as const, }; const vite = await createViteServer({ ...viteConfig, configFile: false, server: serverOptions, appType: "custom", }); // 只对非 API 路由使用 Vite 中间件 app.use((req, res, next) => { const url = req.originalUrl || req.url; if (url.startsWith('/api/')) { console.log(`[Vite] Skipping API route: ${url}`); return next(); } vite.middlewares.handle(req, res, next); }); // 只对非 API 路由使用 HTML fallback app.use("*", async (req, res, next) => { const url = req.originalUrl; // 跳过 API 路由 if (url.startsWith('/api/')) { return next(); } try { const clientTemplate = path.resolve( SERVER_ROOT, "../..", "client", "index.html" ); // always reload the index.html file from disk incase it changes let template = await fs.promises.readFile(clientTemplate, "utf-8"); template = template.replace( `src="/src/main.tsx"`, `src="/src/main.tsx?v=${nanoid()}"` ); const page = await vite.transformIndexHtml(url, template); res.status(200).set({ "Content-Type": "text/html" }).end(page); } catch (e) { vite.ssrFixStacktrace(e as Error); next(e); } }); } export function serveStatic(app: Express) { const distPath = process.env.NODE_ENV === "development" ? path.resolve(SERVER_ROOT, "../..", "dist", "public") : path.resolve(SERVER_ROOT, "public"); if (!fs.existsSync(distPath)) { console.error( `Could not find the build directory: ${distPath}, make sure to build the client first` ); } app.use(express.static(distPath)); // fall through to index.html if the file doesn't exist app.use("*", (_req, res) => { res.sendFile(path.resolve(distPath, "index.html")); }); }