import { fileURLToPath, URL } from 'node:url'; import vue from '@vitejs/plugin-vue'; import { defineConfig } from 'vite'; /** * 框架运行时混合方案(移动端,README §技术栈): * * ① UMD 全局(Vue 系 + axios):index.html 按序引入 vendor/ 自托管 UMD(dev 经 publicDir 服务, * 生产经 nginx/OSS),裸标识符(ref、computed、defineStore…)经下方 define 编译期替换为 * Vue.*、VueRouter.*、Pinia.* 全局访问;SFC 编译器产物的模块名 import 经 alias 重定向到 * 仓库根 shims 目录(运行时取 UMD 全局转发,框架本体不进 dist)。 * * ② npm 编译(Vant):Vant 4 官方无 UMD 构建,只能 import 编译进 bundle—— * 故 Vant **不进** define/alias 清单(`app.use(Vant)` 在 main.ts 走 npm import), * 模板里 van-* 组件由 Vue 全局组件解析(经 alias 的 vue 转发),无需 vant shim。 * dist 因此含 Vant 运行时(与 PC 端"dist 不含 ElementPlus"的差异点,由 Vant 无 UMD 决定)。 */ /** 可裸写的 Vue 组合式 API 标识符(编译期注入为 Vue.*)——与 PC 端同源清单 */ const VUE_APIS: readonly string[] = [ 'ref', 'shallowRef', 'reactive', 'shallowReactive', 'readonly', 'shallowReadonly', 'computed', 'watch', 'watchEffect', 'watchPostEffect', 'watchSyncEffect', 'effectScope', 'onMounted', 'onUnmounted', 'onBeforeMount', 'onBeforeUnmount', 'onUpdated', 'onBeforeUpdate', 'onActivated', 'onDeactivated', 'onErrorCaptured', 'onRenderTracked', 'onRenderTriggered', 'onScopeDispose', 'nextTick', 'h', 'inject', 'provide', 'toRef', 'toRefs', 'toRaw', 'toValue', 'markRaw', 'isRef', 'isReactive', 'isReadonly', 'isVNode', 'customRef', 'triggerRef', 'unref', 'createApp', ] as const; /** 可裸写的 Vue Router 标识符(注入为 VueRouter.*) */ const VUE_ROUTER_APIS: readonly string[] = [ 'createRouter', 'createWebHashHistory', 'createWebHistory', 'useRoute', 'useRouter', ] as const; /** 可裸写的 Pinia 标识符(注入为 Pinia.*) */ const PINIA_APIS: readonly string[] = [ 'defineStore', 'createPinia', 'getActivePinia', 'setActivePinia', 'storeToRefs', ] as const; const defineMap: Record = {}; for (const api of VUE_APIS) defineMap[api] = `Vue.${api}`; for (const api of VUE_ROUTER_APIS) defineMap[api] = `VueRouter.${api}`; for (const api of PINIA_APIS) defineMap[api] = `Pinia.${api}`; export default defineConfig(({ command }) => ({ plugins: [vue()], /** * dev(serve):把仓库根 vendor/ 当 public 根,index.html 的 /vendor/<库>@<版本>/<文件> 直接命中, * 无需 OSS 即可联调;build:不拷贝任何框架文件进 dist(框架由 nginx/OSS 在运行时提供)。 * 注:publicDir 相对 root(本 app 目录)解析,故 ../../vendor = 仓库根 vendor。 */ publicDir: command === 'serve' ? '../../vendor' : false, resolve: { alias: { // UMD 全局框架模块名 → 仓库根 shims 转发层(唯一落点;业务代码禁写这些 import)。 // 路径基:import.meta.url 在 apps/teacher/vite.config.ts,仓库根为上两级(../../)。 vue: fileURLToPath(new URL('../../shims/vue.ts', import.meta.url)), 'vue-router': fileURLToPath(new URL('../../shims/vue-router.ts', import.meta.url)), pinia: fileURLToPath(new URL('../../shims/pinia.ts', import.meta.url)), // 共享层:@unified/shared 直指源码(monorepo 源码消费,免构建) '@unified/shared': fileURLToPath(new URL('../../packages/shared/src', import.meta.url)), // 本端业务层路径别名(@ → 本 app 的 src) '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, define: defineMap, server: { port: 5174, proxy: { // dev 联调:/api 前缀请求代理到后端 dev 地址(可用环境变量覆盖) '/api': { target: process.env.VITE_API_PROXY_TARGET ?? 'http://127.0.0.1:8080', changeOrigin: true, }, }, }, build: { // 质量门禁:主 chunk 上限(README §质量门禁);UMD 框架误打包时体积会显著超限 //(注意:Vant 经 npm 编译进 bundle 属预期,体积判据需结合 Vant 基础体量,非"零框架"判据) chunkSizeWarningLimit: 1024, }, }));