vite 动态导入 element
使用element-plus + vite按需引入的方式,当首次启动vite服务时会对style进行依赖预构建,并且在切换不同路由时如果其他模块有使用到新的组件,页面会卡住直至dependencies optimized完成:

解决方案
开发时全量导入
element-plus组件,打包时按需导入。
开发环境完整引入
针对开发环境,我们希望完整引入 element-plus 的所有组件。在 vite.config.js 中通过添加一个自定义插件来实现这个功能:
import process from 'node:process'
import { defineConfig } from 'vite'
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig({
// ...
plugins: [
// ...
process.env.NODE_ENV === 'development'
? {
name: 'vite:element-plus-auto-import-in-dev',
transform(code, id) {
if (/src\/main.ts$/.test(id)) {
return {
code: `
import ElementPlus from 'element-plus'
import 'element-plus/theme-chalk/src/index.scss'
${code.split('const app = createApp(App)').join('const app = createApp(App);app.use(ElementPlus);')};
`,
map: null,
}
}
},
}
: ElementPlus({ useSource: true }),
],
})transform: 用于修改代码的钩子函数,返回值是一个对象,包含修改后的代码和 sourcemap。process.env.NODE_ENV: 用于判断当前是否是开发环境。src/main.ts: 用于匹配入口文件。code: 用于修改入口文件的代码,将 ElementPlus 注入到 app 中。map: 用于 sourcemap,这里不需要 sourcemap,所以设置为 null。split: 此处是为了避免在APP.vue中使用了el-config-provider,导致页面比ElementPlus加载快,因此需要在mount之前引入ElementPlus。
引入css的时候最好是用以上的方式,如果使用
import 'element-plus/dist/index.css'的方式,可能会存在自定义样式覆盖不到的问题。
在tsconfig.json中添加 element-plus 的类型声明:
{
"compilerOptions": {
"types": [
// ...
"element-plus/global"
]
}
}打包按需引入
在生产环境,我们希望按需引入 element-plus 的组件,这样可以减少打包后的体积,通过配置unplugin-vue-components插件来实现这个功能:
import process from 'node:process'
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
// ...
Components({
dts: 'src/components.d.ts',
include: [/\.vue$/, /\.vue\?vue/],
exclude: ['src/components/**/components/**/*'],
resolvers: process.env.NODE_ENV === 'production' ? ElementPlusResolver({ importStyle: 'sass' }) : undefined,
}),
],
})
unplugin-vue-components的具体配置项可以查看Github。ElementPlusResolver具体配置项可以查看官方文档或者Github。
还需注意
因为这个方案是在开发环境进行全局引入,打包构建后还是保留按需引入。所以在使用 message 这类函数组件时,需要使用import { ElMessage } from 'element-plus'这种手动导入的方式。如果嫌麻烦则可以使用 unplugin-auto-import ,并且在 optimizeDeps 里对这类反馈组件的样式进行预构建:
import path from 'node:path'
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
// ...
optimizeDeps: {
include: [
'@element-plus/icons-vue',
'element-plus/es',
'element-plus/es/components/base/style/index',
'element-plus/es/components/message/style/index',
'element-plus/es/components/message-box/style/index',
'element-plus/es/components/notification/style/index',
],
},
plugins: [
// ...
AutoImport({
imports: [
'vue',
'pinia',
'@vueuse/core',
VueRouterAutoImports,
{
// add any other imports you were relying on
'vue-router/auto': ['useLink'],
},
],
resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
dts: 'src/auto-imports.d.ts',
dirs: [
'src/composables',
'src/events',
'src/stores',
'src/utils',
],
vueTemplate: true,
}),
],
})