Vue3+Vant打包报错 Identifier ‘bem‘ has already been declared的问题排查与解决
作者:网罗开发
前言
在实际项目开发中,前端构建的坑经常出现在一些意想不到的地方。这次我在做 Vue3 + Vant 项目打包的时候,遇到了一个让人摸不着头脑的报错:
[vite:legacy-post-process] unknown: Identifier 'bem' has already been declared
按理说这是个语法错误,但奇怪的是项目本地开发完全没问题,只有在 vite build
打包时才会报错。这里我记录下完整的排查和解决过程,也分享一些在工程化场景下的经验。
问题复现
我项目的基本依赖如下:
{ "dependencies": { "vue": "^3.3.4", "vant": "^4.8.0" }, "devDependencies": { "vite": "^5.0.0", "@vitejs/plugin-vue": "^5.0.0", "@vitejs/plugin-legacy": "^5.4.0" } }
代码中使用了 Vant 按需引入,配置方式如下:
// vite.config.ts import { defineConfig } from "vite" import vue from "@vitejs/plugin-vue" import legacy from "@vitejs/plugin-legacy" import Components from "unplugin-vue-components/vite" import { VantResolver } from "unplugin-vue-components/resolvers" export default defineConfig({ plugins: [ vue(), Components({ resolvers: [VantResolver()], }), legacy({ targets: ["defaults", "not IE 11"], }), ], })
运行 npm run dev
一切正常,UI 渲染没问题。但一旦 npm run build
,就抛出:
[vite:legacy-post-process] unknown: Identifier 'bem' has already been declared
而且注释掉 legacy
插件,依然会报错。
排查过程
1.怀疑是 Vant 内部工具函数冲突
Vant 内部实现里确实有一个 bem
方法,用来生成 CSS BEM className。但按理说不会暴露到全局,也不该和我们项目的变量冲突。
2.定位到编译产物
我在打包后的 .vite
缓存和 dist
下代码里搜索 bem
,发现编译结果里有重复的 const bem = ...
定义,说明某些模块在打包时被重复引入,导致语法层面报错。
3.怀疑 unplugin-vue-components 插件引入方式
如果 unplugin-vue-components
插件没有正确配置 resolvers
,有可能导致 Vant 组件被同时按需引入和全量引入,进而重复打包。
4.对比官方文档
Vant 官方建议 Vite 项目用 unplugin-vue-components + unplugin-auto-import,而且要保证 Vant 只走一套导入机制。
解决方案
最终我通过以下几个步骤解决了问题:
1. 确认 Vant 引入方式唯一
先检查自己代码里有没有手动 import { Button } from 'vant'
或者 import 'vant/lib/index.css'
。如果有,可能会和 unplugin-vue-components
插件的自动导入冲突。
最终只保留插件方式:
// vite.config.ts import Components from "unplugin-vue-components/vite" import { VantResolver } from "unplugin-vue-components/resolvers" Components({ resolvers: [VantResolver()], })
代码中直接写:
<template> <van-button type="primary">确认</van-button> </template>
不再写任何 import。
2. 排查 legacy 插件冲突
虽然注释掉 legacy 还是报错,但在我的场景里,legacy 会进一步放大 polyfill 和语法转换的问题。我尝试了 升级 legacy 插件 并修改配置:
legacy({ targets: ["defaults", "not IE 11"], additionalLegacyPolyfills: ["regenerator-runtime/runtime"], // 补充必要 polyfill })
这样可以避免某些全局 polyfill 影响。
3. 锁定依赖版本
因为 bem
冲突和 Vant 内部实现相关,我最终把 Vant 锁定到 最新的稳定版本,并清理 node_modules 重新安装:
rm -rf node_modules package-lock.json pnpm-lock.yaml npm install
我的最终依赖:
"vant": "4.8.5", "unplugin-vue-components": "^0.25.2",
可运行 Demo
这是一个最小可复现的 Demo 配置:
npm init vite@latest vite-vant-demo cd vite-vant-demo npm install npm install vant unplugin-vue-components unplugin-auto-import
vite.config.ts 配置:
import { defineConfig } from "vite" import vue from "@vitejs/plugin-vue" import Components from "unplugin-vue-components/vite" import { VantResolver } from "unplugin-vue-components/resolvers" export default defineConfig({ plugins: [ vue(), Components({ resolvers: [VantResolver()], }), ], })
App.vue:
<template> <van-button type="primary">确认</van-button> </template>
运行 npm run build
,就不会再出现 Identifier 'bem' has already been declared
的报错。
实际场景的启示
这个问题表面看是 “语法错误”,但实质是 重复依赖和编译冲突。我总结几点经验:
- 依赖引入保持单一来源:按需引入就不要再手动 import,否则容易重复打包。
- 插件版本要匹配:Vite 插件、Vant、unplugin-vue-components 要保持在相互兼容的版本。
- legacy 插件要谨慎使用:如果目标用户浏览器环境允许,可以考虑不引入 legacy,以避免构建复杂化。
- 遇到奇怪语法报错,直接翻 dist 代码:通常能看到冲突的根源。
总结
Vue3 + Vant 项目打包时报 Identifier 'bem' has already been declared
,多数是由于 组件引入重复 或 插件版本不兼容。
解决方式是统一引入方式(推荐 unplugin-vue-components
)、升级到最新 Vant 版本、必要时调整 legacy 配置。
这类问题虽然定位过程比较绕,但一旦搞清楚构建流程,就能快速解决。
到此这篇关于Vue3+Vant打包报错 Identifier ‘bem‘ has already been declared的问题排查与解决的文章就介绍到这了,更多相关Vue3 Vant打包报错解决内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!