zizi 9e95a66ea6 refactor: 技术命名空间 huijing→wanxiang 全栈落地(代码+契约,原「只改文档」决策反转)
- Java 包 cn.huijing.game→cn.wanxiang.game:126 .java + 15 目录 git mv(保留历史)+ Application scanBasePackages/@MapperScan + yaml type-aliases
- SDK HuijingGameSDK→WanxiangGameSDK + postMessage channel huijing-game-sdk→wanxiang-game-sdk(契约 + 前端 host/sdk/inject/bridge)
- 契约 contracts/ 同步(sdk-interface.d.ts / runtime.yaml / game-package.schema / $id URL / V3 SQL 注释)
- 主 agent 独立验证全绿:后端集成编译+55 单测(cn.wanxiang)、前端 build+/browse 冒烟(WanxiangGameSDK+demo 911 像素+遥测 200)、残留 huijing=0、Flyway 5 迁移 diff-identical、yudao cn.iocoder.yudao 2167 文件未误伤
- 保留 yudao 框架 cn.iocoder.yudao + Maven groupId cn.iocoder.cloud

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:16:52 +00:00

101 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { fileURLToPath, URL } from 'node:url'
import type { IncomingMessage } from 'node:http'
import { defineConfig, type Connect, type PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
// 自写 mock 调度器(DOM-free,dev/preview 两端复用)。严格按 contracts/api-schemas 返回数据。
import { dispatch, MOCK_PREFIXES } from './src/mock/index.ts'
/**
* 读取请求体(POST/PUT 等),解析为 JSON。
* connect 中间件层面手动收 chunk,避免依赖 body-parser(零额外依赖)。
*/
function readBody(req: IncomingMessage): Promise<unknown> {
return new Promise((resolve) => {
const chunks: Buffer[] = []
req.on('data', (c: Buffer) => chunks.push(c))
req.on('end', () => {
if (chunks.length === 0) {
resolve(undefined)
return
}
const raw = Buffer.concat(chunks).toString('utf-8')
try {
resolve(raw ? JSON.parse(raw) : undefined)
} catch {
// 非 JSON 体(如 sendBeacon 偶发)直接透传原文,handler 自行兜底
resolve(raw)
}
})
req.on('error', () => resolve(undefined))
})
}
/** 判断 url 是否命中 mock 前缀(/app-api、/admin-api) */
function isMockUrl(url: string | undefined): boolean {
if (!url) return false
return MOCK_PREFIXES.some((p) => url === p || url.startsWith(p + '/') || url.startsWith(p + '?'))
}
/**
* connect 中间件:拦截 API 请求 → 调 dispatch → 写 JSON 包络。
* 未命中 mock 路由则调用 next() 放行(不误吞静态资源/HMR 等)。
*/
const mockMiddleware: Connect.NextHandleFunction = (req, res, next) => {
const url = req.url
if (!isMockUrl(url)) {
next()
return
}
void (async () => {
try {
const body = await readBody(req)
const result = await dispatch(req.method || 'GET', url as string, body)
if (result === null) {
// 命中前缀但无对应路由:返回 404 包络,便于排查“契约里没有的端点”被误调
res.statusCode = 404
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(JSON.stringify({ code: 404, data: null, msg: `mock 未匹配: ${req.method} ${url}` }))
return
}
res.statusCode = 200
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(JSON.stringify(result))
} catch (err) {
// 兜底:mock 自身异常也返回包络,不让请求悬挂
res.statusCode = 200
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.end(JSON.stringify({ code: 1, data: null, msg: (err as Error)?.message || 'mock error' }))
}
})()
}
/**
* 自写 mock vite 插件。
* 关键:同时 hook configureServer(dev) 与 configurePreviewServer(preview),
* 两端都把 mockMiddleware 前置注入 connect 栈 → `vite` 与 `vite preview` 都能命中 mock(验收要求)。
*/
function mockPlugin(): PluginOption {
return {
name: 'wanxiang-local-mock',
// 开发服务器(vite dev)
configureServer(server: { middlewares: Connect.Server }) {
server.middlewares.use(mockMiddleware)
},
// 预览服务器(vite preview)——验收闭环在 preview 跑,必须生效
configurePreviewServer(server: { middlewares: Connect.Server }) {
server.middlewares.use(mockMiddleware)
},
}
}
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(), mockPlugin()],
resolve: {
alias: {
// '@' → src(供 B 工位用 @/ 绝对导入;A1 自身用相对导入,避免依赖 tsconfig paths)
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
})