尤大推荐的神器unplugin-vue-components,解放双手!以后再也不用呆呆的手动引入(组件,ui(Element-ui)库,vue hooks等)__Vite__Vue.js
发布于 3 年前 作者 banyungong 4962 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

theme: channing-cyan

先看效果 一个import都没有!

image.png 本文将介绍下面几个vite插件(可自由搭配,推荐node版本14+) demo仓库地址

1 unplugin-vue-components

image.png

1.1 自动导入ui库,该插件内置了大多数流行库解析器

这里拿几个流行ui库做栗子 Element Plus Ant Design Vue Vant Element UI Headless UI 安装

npm install unplugin-vue-components -D

然后将下面的代码添加到 Vite 或 webpack 的配置文件。

Vite配置

// vite.config.js
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'
import {
  ElementPlusResolver,
  AntDesignVueResolver,
  VantResolver,
  HeadlessUiResolver,
  ElementUiResolver
} from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    Components({
      // ui库解析器,也可以自定义
      resolvers: [
        ElementPlusResolver(),
        AntDesignVueResolver(),
        VantResolver(),
        HeadlessUiResolver(),
        ElementUiResolver()
      ]
    })
  ]
})

Webpack配置

// webpack.config.js
const components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver,AntDesignVueResolver,VantResolver,HeadlessUiResolver,ElementUiResolver } = require('unplugin-vue-components/resolvers')

module.exports =
  plugins: [
    Components({
      resolvers: [
         AntDesignVueResolver(),
         ElementPlusResolver(),
         VantResolver(),
         HeadlessUiResolver(),
         ElementUiResolver()
      ]
    })
  ]
}

插件会生成一个ui库组件以及指令路径components.d.ts文件,详情看这个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 { }

想了解其他的打包工具(RollupVue CLI),请参考 unplugin-vue-components

1.2 自动导入自己的组件

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

// vite.config.js
import { defineConfig } from 'vite'
import Components from 'unplugin-vue-components/vite'

export default defineConfig({
  plugins: [
    Components({
      // 指定组件位置,默认是src/components
      dirs: ['src/components'],
      // ui库解析器
      // resolvers: [ElementPlusResolver()],
      extensions: ['vue'],
      // 配置文件生成位置
      dts: 'src/components.d.ts'
    })
  ]
})

插件会生成一个自己组件路径的components.d.ts文件,详情看这个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 {
    BaseFilter: typeof import('./components/Common/BaseFilter.vue')['default']
    BaseHeader: typeof import('./components/Common/BaseHeader.vue')['default']
    BasePagination: typeof import('./components/Common/BasePagination.vue')['default']
    BaseSidebar: typeof import('./components/Common/BaseSidebar.vue')['default']
    BaseTags: typeof import('./components/Common/BaseTags.vue')['default']
    BaseTitle: typeof import('./components/Common/BaseTitle.vue')['default']
  }
}

export { }

// 插件的所有默认配置
Components({
  // relative paths to the directory to search for components.
  // 要搜索组件的目录的相对路径
  dirs: ['src/components'],
  
  // valid file extensions for components.
  // 组件的有效文件扩展名。
  extensions: ['vue'],
  
  // search for subdirectories
  // 搜索子目录
  deep: true,
  
  // resolvers for custom components
  // 自定义组件的解析器
  resolvers: [],

  // generate `components.d.ts` global declarations, 
  // also accepts a path for custom filename
  // 生成 `components.d.ts` 全局声明,
  // 也接受自定义文件名的路径
  dts: false,

  // Allow subdirectories as namespace prefix for components.
  // 允许子目录作为组件的命名空间前缀。
  directoryAsNamespace: false,
  
  // 忽略命名空间前缀的子目录路径
  // 当`directoryAsNamespace: true` 时有效
  // Subdirectory paths for ignoring namespace prefixes
  // works when `directoryAsNamespace: true`
  globalNamespaces: [],

  // auto import for directives
  // default: `true` for Vue 3, `false` for Vue 2
  // Babel is needed to do the transformation for Vue 2, it's disabled by default for performance concerns.
  // To install Babel, run: `npm install -D @babel/parser @babel/traverse`
  // 自动导入指令
  // 默认值:Vue 3 的`true`,Vue 2 的`false`
  // 需要 Babel 来为 Vue 2 进行转换,出于性能考虑,它默认处于禁用状态。
  directives: true,

  // filters for transforming targets
  include: [/.vue$/, /.vue?vue/],
  exclude: [/[\/]node_modules[\/]/, /[\/].git[\/]/, /[\/].nuxt[\/]/],
})

2 unplugin-auto-import/vite

自动导入vue3的hooks,借助unplugin-auto-import/vite这个插件

支持vue, vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入

先看效果图

// 引入前
import { ref, computed } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)

//引入后
const count = ref(0)
const doubled = computed(() => count.value * 2)


// 引入前
import { useState } from 'react'
export function Counter() {
  const [count, setCount] = useState(0)
  return <div>{ count }</div>
}

//引入后
export function Counter() {
  const [count, setCount] = useState(0)
  return <div>{ count }</div>
}

安装

npm i -D unplugin-auto-import

Vite配置

