import { fileURLToPath, URL } from 'node:url'; import vue from '@vitejs/plugin-vue'; import { defineConfig } from 'vite'; /** * 框架运行时全走 UMD 全局(README §3.3-1「禁 import 框架」)的构建侧落地: * * ① define 注入:业务 .ts/.vue 代码里的**裸标识符**(ref / computed / defineStore / createRouter …) * 在编译期被替换为 Vue.* / Pinia.* / VueRouter.* 全局访问。 * 注意:vite 的 define 按标识符整词替换(带点号前缀的 obj.ref 不替换), * 但**解构/对象键位置不做上下文分析**——因此禁止 `const { ref } = Vue` 这类写法 * (README §3.3-1:要么裸写 ref(),要么显式 Vue.ref())。 * * ② alias 指向 shims:SFC 编译器产物形如 `import { openBlock } from 'vue'`, * 经别名重定向到 shims/*.ts(运行时从 UMD 全局转发,类型来自安装的框架 dev 依赖)。 * 该层是**唯一允许接触框架模块名**的地方,业务代码一律不写。 */ /** 可裸写的 Vue 组合式 API 标识符(编译期注入为 Vue.*) */ 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(command === 'serve'):本地把 vendor/ 当 public 根,index.html 的相对路径 * vendor/<库>@<版本>/<文件> 直接命中仓库文件,无需 OSS 即可联调; * build:不拷贝任何框架文件进 dist(框架由 nginx/OSS 在运行时提供), * dist/ 只含业务产物 —— scripts/check-dist.mjs 对此有门禁。 */ publicDir: command === 'serve' ? 'vendor' : false, resolve: { alias: { // 框架模块名 → 全局转发胶水层(唯一落点;业务代码禁写这些 import) 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)), // 业务层路径别名 '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, define: defineMap, server: { port: 5173, proxy: { // dev 联调:/api 前缀请求代理到后端 dev 地址(可用环境变量覆盖) '/api': { target: process.env.VITE_API_PROXY_TARGET ?? 'http://127.0.0.1:8080', changeOrigin: true, }, }, }, build: { // 质量门禁:主 chunk 上限(README §3.6);框架误打包时体积会显著超限 chunkSizeWarningLimit: 1024, }, }));