| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- 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<string, string> = {};
- 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 <script> 自托管),
- * UMD 构建不在 window 上声明这些 flag。若某条编译产物(尤其复杂模板的 render 函数)
- * 输出 `if (__VUE_PROD_DEVTOOLS__) {…}` 分支,而 define 未内联 → 浏览器把裸标识符当
- * 全局变量求值 → `ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined`(仅命中该分支
- * 的页面白屏/无响应,其余页面正常)。
- * 生产语义:prod 构建关闭 devtools 钩子与 dev 告警 → 全部置 false。
- */
- defineMap.__VUE_OPTIONS_API__ = 'true'; // 使用 Options API(EP 组件均为 Options API)
- defineMap.__VUE_PROD_DEVTOOLS__ = 'false'; // prod 不启用 devtools 钩子(与 prod UMD 一致)
- defineMap.__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = 'false'; // 非 SSR 项目,关闭水合差异详情
- export default defineConfig(({ command, mode }) => {
- // 契约 §4 四层口径(v0.1.24 定稿):所有对外请求 = /api + 相对路径,无一例外;
- // 前端调用路径自带 /api,vite rewrite 无条件去前缀,后端路由一律不含 /api。
- const env = loadEnv(mode, process.cwd(), 'VITE_');
- return {
- 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 地址(.env / .env.development 的 VITE_API_PROXY_TARGET 可覆盖;
- // loadEnv 显式读 .env,不依赖 shell env——shell 里 export 对 vite 进程不可见)
- '/api': {
- target: env.VITE_API_PROXY_TARGET ?? 'http://127.0.0.1:8080',
- changeOrigin: true,
- // 契约 §4:去 /api 前缀(无条件、无例外——含 /api/pay/...,支付渠道回调地址由 nginx 侧配置)
- rewrite: (p) => p.replace(/^\/api/, ''),
- },
- },
- },
- build: {
- // 质量门禁:主 chunk 上限(README §3.6);框架误打包时体积会显著超限
- chunkSizeWarningLimit: 1024,
- },
- };
- });
|