// vite.config.js
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: ['vue', 'vue-router', 'vue-i18n', '@vueuse/head', '@vueuse/core'],
      // 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'
      // dts: 'src/auto-import.d.ts'
    })
  ]
})

原理: 安装的时候会自动生成auto-imports.d文件(默认是在根目录)

// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
  const ref: typeof import('vue')['ref']
  const reactive: typeof import('vue')['reactive']
  const computed: typeof import('vue')['computed']
  const createApp: typeof import('vue')['createApp']
  const watch: typeof import('vue')['watch']
  const customRef: typeof import('vue')['customRef']
  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
  .
  .
  .
}
export {}

可以选择auto-import.d.ts生成的位置,使用ts建议设置为src/auto-import.d.ts

其他插件 vue-router, vue-i18n, @vueuse/head, @vueuse/core等自动引入的自动引入请查看文档

// 插件的所有默认配置
AutoImport({
  // targets to transform
  include: [
    /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
    /\.vue$/, /\.vue\?vue/, // .vue
    /\.md$/, // .md  
  ],

  // global imports to register
  imports: [
    // presets
    'vue',
    'vue-router',
    // custom
    {
      '@vueuse/core': [
        // named imports
        'useMouse', // import { useMouse } from '@vueuse/core',
        // alias
        ['useFetch', 'useMyFetch'] // import { useFetch as useMyFetch } from '@vueuse/core',
      ],
      'axios': [
        // default imports
        ['default', 'axios'] // import { default as axios } from 'axios',
      ],
      '[package-name]': [
        '[import-names]',
        // alias
        ['[from]', '[alias]']
      ]
    }
  ],

  // custom resolvers
  // 可以在这自定义自己的东西,比如接口api的引入,工具函数等等
  // see https://github.com/antfu/unplugin-auto-import/pull/23/
  resolvers: [
    /* ... */
  ]
})

3vue-global-api 解决eslint报错

在页面没有引入的情况下,使用unplugin-auto-import/vite来自动引入hooks,在项目中肯定会报错的,这时候需要在eslintrc.js中的extends引入vue-global-api,这个插件是vue3hooks的,其他自己找找,找不到的话可以手动配置一下globals

安装 vue-global-api

npm install vue-global-api -D
// .eslintrc.js
module.exports = {
  extends: [
    'vue-global-api'
  ]
};

它还为细粒度控制提供了相同的集合和单个 API 选项。

// .eslintrc.js
module.exports = {
  extends: [
    // collections
    'vue-global-api/reactivity',
    'vue-global-api/lifecycle',
    'vue-global-api/component',
    // single apis
    'vue-global-api/ref',
    'vue-global-api/toRef',
  ]
};

4 vite-plugin-style-import

当你使用unplugin-vue-components来引入ui库的时候

message, notification 等引入样式不生效 安装vite-plugin-style-import即可

这里以一些流行库为例

// vite.config.js
import { defineConfig } from 'vite'
import styleImport, {
  AndDesignVueResolve,
  VantResolve,
  ElementPlusResolve,
  NutuiResolve,
  AntdResolve
} from 'vite-plugin-style-import'

export default defineConfig({
  plugins: [
    styleImport({
      resolves: [
        AndDesignVueResolve(),
        VantResolve(),
        ElementPlusResolve(),
        NutuiResolve(),
        AntdResolve()
      ],
      // 自定义规则
      libs: [
        {
          libraryName: 'ant-design-vue',
          esModule: true,
          resolveStyle: (name) => {
            return `ant-design-vue/es/${name}/style/index`
          }
        }
      ]
    })
  ],
  // 引用使用less的库要配置一下
  css: {
    preprocessorOptions: {
      less: {
        javascriptEnabled: true
      }
    }
  }
})

5 注意点

1. element-plus默认是英文

方案: 在app.vue加上ElConfigProvider

<template>
  <div id="app">
    <el-config-provider :locale="locale">
      <router-view></router-view>
    </el-config-provider>
  </div>
</template>
<script setup>
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
const locale = zhCn
</script>

日期相关组件设置中文:

<script setup>
// 日历等与dayjs相关的组件,不想显示中文可以不加
// 第一种方法 使用中国时区weekStart默认为1
import 'dayjs/locale/zh-cn'

// 第二种方法 使用 weekStart可配置(只能是0或者1)
import dayjs from 'dayjs'
// 引入英文即为英文
import cn from 'dayjs/locale/zh-cn'
dayjs.locale({
  ...cn,
  weekStart: 1
})


const locale = zhCn
</script>

2. 按需加载不支持指令方式导入,需要手动导入(仅作记录)

这个是我在作者下面提的issue (2021/11/02记录现在已支持指令)

方案: 新建文件 element-plus-directive.js

import { ElLoading, ElMessage } from 'element-plus'
/**
 * 按需导入 Element Plus 组件
 * Vite 插件 https://github.com/antfu/unplugin-vue-components
 * @param app {App}
 */
export default function styleImport(app) {
  const components = [ElLoading, ElMessage]
  components.forEach((v) => {
    app.use(v)
  })
  return app
}


在main.js使用

import elemetPlusDirectives from './utils/element-plus-directive.js'
const app = createApp(App)
elemetPlusDirectives(app).mount('#app')

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: 藤原托漆 原文链接:https://juejin.im/post/7012446423367024676

回到顶部