仿ElementUI构建自己的Vue组件库用babel-plugin-component按需加载组件及自定义SASS主题
最近使用ElementUI做项目的时候用Babel的插件babel-plugin-component做按需加载,使得组件打包的JS和CSS包体积大大缩小,加载速度也大大提升,所有想模仿做一个组件库也来做下按需加载。
首先用Vue CLI 3.0新建一个项目
vue create bes-ui
注意的是cli3的脚手架用的Babel7的配置,只有babel.config.js文件,所以要自己添加.babelrc文件。
项目结构
新建项目之后,可以按照自己的想法建文件结构,也可以按照babel-plugin-component官方文档的目录构建:
上面有两种方式,前一种是组件单一主题方式,后一种是主题库的方式,大家可以自己选择,下图是bes-ui的目录结构:
这里大概介绍下文件用途:
-dist:组件库测试项目打包文件
-examples:组件库的测试项目
-lib:组件库的源码
-local:组件库的国际化文件
-package:组件库打包后的压缩的js,css文件
-static:组件库的静态资源(css主题)
其他文件就不介绍了,都是脚手架生成的文件
组件介绍
这里组件库写了两个样例:component1,component2 。 每个组件都添加了自己的初始化install方法(用于按需加载时候独立使用),install方面里面加个日志,方便后面看看组件加载记录。
最外面添加整体加载用的index.js,用于一次性加载所有项目
最后就是组件的样式文件了(这里的base.css和index.css都是必须的,官方的api有有标注):
大家注意的一点是组件包名一定要叫 “ lib ” ,样式文件的路径和名字大家可以随意,到时候在配置文件里面引用对应的路径就行,我这里叫static,里面一定要加 base.css和index.css,这都是babel-plugin-component的API里面标注了,当然大家也可以看babel-plugin-component的源码core.js【位置在node_modules/babel-plugin-component/lib/core.js】里面有涉及到获取对应文件:
if (styleLibrary && _typeof(styleLibrary) === 'object') {//这个是样式的一些配置 styleLibraryName = styleLibrary.name; isBaseStyle = styleLibrary.base; modulePathTpl = styleLibrary.path; mixin = styleLibrary.mixin; styleRoot = styleLibrary.root; } if (styleLibraryName) {//是否在.babelrc配置了styleLibraryName if (!cachePath[libraryName]) {//是否存在配置好的样式获取路径 var themeName = styleLibraryName.replace(/^~/, ''); cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?//路径是否相对于element-ui/lib resolve(process.cwd(), themeName) : "".concat(libraryName, "/").concat(libDir, "/").concat(themeName); }//如果是相对于lib 组合路径---element-ui/lib/theme-chalk/ 这个目录下是75个css文件 //这里将这一段路径保存在了cachePath[libraryName] 后续会用到 if (libraryObjs[methodName]) {//作者也没搞清楚这里是什么 不过没关系,事实证明这里走了false /* istanbul ingore next */ if (cache[libraryName] === 2) { throw Error('[babel-plugin-component] If you are using both' + 'on-demand and importing all, make sure to invoke the' + ' importing all first.'); } if (styleRoot) {//这里默认是没有配置的 所有走false path = "".concat(cachePath[libraryName]).concat(styleRoot).concat(ext); } else { path = "".concat(cachePath[libraryName]).concat(_root || '/index').concat(ext); }//这里会默认先加载index.css 因为ext没设置就会默认css cache[libraryName] = 1; } else {//走了else if (cache[libraryName] !== 1) {//这里肯定是不等于1,因为上面一行才会赋值1 /* if set styleLibrary.path(format: [module]/module.css) */ var parsedMethodName = parseName(methodName, camel2Dash); if (modulePathTpl) { var modulePath = modulePathTpl.replace(/\[module]/ig, parsedMethodName); path = "".concat(cachePath[libraryName], "/").concat(modulePath); } else {//这里走了else 也就是样式路径后续为模块名.[ext] path = "".concat(cachePath[libraryName], "/").concat(parsedMethodName).concat(ext); }//所有这里的路径就是element-ui/lib/ if (mixin && !isExist(path)) { path = style === true ? "".concat(_path, "/style").concat(ext) : "".concat(_path, "/").concat(style); } if (isBaseStyle) { addSideEffect(file.path, "".concat(cachePath[libraryName], "/base").concat(ext)); } cache[libraryName] = 2; } } addDefault(file.path, path, { nameHint: methodName }); } else { if (style === true) { addSideEffect(file.path, "".concat(path, "/style").concat(ext)); } else if (style) { addSideEffect(file.path, "".concat(path, "/").concat(style)); } } }
转回正题,文件创建好了之后,就可以发包到npm了,这里提供了两种方式:1是将组件库打包压缩成css和js,暴露出去(这种方式无法做按需,因为所以代码压缩在一起了);2是将lib下的index暴露出去(这种方式可以做按需加载);如下(package文件):
组件使用
组件放上去后,就可以在项目里面使用了,这里用vue create添加了一个example项目:
项目加载bes-ui:
项目使用bes-ui(这里只加载了component2):
启动项目后,观察加载的项目日志:
这里日志打印的只加载了component2,如果还不放心的话可以看下style标签是不是只有component2的css:
这里确实只有component2的样式,这里有个问题就是样式加载了两遍 这里主要是组件内部加载了一次样式,babel-plugin-component的按需又加载了一次,这里主要是为了测试两种不同方式,(组件内的加载样式是给压缩js和css用的)如果做按需的话就可以去掉了:
这里贴下Babel的配置:
总结
最后可以打个测试项目包,看下里面确实没有其他组件的代码和样式,这里就不贴图了,大家可以自己尝试,总结下这里的bes-ui其实就是模仿ElementUI的一个简易的组件库(虽然目前只加了按需加载,后续可以把国际化和主题加上),项目里面的一些配置和文件都大同小异,如果有兴趣构建自己的vue组件库的时候,bes-ui是个不错的模版。
GitHub项目地址:https://github.com/BothEyes1993/bes-ui
- GearCase UI - 自己构建一套基于 Vue 的简易开源组件库
- 基于vue的Element-ui定义自己的select组件
- Vue整合Element-UI的分页组件实现分页
- 在vue项目中使用element-ui的Upload上传组件
- sencha touch 扩展篇之使用sass自定义主题样式 (下)通过css修改官方组件样式以及自定义图标
- vue2.0 使用element-ui里的upload组件实现多图上传。采用FORMDATA的方式上传。
- vue+axios+element ui 实现全局loading加载示例
- 基于vue2.0前端组件库element中 el-form表单 自定义验证填坑
- Vue.js(十) element-ui 组件库
- vue-cli3.0+element-ui上传组件el-upload的使用
- vue elementUI table表格数据 滚动懒加载的实现方法
- vue 基于element-ui 分页组件封装的实例代码
- vue项目搭建配置sass、element-ui、vux、axios、服务器代理
- vue + element-ui 制作tab切换(切换vue组件,踩坑总结)
- element-ui+vuex共享自定义方法进行表单验证 validator
- vue2.0 使用element-ui里的upload组件实现图片预览效果
- 【vue 组件 mint-ui】 看了一下源码,给轮播图Swiper封装自定义跳转的函数
- vuejs 无node单页应用方案二(babel-standalone or traceur,vue-router实现、组件按需懒加载)
- element-ui 以服务的方式自定义Loading加载效果
- vue+element-ui的主题颜色切换