之前只是简单的了解了组件开发的过程,今天在本地自己实现了一个。现在记录一下过程。以下过程中使用vue-cli3
创建项目
创建项目的过程中去掉eslint。保留babelrc
vue create elBtn // elBtn是我的插件名称
修改对应的配置
src中的配置
新建packages文件夹,对应创建button.vue和index.js
button.vue对应的组件的内容
<template>
<div>
我是一个button
</div>
</template>
<script>
export default {
name: 'el-btn',
}
</script>
<style>
</style>
index.js中的配置
import elBtn from './button'
let components = {elBtn}
const install = function(Vue){
for(let key in components){
Vue.component(components[key].name,components[key])
}
}
// 判断是否直接引入文件,如果是,就不用vue.use
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
// 导出install方法
export default {
install
}
vue.config.js中的配置
const path = require('path')
module.exports = {
pages: {
index: {
// 修改项目入口文件
entry: 'src/packages/index.js',
template: 'public/index.html',
filename: 'index.html'
}
},
// 扩展webpack配置,使webpages加入编译
chainWebpack: config => {
config.module
.rule('js')
.include.add(path.resolve(__dirname, 'packages')).end()
.use('babel')
.loader('babel-loader')
.tap(options => {
return options
})
}
}
package.json中的配置
{
"name": "tst",
"version": "0.1.0",
"private": false,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lib": "vue-cli-service build --target lib src/packages/index.js"
},
"dependencies": {
"core-js": "^3.10.1",
"vue": "^2.6.12"
},
// 配置import引入时的路径,若果没有引入,会导致import的时候没有内容,同样在下面本地测试也会有问题-----问题看下面本地测试部分
"main": "dist/tst.umd.js",
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.12",
"@vue/cli-service": "^4.5.12",
"vue-template-compiler": "^2.6.12"
},
// 指定打包后发布到npm的文件名,没指定则不传,package.json是默认上传的
"files": [
"dist",
"src/packages"
],
"author":{
"name":"",
"CSDN":"",
"github":""
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
本地测试
编译
elBtn目录下执行npm run lib的命令,可以编译对应的dist文件。
tgz包
elBtn目录下执行npm pack的命令,生成对应的tgz包
在其他项目中测试
在测试项目中执行npm install ../elBtn/elBtn-0.1.0.tgz 可以安装elBtn下的内容。和使用npm install 远端的仓库是一个意思,../elBtn/elBtn-0.1.0.tgz是我本地tag所在的目录。其实通过研究发现当我们使用npm install远端的组件时候,也是通过将压缩包下载到.npm文件下然后解压到node-modules的目录下。参考阮一峰老师的文章
然后执行import elBtn from 'elBtn' Vue.use(elBtn)就可以使用组件啦。
可能存在的问题
可能在use的时候出现下面的问题,经过我几个小时的研究发现,在button.vue中export的时候忘记写上name的属性,或者name的属性是空,就会有下面的问题。
Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
发布到npm仓库
1.npm官网注册自己的账号名和密码
2.npm adduser 使用你的账号和密码邮箱登录、这里npm依赖下载的地址要使用npm官方地址,其他地址会导致登录不成功
3.npm publish 发布,同样npm unpublish 就会对应删除包
4.npm install 就会安装上对应的包
在解决上面可能存在问的问题的时候,深入思考了下install的相关原理
- 在import对应封装的组件时候,其实返回的是下面的对象
- import当前测试项目的注册组件
// button.js
import TopBtn from './button'
TopBtn.install = function (Vue) {
Vue.component('TopBtn', TopBtn)
}
export default TopBtn
// main.js中引入
import TopBtn from './components/index.js'
Vue.use(TopBtn)
main.js中的topBtn的返回结果
vue.use的时候,会去找到install方法,将其中的内容注入到vue实例上。
- use的源码
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
// 判断当前的plugin是否注册,已经注册直接返回
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// 没有注册的进行plugin的install
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}