前言
在前端开发中,除了常用的UI组件库以外,我们还会涉及到基于公司业务,需要定制化开发一些业务组件,还有随着项目的增多,开发人员的增多,为了提高工作效率,我们就需要统一管理好已开发好的业务组件。这时候我们就需要搭建自己的组件库,因为涉及到一些公司的业务,我们只能发布到私服的npm上。下面几点是我们需要做的几个内容:
1、项目搭建以及UI或者业务组件的开发
2、组件的打包
3、搭建私服npm
4、发布组件至私服npm
5、组件库国际化
6、搭建组件库文档
(注:这里用到的 npm版本6.14.15,node版本v14.18.3)
一、项目搭建以及UI或者业务组件的开发
1、搭建vue2项目
vue create demo-ui
2、项目基本结构
在项目的根目录新建 components 文件夹
3、修改vue.config.js
新增pages,修改入口配置,如下:
//vue.config.js
module.exports = {
pages:{
index:{
entry:'src/main.js',
template:'public/index.html',
filename:'index.html'
}
}
}
4、components文件夹设计
- 建立css文件夹和lib文件夹
- css文件夹用于存放样式文件
这里使用到了sass,所以我们需要先安装好sass
cnpm i sass node-sass@4.14.1 sass-loader@8.x
新建样式表,如下:
- lib文件夹用于存放各个组件,并建立主index.js导出全部组件
// lib/index.js
import Demo from './demo';
import Card from './card';
const components = {
Demo,
Card
}
const install = function(Vue){
if(install.installed) return;
Object.keys(components).forEach(key =>{
Vue.component(components[key].name,components[key])
})
}
const API = {
install
}
export default API;
export {
Demo,
Card
}
View Code
5、组件开发
一个组件是独立的一个文件夹,在components/lib下建立相应文件夹,以card为例:
建立card/src/main.vue和card/index.js两个文件,
card目录如下:
/components/lib/card/main.vue内容如下:
<template>
<div class="m-card" :style="width ? {width: width + 'px'} : {}">
<div class="m-card-img" :style="imgHeight? {height:imgHeight+'px'}:{}">
<img :src="imgSrc" alt="img" />
</div>
<div class="m-card-summary" v-if="summary">
{{summary}}
</div>
<div v-else class="m-card-summary">
<slot></slot>
</div>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
name:'m-card',
props: {
width: { //卡片宽度
type:Number,
default:0
},
imgSrc: { //卡片图片资源
type:String,
default:''
},
imgHeight: { //图片高度
type:Number,
default:0
},
summary: { //卡片概要
type:String,
default:''
},
}
}
</script>
<style>
</style>
View Code
components/lib/card/index.js内容如下:
import Card from './src/main.vue'
Card.install = function(Vue) {
Vue.component(Card.name,Card)
}
export default Card
View Code
main.js中引入
import Vue from 'vue'
import App from './App.vue'
import '../components/css/card.scss'
import Card from '../components/lib/card/index'
Vue.use(Card)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
6、App.vue中使用卡片组件
App.vue内容如下:
<template>
<div id="app">
<m-card
imgSrc="logo.png"
summary="这是一个自定义组件"
>
<template v-slot:footer>
<div class="footer">
<div class="left">哈哈哈哈</div>
<div class="right">嘿嘿嘿嘿</div>
</div>
</template>
</m-card>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<div id="app">
<m-card
imgSrc="logo.png"
summary="这是一个自定义组件"
>
<template v-slot:footer>
<div class="footer">
<div class="left">哈哈哈哈</div>
<div class="right">嘿嘿嘿嘿</div>
</div>
</template>
</m-card>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
View Code
执行npm run serve
启动vue项目,查看组件效果,卡片正常显示:
(注:这里只是展示了card的组件,另一个组件demo组件请自行增加,如果没有内容,不需要导出,请删除,否则会报错)。
二、组件库打包
打包有两种方式
方式一:(webpack、gulp)
这里使用到的是 webpack和gulp
1、根目录下创建webpack.components.js,内容如下:
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const glob = require('glob')
const list = {}
async function makeList(dirPath,list){
const files = glob.sync(`${dirPath}/**/index.js`)
for(let file of files) {
const component = file.split(/[/.]/)[2]
list[component] = `./${file}`
}
}
makeList('components/lib',list)
module.exports = {
entry:list,
mode:'development',
output: {
filename:'[name].umd.js',
path:path.resolve(__dirname,'dist'),
library:'rui',
libraryTarget:'umd'
},
plugins: [
new VueLoaderPlugin()
],
module:{
rules: [
{
test:/\.vue$/,
use: [
{
loader: 'vue-loader'
}
]
},
{test:/\.css$/, use: ['css-loader']},
{test:/\.scss$/, use: ['css-loader','sass-loader',]},
{test:/\.(jpg|png|gif|bmp|jpeg)$/, loader: 'url-loader'},
{test:/\.(ttf|eot|svg|woff|woff2)$/,use: 'url-loader'}
]
}
}
View Code
2、package.json中添加打包命令
"build:js": "webpack --config ./webpack.components.js"
3、执行打包命令,将js打包为umd模块
npm run build:js
执行后如果提示需要安装webpack-cli,yes安装即可。
4、查看js打包结果
index.umd.js提供整个组件库的引入使用;
card.umd.js和demo.umd.js可提供组件库的按需引入。
如果webpack打包js报错如下:
请分别安装 :
npm i vue-loader@15.9.8
npm i vue-template-compiler@2.7.14 (这里的版本必要要跟vue的版本一致)
5、gulp打包css文件
- 根目录新建gulpfile.js
安装相关依赖:
npm install gulp gulp-sass gulp-minify-css
//gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')( require ( 'sass' ) ) //sass转成css
const minifyCSS = require('gulp-minify-css') //压缩
gulp.task('sass',async function(){
return gulp.src('components/css/**/*.scss')
.pipe(sass())
.pipe(minifyCSS())
.pipe(gulp.dest('dist/css'))
})
- package.json添加打包命令
"build:css": "npx gulp sass"
- 执行打包命令,将css打包
npm run build:css
如果打包报错如下:
请先执行 npm uni sass 删除sass。
然后再执行 npm i sass 重新安装sass。
- 查看css打包结果
/dist/css下已生成css文件
- 整合js和css的打包命令
"build": "npm run build:js && npm run build:css"
执行npm run build
,一键打包js和css文件
打包成功如下:
方式二:
这种方式,只需要在package.json中加上如下内容:
"lib": "vue-cli-service build --target lib --name awsui --dest dist ./components/lib/index.js"
注:方式一和方式二在组件的引用方面没有区别,区别在于css的,第一种方式可以按钮引入组件样式,第二种方式只能全局引用组件的样式。
三、搭建私服npm
我们这里使用verdaccio搭建npm私服,发布组件库。verdaccio官方文档
(以下效果是我在本地电脑上安装的,没有在远程服务器上)
1、安装和配置
安装:
npm install -g verdaccio
启动:
verdaccio
这里要注意第一行打印的信息,这个yaml文件就是verdaccio的配置文件,后面我们需要修改该文件进行相关配置。
2、启动成功后,直接在浏览器输入服务器的ip地址 + 最后一行打印出的端口号,看到这样的页面就说明安装成功了。如果访问不了可能是因为服务器防火墙没关,可以检查下防火墙。
3、修改配置文件 config.yaml
用记事本打开config.yaml,修改两个位置:
- 把listen改成自己的域名地址,
- ax_users 设为 -1,禁止注册用户,一般情况下都应该由管理员派发账号,禁用后再添加用户会直接报错
禁用后我们可以通过这个网站 添加账号密码,然后分发给对应的人
把生成的密码复制出来,添加到htpasswd文件中即可
四、发布组件至私服npm
1、package.json文件修改
{
"name": "demo-ui",
"version": "0.1.0",
"private": false,//这里要设置成false
"description": "awsUI自定义组件",
"main": "./dist/index.umd.js",//指定入口文件
"keywords": [ // 关键字,方便搜索
"vue",
"typescript",
"demo-ui",
"demoui",
"element-ui"
],
"author": "zyf",
"files": [ //指定发布的文件目录
"dist",
"components"
],
"scripts": {
"serve": "vue-cli-service serve",
"build": "npm run build:js && npm run build:css",
"lint": "vue-cli-service lint",
"build:js": "webpack --config ./webpack.components.js",
"build:css": "npx gulp sass",
"lib": "vue-cli-service build --target lib --name awsui --dest dist ./components/lib/index.js",
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
"dependencies": {
"core-js": "^3.6.5",
"gulp": "^4.0.2",
"gulp-minify-css": "^1.2.4",
"gulp-sass": "^5.1.0",
"leader-line": "^1.0.7",
"sass": "^1.60.0",
"vue": "^2.6.11",
"vue-router": "^3.5.3",
"vue-server-renderer": "^2.6.14",
"webpack-cli": "^3.1.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.15",
"@vue/cli-plugin-eslint": "~4.5.15",
"@vue/cli-service": "~4.5.15",
"axios": "^0.27.2",
"babel-eslint": "^10.1.0",
"element-theme-chalk": "^2.15.9",
"element-ui": "^2.15.12",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.14.1",
"qs": "^6.11.0",
"sass-loader": "^8.0.2",
"sass-resources-loader": "^2.2.5",
"skeleton-loader": "^2.0.0",
"vue-template-compiler": "^2.6.11",
"vuepress": "^1.9.9",
"vuex": "^3.6.2"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
2、安装nrm并切换npm源到我们私有的仓库地址
这里我使用到了nrm来管理npm registry
npm install -g nrm
// 添加自定义的源 源就是启动verdaccio时打印出来的地址
nrm add demo-ui http://10.0.0.159:8080/
// 查看所有可用的源
nrm ls
// 切换源到我们的私有仓库
nrm use demo-ui
确定已用nrm把源切换到我们的仓库
3、如果没有创建账户的,可以先创建账户
npm adduser --registry http://10.0.0.159:8888/
4、然后发布包
npm publish --registry http://10.0.0.159:8888/
发布成功后,再访问私有仓库地址,就会发现自己的包已经发上去了。
5、具体使用方式
在项目中需要先安装好依赖(记得先用rem切换到私有npm源):
npm i demo-ui
在main.js中,示例如下:
//全局引用
import AwsUI from 'demo-ui';
import 'demo-ui/dist/css/index.css';
Vue.use(AwsUI)
//按需引用
import {Card,Demo} from 'demo-ui';
import 'demo-ui/dist/css/card.css';
Vue.use(Card).use(Demo)
五、组件国际化
在根目录下创建locale文件夹,目录如下:
1、新建多语言文件 locale/lang/zh-CN.js ,其他的语言只要保持key不变,内容做相对应的修改即可。
//zh-CN.js
export default{
card:{
refresh:'刷新'
}
}
2、新建 locale/index.js
import defaultLang from './lang/zh-CN'
let lang = defaultLang
let i18nHandler = function () {
const vuei18n = Object.getPrototypeOf(this).$t
if (typeof vuei18n === 'function') {
return vuei18n.apply(this, arguments)
}
}
// eslint-disable-next-line no-unused-vars
export const t = function (path, options) {
let value = i18nHandler.apply(this, arguments)
if (value !== null && typeof value !== 'undefined') {
return value
}
const array = path.split('.')
let current = lang
for (let i = 0, j = array.length; i < j; i++) {
const property = array[i]
value = current[property]
if (i === j - 1) return value
if (!value) return ''
current = value
}
return ''
}
export const use = function (l) {
lang = l || lang
}
export const i18n = function (fn) {
i18nHandler = fn || i18nHandler
}
export default {use, t, i18n}
3、新建 mixins/index.js
import { t } from '../locale'
export default {
methods: {
t (...args) {
return t.apply(this, args)
}
}
}
4、修改 components/index.js
/* eslint-disable no-debugger */
import Demo from './demo';
import Card from './card';
import locale from '../../locale/index'; //引入多语言
const components = {
Demo,
Card
}
const install = function(Vue,options = {}){
//设置多语言
locale.use(options.locale)
locale.i18n(options.i18n)
if(install.installed) return;
Object.keys(components).forEach(key =>{
Vue.component(components[key].name,components[key])
})
}
const i18n = locale.i18n;
const API = {
install
}
export default API;
export {
Demo,
Card,
locale,
i18n
}
5、在components组件中使用mixins
6、修改package.json ,打包时添加 locale 文件夹
7、打包发布后,在其他项目中使用。在 main.js 中示例如下:
//main.js
import Vue from 'vue'
import demoui from 'demo-ui'
import locale from 'demo-ui/locale/lang/en'
Vue.use(demoui, { locale })
配合 Vue I18n 使用
只要跟着 vue-i18n
的文档把自己的 App 配好就行,不用管组件库,会自动适配。但有一点要注意:需要先将 组件库的语言包合并到 App 语言包中去。比如:
import Locale from 'demo-ui/locale/lang/en'
let appLocale = Object.assign({}, Locale, {
// ...
})
// 接下来该干嘛干嘛
6、搭建组件库文档
这里使用的是 VuePress 来搭建组件库文档
1、安装vuepress(可直接在当前项目上安装)
npm install -D vuepress
2、在根目录上新建 docs 文件夹并创建第一个说明文档
mkdir docs && echo '# Hello VuePress' > docs/README.md
如果在vscode上运行命令报错的话,点击右上角的 + 号,选择Command Prompt ,重新打开终端在运行命令即可。
3、命令运行成功后的目录,在根目录下就可以看到一个docs文件夹
4、修改 README.md 内容
# 快速开始
#### 安装组件库
```bash
npm i aws-ui -S
```
#### 使用组件库
> 在main.js中应用组件库
```javascript
//全部引用
import AwsUI from 'aws-ui';
import 'aws-ui/dist/css/index.css';
Vue.use(AwsUI)
//按需引用
import {Card} from 'aws-ui';
import 'aws-ui/dist/css/card.css';
Vue.use(Card)
```
5、在docs目录下新建 .vuepress 文件夹
6、在 .vuepress 目录下新建 components 文件夹,并把组件放在这个位置里
7、在 .vuepress 目录下新建 public 文件夹,这个文件夹是用来存在静态资源的
8、在 .vuepress 目录下新建 config.js 文件,内容如下:
module.exports = {
title: 'demo-ui',
base:'/demoui/',
themeConfig:{
nav: [
{ text: '首页', link: '/' },
{ text: 'Guide', link: '/guide/' },
{ text: 'External', link: 'https://google.com' },
],
sidebar:[
'/',
'/componentDocs/card'
]
}
}
9、在docs目录下新建 componentDocs 文件夹,并在此目录下创建 card.md 文件
# Card
卡片组件
### 示例
<m-card :imgSrc="$withBase('/logo.png')" summary="这是简介啊"></m-card>
### 代码
```html
<m-card imgSrc="logo.png" summary="这是简介啊"></m-card>
```
docs目录结构如下:
最后执行 npm run docs:dev ,预览文档
预览效果如下: