likes
comments
collection
share

vue3 +vite 黑科技,组件自动引入

作者站长头像
站长
· 阅读数 34

前言

按需引入插件unplugin-vue-components 的教程已经很多了,本文并不是单纯的介绍unplugin-vue-components 插件,而是vite-plugin-autogeneration-import-fileunplugin-vue-components两个插件结合使用,以弥补unplugin-vue-components的不足,看下去绝对物超所值。

unplugin-vue-components

unplugin-vue-components是我们按需引入的核心,是尤大推荐的一款插件,可以让我们直接写组件名,就可以在编译时自动添加引入对应组件的代码。

安装

npm install unplugin-vue-components -D

引入流行组件库

unplugin-vue-components支持多个流行组件库(包括Ant Design Vueelement-plusNaive UI等 具体请查看官方文档),这里以element-plus为例子

// vite.config.ts 
import { defineConfig } from 'vite' 
import Components from 'unplugin-vue-components/vite' 
import { ElementPlusResolver} from 'unplugin-vue-components/resolvers' 
export default defineConfig({ 
plugins: [ 
    Components({
        // ui库解析器,也可以自定义 
        resolvers: [ 
            ElementPlusResolver(),
        ]
    })
] 
})

插件会生成.d.ts type文件(components.d.ts文件,具体路径可以设置dts自行配置),用于typescript类型识别 详情看这个vue3的issue types(defineComponent): support for expose component types

// components.d.ts

// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399

declare module 'vue' {
  export interface GlobalComponents {
    ElAside: typeof import('element-plus/es')['ElAside']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElContainer: typeof import('element-plus/es')['ElContainer']
    ElDropdown: typeof import('element-plus/es')['ElDropdown']
    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
    ElHeader: typeof import('element-plus/es')['ElHeader']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElMain: typeof import('element-plus/es')['ElMain']
    ElMenu: typeof import('element-plus/es')['ElMenu']
    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
    ElResult: typeof import('element-plus/es')['ElResult']
  }
}

export { }


自动导入自己的组件

直接写组件名即可,插件会帮你引入进来

vite 配置详情

// vite.config.ts
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver} from 'unplugin-vue-components/resolvers' 
export default defineConfig({
  plugins: [
    Components({
      // 指定组件所在文件夹的位置,默认是src/components
      dirs: ['src/components'],
      // ui库解析器
      resolvers: [ElementPlusResolver()],
      extensions: ['vue'],//文件扩展
      // 配置type文件生成位置
      dts: 'src/components.d.ts'
    })
  ]
})

自己的组件类型也会生成到components.d.ts

// components.d.ts

// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399

declare module 'vue' {
  export interface GlobalComponents {
    ElAside: typeof import('element-plus/es')['ElAside']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElContainer: typeof import('element-plus/es')['ElContainer']
    ElDropdown: typeof import('element-plus/es')['ElDropdown']
    ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
    ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
    ElHeader: typeof import('element-plus/es')['ElHeader']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElMain: typeof import('element-plus/es')['ElMain']
    ElMenu: typeof import('element-plus/es')['ElMenu']
    ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
    ElResult: typeof import('element-plus/es')['ElResult']
    BaseHeader: typeof import('./components/Common/BaseHeader.vue')['default']
    BaseForm: typeof import('./components/Common/BaseForm.vue')['default']
    BaseTags: typeof import('./components/Common/BaseTags.vue')['default']
  }
}

export { }

配置说明

下面显示配置的默认值

