import { fileURLToPath, URL } from 'node:url'; import vue from '@vitejs/plugin-vue'; import { defineConfig, loadEnv } 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}`; /** * Vue 编译期特性开关(SFC 编译器 / @vitejs/plugin-vue 产物会引用这些裸标识符)。 * * 必须在此显式 define,原因:本项目框架层全走 UMD 全局(index.html