建立了自己常用的组件,并将其推到自己的组件库中,大大提高开发效率。最近看了很多自己创建组件库并推到npm的教程,但是都不怎么适合自己,他们的文章中都没有提及到我遇到的一些坑,可能我们遇到的问题不同,我将我的操作分享一下。
如何编写单个的组件我这里就不介绍了,我直接从单个组件如何打包成组件库开始说说:(仿照着element-ui做的)
1.做一个组件库:假设编写的单个组件是在demo1文件夹,此时我们需要再创建一个vue文件夹,执行命令 vue create demo2 (创建单个组件时的选择了sass等,创建demo2时也需要选择)。
2.在vscode打开demo2 , 在根目录新建文件夹 packages , 用于存放封装的所有组件,并将src文件夹改成了examples(不要疑问为什么,仿照了element) , 用于测试我们封装的组件(如果不用测试可以直接删除src文件夹,下面介绍的是需要测试的情况)。
3.src文件夹改了后,npm run serve 无法启动文件,此时更改入口文件即可,找到vue.config.js文件夹(没有在根目录创建),更改里面的配置,代码如下:
const path= require ('path')
module.exports={
pages:{
index:{
//修改项目的入口文件为examples
entry:'examples/main.js',
template:'public/index.html',
filename:'index.html'
}
},
//扩展webpack 配置,使packges加入编译,最终需要打包的文件packges ,注意chainWebpack 的大小写。
chainWebpack:config=>{
config.module
.rule('js')
.include.add(path.resolve(__dirname,'packages')).end()
.use('babel')
.loader('babel-loader')
.tap(options=>{
return options
})
},
}
此时执行命令:npm run serve 即可。
4.将自己封装的所有组件复制到packges文件夹中,字体图标(封装租件字体图标时使用方法在文章末尾)也要复制粘贴进来,如图:
5.在packages文件夹中创建index.js ,这是整个包的入口文件:里面的配置:
//整个包的入口文件
//如果导出一个对象 对象就是install,如果导出函数,函数就是install方法
//参考vue的官网上Vue.use() 中install的使用
// export default {
// install
// }
//法二:
import button from './MyButton.vue'
//不要忘记引入字体图标
import './font_3424295_9ml5vax0v5v/iconfont.css'
const components=[
button
]
const install = function(Vue){
//全局注册所有的组件
console.log(123);
components.forEach(item => {
Vue.component(item.name,item)
});
}
//判断是否直接全局引入文件,如果是就不用调用Vue.use(),看官网
if(typeof window !== 'undefined'&& window.Vue){
install(window.Vue)
}
export default {install}
6.在examples文件中测试: 在main.js中引入自己的插件 ,然后直接使用就可以
//引入自己的插件
import myui from '../packages/index'
Vue.use(myui)
7.测试没问题对packages打包,vue cli中里面有一个构建目标,构建成一个库,所以在demo2文件的package.json 文件中配置命令 + 打包的文件: "lib":"vue-cli-service build --target lib packages/index.js" :
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"lib":"vue-cli-service build --target lib packages/index.js"
},
- 打包之前最好先配置一下(不然后面通过命令安装使用时可能把文件名弄错),为推npm做准备:
{
"name": "bancnmy-ui",
"version": "0.1.0",
"private": false,
"main": "dist/bancnmy-ui.umd.min.js",
"author": {
"name": "半城樱花雨"
},
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"lib":"vue-cli-service build --target lib packages/index.js"
},
}
"name": "bancnmy-ui",表示npm包的名字,独一无二的,"private": false, ,必须不是私有的,"main": "dist/bancnmy-ui.umd.min.js", npm包的入口文件。
然后执行打包命令:npm run lib ,此时如果有报错:error Mixed spaces and tabs no-mixed-spaces-and-tabs ,那就在 .eslintrc.js 文件夹中的 rules 中,手动添加’no-mixed-spaces-and-tabs’,然后定义为0,关闭规则.
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-mixed-spaces-and-tabs':0
}
打包完成后生产dist文件:
9.将使用笔记复制一份在 README.md 文件夹中,
10.可以将自己的代码推到GitHub上去。
11.重点来了,发布到 npm 上去,
-
除了上面必须配置的:
"name": "bancnmy-ui",表示npm包的名字,独一无二的,"private": false,,必须不是私有的,"main": "dist/bancnmy-ui.umd.min.js",npm包的入口文件。以外还可以:"keywords": [ "ui", "组件库" ], "author": "半城樱花雨", 等等; -
在根目录创建文件
.npmignore,如同gitignore(里面配置的都是一些忽略的文件),配置:
# 忽略以下东西不被npm上传,所有文件都不要,只要dist文件
examples/
packages/
public/
vue.config.js
babel.config.js
*.map
-
npm上传:
1.如果使用
nrm命令的得保证源是npm的源(这里不讲)。2.我是用的 npm (前提必须得有 npm 账号密码) : A.执行命令:
npm login回车 => 输入账号 +回车 => 输入密码(密码是不可见的)+ 回车 => 邮箱 +回车;B.执行命令
npm publish(删除已上传的包: npm unpublish 包名 -force ;如下:npm unpublish chenmy-ui -force)注意发包时遇到的坑: 这个人总结的不错 ,补充一点:
① npm unpublish 命令只能删除 72 小时以内发布的包
② npm unpublish 删除的包,在 24 小时内不允许重复发布(但是可以换 npm包 的名字继续发,哈哈)
③ 发布包的时候要慎重,尽量不要往npm 上发布没有意义的包!
上传npm包成功:
如果后期自己又更改完善之前的组件后,要更改版本 packages.json 中 "version": "0.1.0",
12.使用自己发布的包 :
下载执行命令:npm install bancnmy-ui -s ,
main.js中全局引入: (注意样式的引入路径,此处容易错)
//引入npm包和样式
import myui from 'bancnmy-ui'
import 'bancnmy-ui/dist/bancnmy-ui.css'
Vue.use(myui)
13.这里讲讲字体图标在封装组件时的使用情况:
- 阿里巴巴矢量图下载字体图标,放到静态文件中:
- 封装组件中:
<!-- icon 传过来的值是什么就显示该字体图标 -->
<!-- v-if="icon" 表示有了icon 才会显示图标 -->
<i class="iconfont" :class="icon" v-if="icon"></i>
- 使用组件中,这里是关键:icon="icon-shanchu",icon的值是从iconfont.css文件中而来
<div class="row">
<!-- icon的值是从iconfont.css 而来 icon="icon-shanchu"-->
<my-button circle type='primary' icon="icon-shanchu"></my-button>
<my-button circle type='success' icon="icon-duigou"></my-button>
<my-button circle type='info' icon="icon-youjian"></my-button>
<my-button circle type='danger' icon="icon-star"></my-button>
</div>
- iconfont.css 文件:
@font-face {
font-family: "iconfont"; /* Project id 3424295 */
src: url('iconfont.woff2?t=1653391255245') format('woff2'),
url('iconfont.woff?t=1653391255245') format('woff'),
url('iconfont.ttf?t=1653391255245') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-yanjing:before {
content: "\e8c7";
}
.icon-cancel-test:before {
content: "\e61b";
}
.icon-shanchu:before {
content: "\e8c1";
}
.icon-duigou:before {
content: "\ebe6";
}
.icon-youjian:before {
content: "\eb44";
}
.icon-star:before {
content: "\e60b";
}