Vue模板中@mdi/js图标动态导入是否支持tree-shaking?
问题根源
你当前的方案无法支持tree-shaking的核心原因是:你在运行时动态导入全量@mdi/js包后通过变量名取值,构建工具(Vite/Webpack/Rollup)在编译阶段无法静态分析你实际用到的图标,只能将整个@mdi/js的所有图标全量打入最终产物。
最优解决方案(保留原有调用习惯,无需手动导入图标)
该方案不需要修改你现有业务代码中<Icon name='mdiMagnify' />的调用方式,仅需新增依赖、调整构建配置和Icon组件实现即可实现全量tree-shaking,仅打包用到的图标。
步骤1:安装依赖
npm install unplugin-icons @iconify-json/mdi -D # 用yarn/pnpm的话自行替换包管理器命令即可
步骤2:调整构建配置
以Vite为例,修改vite.config.js配置:
import { defineConfig } from 'vite' import Icons from 'unplugin-icons/vite' export default defineConfig({ plugins: [ // 其他原有插件 Icons({ compiler: 'vue2', // Vue3项目改为vue3即可 autoInstall: false, }) ] })
如果使用Webpack,仅需将unplugin-icons/vite替换为unplugin-icons/webpack,其余配置逻辑完全一致。
步骤3:重写Icon.vue组件
<template> <component :is="iconComponent" v-bind="$attrs" /> </template> <script> // Vue3环境需要先导入defineAsyncComponent,Vue2无需该行 // import { defineAsyncComponent } from 'vue' export default { name: 'Icon', props: { name: { required: true, type: String, }, }, computed: { iconComponent() { // 将mdi开头的驼峰命名转换为短横线命名 const iconName = this.name .replace(/^mdi/, '') .replace(/([A-Z])/g, '-$1') .toLowerCase() return defineAsyncComponent(() => import(`~icons/mdi/${iconName}`)) }, }, } </script>
备选无额外依赖方案
如果不想新增依赖,可以手动维护项目用到的图标列表,让构建工具可以静态分析:
- 新建
src/utils/icons.js文件,手动导入所有用到的图标:
export { mdiMagnify, mdiMenu, mdiClose } from '@mdi/js'
- 修改Icon组件的导入路径为本地文件:
async created() { const { [this.name]: icon } = await import('@/utils/icons.js') this.icon = icon }
该方案缺点是每次新增图标都需要手动在icons.js里加导出,优点是不需要新增第三方依赖。
内容的提问来源于stack exchange,提问作者stephenjason
相关产品推荐
相关产品推荐

