Vite 进行组件自动化注册

对于libs中的通用组件,进行手动的组件注册是这样的:

// libs/index.js
import svgIcon from './svg-icon/index.vue'
export default {
install(app) {
app.component('m-svg-icon', svgIcon)
}
}

每生成一个通用组件都需要引入注册一次。

通过Vite提供的功能,如何进行通用组件的注册呢?

步骤

  1. 获取当前路径下所有文件夹中的 index.vue
  2. 遍历获取到的组件模块
  3. 利用 app.component 进行注册

vite 的 Glob 导入 功能

  • 文件系统中导入多个模块

Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块:

const modules = import.meta.glob('./dir/*.js')

匹配到的文件默认是懒加载的,通过动态导入实现,并会在构建时分离为独立的 chunk。以上将会被转译为下面的样子:

// vite 生成的代码
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
'./dir/bar.js': () => import('./dir/bar.js')
}

遍历 modules 对象的 key 值来访问相应的模块:

for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}

利用这样的功能,我们就可以实现第一条和第二条:获取当前路径下所有文件夹中的 index.vue并且遍历获取到的组件模块:

export default {
install(app) {
// 1. 获取当前路径下所有文件夹中的 index.vue
const components = import.meta.glob('./*/index.vue')
console.log(components)
}
}
3D86B3C5-9F06-46ED-9764-5F6B530B9885

控制台里可以看到我们获取到了libs下所有的组件中的index.vue文件,此时我们遍历获取到的组件来获得他们的相对路径:

export default {
install(app) {
// 1. 获取当前路径下所有文件夹中的 index.vue
const components = import.meta.glob('./*/index.vue')
// console.log(components)
+ // 2. 遍历获取到的组件模块
+ for (const [fullPath, fn] of Object.entries(components)) {
+ console.log(fullPath)
+ }
}
}
FB1BA1A4-4855-49CC-8CCB-405E8D4C2D65

控制台上打印出了我们当前文件夹下所有组件的相对路径。

接下来是统一命名方式,在注册过程中我们的组件命名方式是m-xxx,因此我们把fullPath处理一下:

export default {
install(app) {
// 1. 获取当前路径下所有文件夹中的 index.vue
const components = import.meta.glob('./*/index.vue')
// 2. 遍历获取到的组件模块
for (const [fullPath, fn] of Object.entries(components)) {
+ // 拼接组件注册的 name
+ const componentName = 'm-' + fullPath.replace('./', '').split('/')[0]
}
}
}
0ED0AEFB-7907-4893-8632-1B239F1C2F47

对通用组件的名称统一我们已经处理好了。

vue 的 defineAsyncComponent

  • 创建一个只有在需要时才会加载的异步组件

对于基本用法,defineAsyncComponent 可以接受一个返回 Promise 的工厂函数。Promise 的 resolve 回调应该在服务端返回组件定义后被调用。你也可以调用 reject(reason) 来表示加载失败。

import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
app.component('async-component', AsyncComp)

for (const [fullPath, fn] of Object.entries(components)) {}遍历过程中我们获取的[fullPath, fn],控制台打印可以看到,fn是一个import('')的回调函数,根据defineAsyncComponent官方文档,这正是我们想要的:

EF6CB418-C5DE-4886-9BD3-91CC5BF4C9CB

此时我们通过 defineAsyncComponent 异步导入fn并且用利用 app.component 进行注册就完成了:

export default {
install(app) {
// 1. 获取当前路径下所有文件夹中的 index.vue
const components = import.meta.glob('./*/index.vue')
// 2. 遍历获取到的组件模块
for (const [fullPath, fn] of Object.entries(components)) {
// 拼接组件注册的 name
const componentName = 'm-' + fullPath.replace('./', '').split('/')[0]
// 通过 defineAsyncComponent 异步导入指定路径下的组件
// 3. 利用 app.component 进行注册
+ app.component(componentName, defineAsyncComponent(fn))
}
}
}

回到项目之中,在libs下的通用组件仍然能够正常显示,之后再次在该文件夹下用相同格式写通用组件,就可以实现自动注册了。