
Vite 生产构建会剥离函数名(func.name 为空),导致通过 import.meta.glob 动态注册的 $filters 失效;解决方案是改用具名导出的对象结构,避免匿名函数数组,确保函数名在压缩后仍可被正确识别。
vue 3 中通过 `import.meta.glob` 动态注册全局过滤器时,vite 生产构建常导致 `func.name` 为空字符串,使 `$filters.currency` 等调用失败;根本原因是函数以数组形式定义并导出后,在 terser 压缩阶段丢失了函数名标识。本文提供稳定、可维护的替代方案,并附完整实现与注意事项。
在 Vue 3 + Vite 项目中,为复刻 Vue 2 的 $filters 语法(如 {{ $filters.currency(price) }}),开发者常借助 import.meta.glob 批量导入过滤器模块。但原始写法存在严重构建兼容性问题:
// ❌ 问题写法:currency.filter.ts(数组导出)
const filters: Function[] = [
function currency(value: string) { /* ... */ },
function percent(value: number) { /* ... */ }
]
export default filters // → 经过 Vite 构建后,func.name 变为空字符串该方式在开发环境(未压缩)下能正常获取 func.name,但生产构建启用 Terser 压缩后,函数会被转为匿名形式(如 function(value){...}),func.name 永远为 "",导致 app.config.globalProperties.$filters[func.name] 实际注册为 undefined。
✅ 正确做法是放弃函数数组,改用具名对象导出,让每个过滤器作为对象属性显式声明:
// ✅ 推荐写法:currency.filter.ts(对象导出)
export default {
currency(value: string | number): string {
if (value == null) return ''
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(Number(value))
},
percent(value: number, digits = 2): string {
return `${value.toFixed(digits)}%`
}
}对应 main.ts 中的注册逻辑也需同步调整,不再依赖 func.name,而是直接遍历对象键名:
立即学习“前端免费学习笔记(深入)”;
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// 初始化全局 filters 对象
app.config.globalProperties.$filters = {}
// 批量导入并注册所有 .filter.ts 文件导出的对象
const filterModules = import.meta.glob<{ [key: string]: Function }>('./common/filters/*.filter.ts', {
eager: true,
import: 'default'
})
Object.entries(filterModules).forEach(([path, filterObj]) => {
// 将每个模块导出的对象属性(即过滤器函数)挂载到 $filters
Object.keys(filterObj).forEach(key => {
app.config.globalProperties.$filters[key] = filterObj[key]
})
})
app.mount('#app')此方案优势显著:
- ✅ 构建安全:函数名由对象键名(字符串字面量)决定,不受 Terser 压缩影响;
- ✅ 类型友好:TypeScript 可精确推导
filterObj类型,支持自动补全与类型检查; - ✅ 可读性强:每个过滤器语义清晰,便于维护与单元测试;
- ✅ 零运行时开销:
eager: true确保编译期静态分析,无动态require或eval。
⚠️ 注意事项:
- 避免在过滤器函数内使用
this或依赖组件实例上下文——它们是纯函数,不应访问响应式数据或生命周期; - 若需国际化、日期格式化等能力,优先封装为独立 Composable(如
useDateFormat()),而非全局过滤器,以提升可测试性与组合灵活性; - 在
<script setup></script>中仍可直接使用$filters.xxx(),但更推荐在 Composition API 中通过getCurrentInstance()?.proxy?.$filters(不推荐)或显式导入函数(推荐)方式调用,以保持逻辑解耦。
总结:Vite 生产环境下 func.name 不可靠是已知约束,与其绕过压缩机制,不如拥抱现代 ES 模块设计范式——用具名对象替代函数数组,用静态键名替代动态 name 属性。这不仅解决当前问题,更让代码更健壮、可维护、易演进。


















