前言
说到组件库的封装,通常我们是为了团队统一解决方案,例如将(文件上传、表单、表格)的实现统一、标准化,提升开发效率和项目的可维护性。
但是!!! 这里我要说但是,搭建一个组件库真的一定能给你的团队带来项目开发上的正向推进吗?答案当然不是绝对的,我们可不要为了造轮子而造轮子。
使用组件库通常会出现几个问题:
- 能否保证封装组件的技术成熟度,组件出现问题或者不好用,开发同事可是要背后骂娘的!
- 当发现bug时,用到组件的系统都存在这个问题,怎么去维护修复?
- 封装的组件对业务的覆盖程度、某种业务场景是否形成了产品标准?
- 组件库的初衷是为了提升效率而不是要开发人员徒增使用成本,或者写一堆兼容代码!
- 组件库的维护工作是庞大的,团队是否具备充足的人力资源来进行维护?
- 跟组件有无关的问题,同事都会直接找到你,你做好准备了吗?
当然,如果你的回答是“上面的问题咱都知道。多虑了”,或者有具体的应对方案了。ok,那咱们就开始吧。
使用pnpm
npm i pnpm@6.23.4 -g
搭建组件库
拉取vue cli工程,删除多余文件夹,创建package目录定义组件库
- ui
- example -----------------组件测试(可选)
- packages ----------------组件库
- button --------------组件定义
- button.vue
- index.js---------单个组件注册
- components.js -----组件统一导出
- index.js -------------组件库入口文件
- button --------------组件定义
- ui/packages文件夹下创建组件目录(以button为例),包含以下文件
//button.vue ->vue组件(注意必须定义组件name,用于项目中引入使用)
<template>
<div class="">
<a-button type="primary" @click="emitClick">
按钮
</a-button>
</div>
</template>
<script>
export default {
name: 'JfButton',//注意,必须定义组件名
data() {
return {}
},
methods: {
emitClick() {
this.$emit('click')
}
}
}
</script>
<style scoped lang="less"></style>
//index.js ->在install方法中注册组件并导出
import Button from './button.vue'
Button.install = (app) => {
app.component(Button.name, Button)
return app
}
export default Button
- packages/components.js统一导出
export { default as Button } from './button'
export { default as Modal } from './modal'
export { default as Pagination } from './pagination'
- packages/index.js定义全局install方法,将所有组件注册到vue
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import * as components from './components'
export * from './components' //项目中可按需引入
function install(app) {
if (process.env.NODE_ENV === 'development') {
app.use(Antd)
}
for (const component in components) {
// @ts-expect-error
const Comp = components[component]
if (Comp.install) { app.use(Comp) }
}
return app
}
export default install
组件库编译配置
//vue.config.js
const path = require('path')
module.exports = {
pages: {
index: {
// 修改项目入口文件
entry: 'examples/main.js',
template: 'public/index.html',
filename: 'index.html'
}
},
// 扩展webpack配置,使packages加入编译
chainWebpack: config => {
config.module
.rule('js')
.include.add(path.resolve(__dirname, 'packages')).end()
.use('babel')
.loader('babel-loader')
.tap(options => {
return options
})
}
}
package.json定义打包引用组件库文件配置及打包指令指令lib
"name": "@jf/vue-cpns-lib",
"version": "0.0.3",
"main": "dist/vue-cpns-lib.umd.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lib": "vue-cli-service build --target lib packages/index.js",
},
执行打包指令
npm run lib
搭建组件库文档站点
在ui文件夹同层级创建docs文件夹
安装vuepress@1.9.8
npm i vuepress@1.9.8 -D
项目结构如下
- docs
- .vuepress ------------ 插件相关
- configs ---------- 存放站点导航模块
- navbar
- sidebar
- dist -------------- 站点打包文件
- styles
- palette.styl-- 样式覆盖
- config.js --------- 配置文件
- enhanceApp.js -- 入口文件(同main.js)
- configs ---------- 存放站点导航模块
- components --------- 组件对应文档
- guide ----------------- 指南(可选)
- README.md --------- 文档站点入口,对应路由'/''
- .vuepress ------------ 插件相关
配置文件config,js说明(vuepress v1.x)
const path = require('path')
module.exports = {
title: "jf-vue-cpn-lib",
base: "/",
plugins: ["demo-container"],
lang: "zh-CN",
theme: "reco",//引用主题插件,先安装vuepress-theme-reco
themeConfig: {
// 顶部导航栏
nav: [
{
text: '组件',
link: '/components/modal/',
},
{
text: "指南",
ariaLabel: 'Language Menu',
items: [
{
text: '如何使用',
link: '/guide/howToUse/'
},
{
text: "搭建与维护",
link: "/guide/maintain/",
},
]
},
],
sidebar: [
{
path: "/components/modal/", //分组默认地址
title: "模态框", //分组标题
sidebarDepth: 1,//作用在项内部的层级,优先级比外部的更高
},
{
path: "/components/pagination/", //分组默认地址
title: "分页", //分组标题
sidebarDepth: 1,//作用在项内部的层级,优先级比外部的更高
},
],
},
//解决组件库code-js鱼vuepress所依赖的core-js包版本不兼容报错
//报错示例:Cannot find module 'core-js/library/fn/xxx/xxx'
chainWebpack: config => {
config.resolve.alias.set('core-js/library/fn', 'core-js/features')
},
configureWebpack: {
resolve: {
alias: {
'@ui': path.resolve(__dirname, '../../ui'),
}
}
}
}
入口文件enhanceApp.js(vuepress v1.x)
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/antd.css'
import jfCpn from '@ui/dist/vue-cpns-lib.umd.min'
import '@ui/dist/vue-cpns-lib.css'
export default ({
Vue
}) => {
Vue.use(Antd).use(jfCpn)
}
组件文档中生成demo及代码示例
npm i vuepress-plugin-demo-container
组件的markdown文件中按以下语法编写vue
::: demo
``` vue
<template>
<jf-pagination :total="21" style="display:flex;justify-content:space-between;" @onChange="onChange" ref="gloPagination" @onSizeChange="sizeChange"></jf-pagination>
</template>
<script>
export default {
name: "homechild",
components: {},
data() {
return {
testVisible: false,
testTitle: "标题"
};
},
computed: {},
mounted() {},
methods:{
sizeChange(current, size) {
this.param.pageSize = size;
this.param.current = current;
this.getList();
},
onChange(page){
console.log(page)
}
}
};
</script>
<style scoped lang="less"></style>
在 markdown 中使用 vue可参考vuepress.vuejs.org/zh/guide/us…
部分问题可参考zhuanlan.zhihu.com/p/360516838
搭建私有npm
安装verdaccio
npm install -g verdaccio
安装完后执行
verdaccio
通过控制台地址访问验证是否启动成功
如果其他电脑无法通过ip访问到verdaccio服务,检查config.yanl文件,末尾添加
listen: 0.0.0.0:4873
切换npm源
//安装nrm
npm install -g nrm
//查看源地址
nrm ls
//添加新的源地址
nrm add jfnpm http://10.10.0.53:4873
//切换源
nrm use jfnpm
//如需新用户注册
npm addUser
发布
//切换到发布文件目录下
//定义当前发布版本,不可与已有版本重合
npm version x.x.x
//发布
npm publish
//删除npm某个库
npm unpublish xxx --force
使用pm2启动verdaccio(进程监听,不会因终端停掉导致服务关闭)
npm i -g pm2
pm2 start verdaccio
pm2启动verdaccio失败
前端组件库使用说明
环境
node: 14.17.0+
vue: 2.6.11
ant-design-vue: 1.6.3
安装
首先确保切换到内部npm源
- 切换npm源
//安装nrm
npm install -g nrm
//查看源地址
nrm ls
//添加新的源地址
nrm add jfnpm http://10.10.0.53:4873
//切换源
nrm use jfnpm
//如需新用户注册
npm addUser
npm i @jf/vue-cpns-lib
使用组件
全局引入
//main.js
import UIDesign from '@jf/vue-cpns-lib'
import '@jf/vue-cpns-lib/dist/vue-cpns-lib.css'
Vue.use(UIDesign)
//home.vue
<jf-button @click="globalVisible = true">组件内引入</jf-button>
按需引入
//main.js
import '@jf/vue-cpns-lib/dist/vue-cpns-lib.css'
//home.vue
import { Button, Modal } from '@jf/vue-cpns-lib'
components: { Button, Modal },