import type { IncomingHttpHeaders } from 'node:http'; import { fileURLToPath, URL } from 'node:url'; import type { Connect, Plugin } from 'vite'; import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { mockRoutes } from './src/mock/routes'; interface MockContext { body: unknown; headers: IncomingHttpHeaders; method: string; query: Record; url: string; } const createMockMiddleware = (): Connect.NextHandleFunction => { return async (req, res, next) => { if (!req.url || !req.method) { next(); return; } const method = req.method.toUpperCase(); const requestUrl = new URL(req.url, 'http://localhost'); const route = mockRoutes.find((item) => { const methodMatched = item.method === method; const pathMatched = typeof item.path === 'string' ? item.path === requestUrl.pathname : item.path.test(requestUrl.pathname); return methodMatched && pathMatched; }); if (!route) { next(); return; } const body = await new Promise((resolve, reject) => { if (method === 'GET') { resolve(''); return; } let raw = ''; req.on('data', (chunk: Buffer) => { raw += chunk.toString(); }); req.on('end', () => resolve(raw)); req.on('error', reject); }); let parsedBody: unknown = {}; if (body) { try { parsedBody = JSON.parse(body); } catch { parsedBody = body; } } const payload = await route.handler({ body: parsedBody, headers: req.headers, method, query: Object.fromEntries(requestUrl.searchParams.entries()), url: requestUrl.pathname } as MockContext); res.statusCode = 200; res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.end(JSON.stringify(payload)); }; }; const mockApiPlugin = (): Plugin => { const middleware = createMockMiddleware(); return { name: 'crossborder-os-mock-api', configureServer(server) { server.middlewares.use(middleware); }, configurePreviewServer(server) { server.middlewares.use(middleware); } }; }; export default defineConfig({ plugins: [vue(), mockApiPlugin()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { host: '0.0.0.0', port: 5173 }, build: { rollupOptions: { output: { manualChunks(id) { if (id.includes('node_modules/element-plus') || id.includes('@element-plus')) { return 'element-plus'; } if (id.includes('node_modules/vue') || id.includes('node_modules/pinia') || id.includes('node_modules/vue-router')) { return 'vue-vendor'; } } } } } });