vite-plugin-components-支持vue2组件库

4,314 阅读4分钟

介绍

之前在vue3+vite中使用部分组件库,支持了antdv等组件库(antd支持vite-plugin-components记录),大多数同学都在使用vue2生态,为了方便vue2生态更好迁移到vite2,这周搞了一下vite2+vue2,将带我启蒙的element-uiiview(view-design)支持vite-plugin-components自动按需加载,为开源社区贡献自己一点微薄的力量,顺便踩踩坑~~

使用vite2+vue2搭建基础项目

准备依赖包

vite 依赖

 "vite-plugin-vue2": "^1.7.2",

vue 依赖

 "@vue/compiler-sfc": "^3.1.4",
 "vue": "2.6.11",
 "vue-template-compiler": "2.6.11",

配置vite.config.js

import { createVuePlugin } from 'vite-plugin-vue2';
import { defineConfig } from 'vite';
export default defineConfig({
 plugins: [
    createVuePlugin()
 ]
})

很简单就配置完成了,下面就可以开始玩耍了

支持Element-UI

缘由

这个是我之前工作中用的最多的组件库,虽然现在不维护了,但依然老当益壮,对他有独特的情怀,即使挂也要让他挂的体面 ~

踩坑之旅

基本没有什么大坑,不得不赞一下作者的优秀设计! 注意的是需要引入基础样式base.css,要不input-number组件的按钮就会没有, 组件库分包还是比较规整的,只需要将组件名成转换为 烤肉串(kababCase) 形式即可, 子组件,比如menu-itemmenu都分别定义成了两个包,打包之后在lib包下也分为两个文件,menumenu-item.js 按需加载无需再关注他们的包含关系,直接导入对应的组件文件即可

     return {
          path: `element-ui/lib/${partialName}`,
          sideEffects: getSideEffects(partialName, options),
     }

所有样式都放在theme-chalk下,引入对应组件样式和基础样式 如下:

if (importStyle === 'sass') {
  return [
    'element-ui/packages/theme-chalk/src/base.scss',
    `element-ui/packages/theme-chalk/src/${partialName}.scss`,
  ]
}
else if (importStyle === 'css') {
  return [
    'element-ui/lib/theme-chalk/base.css',
    `element-ui/lib/theme-chalk/${partialName}.css`,
  ]
}

备注antfu大佬建议合并配置参数,因为之前是分别定义了,importStyle,importCss,importSass三个参数,确实感觉没太大必要,用一个参数importStyle不同的值完全可以满足三种状态开关,这样更易用。

PR:element-ui support

支持View-UI(iView)

缘由

这个是我接触vue2最开始的启蒙的组件库,当时的render函数就是通过这个组件库学会的,感觉他体内流淌着一些antd的血,虽然只用了一周,但是当时它确实显得更精致一些,但是由于后来工作中还是寻求稳定,没有选择它,更新频率有点慢。但是现在作者全职维护后更新快一些了,还改了名字,感觉不如iview好记。支持这个组件库也是因为有种独特的情怀吧~

踩坑之旅

这个坑就比较多了

1. 引入Select等依赖popover.js的组件时候,会报一个错误 require is not defined

解决:查看代码发现select的dropdown中是通过require这种commonjs语法导入popoverjs的 源码是这样写的:

 const Popper = isServer ? function() {} : require('popper.js/dist/umd/popper.js');  // eslint-disable-line

应该是vite默认不支持coomonjs语法导入所以报错,于是我就在vite-awesome中查找相关插件,找到一个插件可以支持coomonjs导入,插件是@originjs/vite-plugin-commonjs,使用方式也很简单,如下:

import { viteCommonjs } from '@originjs/vite-plugin-commonjs';
export default defineConfig({
  plugins: [
    viteCommonjs({}),
  ]
})

至此,这个问题解决了.

2. 引入viteCommonjs之后报vue.runtime.esm.js:619 [Vue warn]: Error in nextTick: "TypeError: Popper is not a constructor"

解决:查询popover相关的issue,解决方式是需要在main函数中import一下,我觉得这样增加了用户的负担,于是直接在副作用sideEffects中引入这个库 至此这个问题解决。

3. table依赖的'element-resize-detector',date-picker组件依赖js-calendar也需要通过副作用的方式引入

因为这俩依赖库也采用的commonJS的module.export写法,es6的import引入不进来

wiki: commonjs和es6模块化的使用

4. select下拉如果通过slot传入option,会报如下的错误

vue.runtime.esm.js:619 [Vue warn]: Error in getter for watcher "dropVisible": "TypeError: Cannot read property 'match' of undefined"