Components({
  // 用于搜索组件的目录的相对路径。
  dirs: ['src/components'],

  // 组件的有效文件扩展名。
  extensions: ['vue'],
  // 搜索子目录
  deep: true,
  // 自定义组件的解析器
  resolvers: [],

  //生成`components.d.ts`的全局声明,  
  //也接受自定义文件名的路径  
  // 如果安装了typescript包default: true
  dts: false,

  // 允许子目录作为组件的名称空间前缀。
  directoryAsNamespace: false,
  // 忽略名称空间前缀的子目录路径
  // 当`directoryAsNamespace: true`时工作
  globalNamespaces: [],

  // 自动导入指令
  // 默认:' true '用于Vue 3, ' false '用于Vue 2
  // Vue 2需要使用Babel进行转换,出于性能考虑,它在默认情况下是禁用的
  // 要安装Babel,运行:' npm install -D @babel/parser '
  directives: true,

  // 在解析之前转换路径
  importPathTransform: v => v,

  // 允许组件覆盖具有相同名称的其他组件
  allowOverrides: false,

  // 变换目标的滤波器
  include: [/.vue$/, /.vue?vue/],
  exclude: [/[\/]node_modules[\/]/, /[\/].git[\/]/, /[\/].nuxt[\/]/],

  // Vue版本的项目。如果没有指定,它将自动检测。
  // 取值范围: 2 | 2.7 | 3
  version: 2.7
})

vite-plugin-autogeneration-import-file

使用unplugin-vue-components能基本满足我们的需求,但是有几点不足

  1. 引入组件的规则配置不够灵活,只支持配置文件夹和是否递归,组件的名称转化和递归时具体指定哪个文件忽略掉哪个文件无法自行配置

  2. component.d.ts里面的类型不是创建完组件后自动生成,而是我们访问页面或者vite热更新代码时,扫描到我们用到了某个组件才会生成对应的类型声明。这样不利于新建时编辑器提示。

针对以上两点不足,我们使用第二个插件vite-plugin-autogeneration-import-filevite-plugin-autogeneration-import-file可以扫描特定文件下,特定模式的文件自动生成特定模板的文件,并且是在运行dev命令、build命令和文件变更时自动生成。 支持导出unplugin-vue-componentsresolver函数。

安装

npm i vite-plugin-autogeneration-import-file -D

配置使用

// vite.config.ts
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver} from 'unplugin-vue-components/resolvers'
import { createPlugin } from 'vite-plugin-autogeneration-import-file';
const {autoImport, resolver} = createPlugin();
function pathResolve(dir: string) {//路径转化
  return resolve(__dirname, '.', dir);
}
export default defineConfig({
  plugins: [
   autoImport([
        // 自动生成
        {
          // auto import components
          pattern: ['*.{vue,ts}', '**/index.{vue,ts}'],//监听的文件规则当前规则为 监听文件夹下的后缀为vue/ts子文件和 文件名为index.vue和index.ts的子孙文件
          dir: pathResolve('src/components'),//监听的文件夹
          toFile: pathResolve('types/components.d.ts'),//生成的文件
          template: fs.readFileSync(pathResolve('./template/components.d.ts'), 'utf-8'),//文件生成模板
          codeTemplates: [ //代码模板
            {
              key: '//code',
              template: '{{name}}: typeof import("{{path}}")["default"];\n    ',
            },
            {
              key: '//typeCode',
              template: 'type {{name}}Instance = InstanceType<typeof import("{{path}}")["default"]>;\n  ',
            },
          ],
          name: '_{{name}}',//组件名命名规则支持字符串模板和函数
        },
      ]),
    Components({
      // 忽略掉'unplugin-vue-components'的组件引入
      dirs: [],
      // ui库解析器
      resolvers: [resolver([0])],//应用vite-plugin-autogeneration-import-file插件的第0组规则进行组件引入
      //禁止生成component.d.ts
      dts: false
    })
  ]
})

template/components.d.ts 模板内容

declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    //code
  }
}
declare global {
  //typeCode
}
export {};

详细配置说明请参考vite-plugin-autogeneration-import-file文档

因为每次运行devbuild命令都会重新生成component.d.ts建议在git中忽略掉component.d.ts以免自动生成的文件冲突

示例项目

当前插件以在我的开源项目meadmin-template(一个element-plus+vxetable+vite3+ts应用最新技术栈的后台模板)中使用,大家可以拉下来测一下,希望帮到您的同时能star一下 meadmin-templatevite-plugin-autogeneration-import-file