解决: 通过查看源代码,发现在select中有个匹配option还是optionGroup的正则,是用opts.tag.match的方式进行判断的,此时如果tagundefined则会报上面的错误 image.png tag的作用 官网描述如下:

Xnip2021-07-19_17-14-52.jpg

select源码

更改如下:

 if (opts && optionRegexp.test(opts.tag)) return [node];

经过测试并不影响原有功能,兼容undefined情况。

view-ui PR: github.com/view-design…

5. view-ui下拉框选中,值不回显的问题(暂未解决)

解: 经过在源码中打log,发现当点击option的时候触发了两遍,第一遍正常调用将选中的选项传过去,第二遍值变成undefined,暂时没有查清楚是哪里导致的重复调用,在vue-cli中是正常的

6. scroll组件无法正常解析,vue uses lang html for template, however it is not installed.(暂未解决,不清楚设计目的,可手动解决)

解:这个问题很明显,是vite无法解析模板语法,因为scroll/loading-component这个组件用了一个模板语法是<template lang="html"> view-ui 使用webpack相关的loader(html-loader)进行解析,但是vite暂时还没有类似的loader所以无法解析,我尝试将lang=”html“去掉发现就正常了,暂时不知为什么设计成这样,这个组件内部就是普通的vue语法,并没有什么特别的。

7. list下的子组件(list-item,list-item-meta)需要特别处理,都放在list目录下,否则找不到

至此组件库迁移,绝大多数没有问题了,把官网文档的demo都跑了一遍

核心代码:

export const ViewUiResolver = (): ComponentResolver => (name: string) => {
  if (name.match(/^I[A-Z]/)) {
    const compName = name.slice(1)
    return {
      path: `view-design/src/components/${getCompDir(compName)}`,
      sideEffects: getSideEffects(compName),
    }
  }
}
const getSideEffects: (
  compName: string,
) => string[] = (compName) => {
  const sideEffects = [
    'view-design/dist/styles/iview.css',
    'popper.js/dist/umd/popper.js',
  ]

  if (/^Table/.test(compName))
    sideEffects.push('element-resize-detector')

  if (/^Date/.test(compName))
    sideEffects.push('js-calendar')

  return sideEffects
}

PR: view-ui support

迁移Vuesax(alpha版本)

缘由

主要就是因为好看,这个组件库现在从版本3升级到了4,但是依然是只支持vue2,特效很炫,组件不是很多,搞他的目的就是因为他好看,没有别的原因,哈哈,不过路途也挺艰辛。

踩坑之旅

按需加载可以加载源码或者直接加载dist目录

1. 加载源码需要在项目安装 vue-class-component,vue-property-decorator,sass,否则报错

因为源码都是采用ts decorator的形式写的,vue2时代写ts一般都采用这种,安装上面依赖以便解析对应的class语法和装饰器语法,这种语法看上去很不好看,代码量还多

2. 匹配组件目录

  • 源码:如果引入的是源码则需要匹配到真实的组件目录,比如VsSidebarGroup的真实目录是vsSidebar/Group, 源码中并没有单独为子组件创建一个包
  • 编译代码:但是如果引入编译之后的文件就不必匹配了,编译之后dist目录会单独创建一个VsSidebarGroup的目录,里面有index.jsstyle.css,组件目录的首字母为小写,转换对了即可。

3. 引入layout子组件row,col的路径问题

  • 源码:layout下的组件是放到了与components同级目录,所以匹配的时候需要到上一级查找,可以正常引入
  • 编译代码:dist目录并没有打出layout的包,导致这俩layout相关的子组件无法引入,但是全量包中存在

核心代码:

    return {
      path: getPath(name, options),
      sideEffects: [
        'vuesax/dist/vuesax.css'],
    }
  if (importSass) {
    const dir = getCompDir(compName)
    return `vuesax/src/components/${dir}`
  }
  else {
    const dir = `${compName[0].toLowerCase()}${compName.slice(1)}`
    return `vuesax/dist/${dir}`
  }

暂时没有提交PR,这个组件库V4处于alpha阶段,组件不太完善,改动可能还会很大,等稍微稳定一些再说

结语

经过周末的几天研究,感觉还是很有收获的,起码用vite可以跑vue2的受众很广的组件库,不用再一遍遍写无用的注册代码,确实更爽了,其实这个插件还是有一些问题的,比如tsx/jsx的组件无法按需加载,此时就需要在单独引入别的按需插件,这个插件就失去了意义,对于template开发者还是很友好的。 总的来说,一个周末迁移了这三个组件库到vite生态,达到可用的状态,感觉还是挺爽的,能为开源社区贡献一份微薄之力,心满意足了~