一、前言
最近在学习 element-ui,试着搭建自己的前端组件库(基于Vue),并发布到 npm。
二、搭建目录结构
-
创建目录 lushuixi-ui 并打开目录
-
npm init,生成一个package.json文件 -
搭建目录结构
- packages 组件包目录
- src 源码入口目录
- scripts 脚本执行目录
- README.md
- package.json
- 在packages目录创建一个button组件
- 创建button目录
- 创建button/src/button.js
- 创建button/index.js
// version 1.0.0
// button/index.js
import Button from './src/button';
/* istanbul ignore next */
// 在Vue.use(Button) 时调用组件上的intall
Button.install = function (Vue) {
// 全局注册组件
// react与vue不同的是, vue组件必须注册(或全局注册,或局部注册)
Vue.component(Button.name, Button);
};
export default Button;
注意:
- 这里因为vue注册组件的时候,定义组件名有两种方式【kebab-case(短横线分隔命名) | PascalCase(首字母大写命名)】
- 注册组件时,当使用 kebab-case 定义一个组件时,引用该组件时也必须使用 kebab-case
- 注册组件时,当使用 PascalCase 定义一个组件时,引用该组件时即可使用 PascalCase 也可使用 kebab-case(尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的)
- 在使用 element-ui 插件时,我们引用组件是通过 ... 形式,便是因为该组件在注册时,使用的是 ElButton 定义的
- 所以,这里修改如下
// version 1.0.1
// button/index.js
import LsxButton from './src/button';
/* istanbul ignore next */
// 在Vue.use(LsxButton) 时调用组件上的intall
LsxButton.install = function (Vue) {
// 全局注册组件
// react与vue不同的是, vue组件必须注册(或全局注册,或局部注册)
// 这里LsxButton.name值是LsxButton
// ./src/button.vue中的scripts标签中export default {name: LsxButton}
Vue.component(LsxButton.name, Button);
};
export default LsxButton;
- 入口文件src/index.js
// version 1.0.0
import Button from '../packages/button';
const components = [
Button,
]
// 全局注册组件
// 在Vue.use(插件)时调用 插件.install
const install = function (Vue, opts = {}) {
components.forEach(component => {
Vue.use(component.name, component);
});
}
export default {
install,
Button,
}
这里需要注意一下
- Vue组件使用之前必须导入且注册,在编写Vue插件时使用全局注册组件(Vue.use(component.name, component))
- 该插件中的组件导入有两种方式,按需导入(Vue.use(Button),会调用Button.install方法以注册组件)和全局导入(Vue.use(插件名),会调用该插件的install以注册所有子组件)
纠正:
// version 1.0.2
import Button from '../packages/button';
const components = [
Button,
]
// 全局注册组件
// 在Vue.use(插件)时调用 插件.install
const install = function (Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component);
});
}
export default {
install,
Button,
}
三、发包到 npm
-
如果没有 npm 账号,先到 npm 上注册一个
-
如果是第一次发布,则
npm addUser输入用户名、密码和邮箱账号 -
如果非第一次发布,则
npm login -
接下来,
npm publish发包,如果package.json注明了"private": true,则不允许发到npm上的,需要将该字段去掉或者改为false -
进入npm官网的packages可以查看发的包
注意:重复发包,如果版本号一致,则会报错的。所以,每次发包需更新版本号
四、使用包
-
vue create hello-wrold, 搭建vue项目,选择vue版本为2.x,并安装依赖 -
使用 npm i 插件名,下载包
-
src/main.js 导入插件
import Vue from 'vue'
import App from './App.vue'
import LushuixiUi from 'lushuixi-ui';
// 全局导入组件
Vue.use(WeizhiUi)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
注意:两种组件导入方式
- 全局导入
- 按需导入
- app.vue 中全局导入插件
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<lsx-button></lsx-button>
</div>
</template>
注意:
- 有如下报错,说是该组件没有被注册或者注册失败
- 这里我使用的是全局导入插件中的所有组件,所以便去查看src/index.js中的install方法,发现组件注册那块的代码有误,应该使用的是Vue.component(组件名,组件本身)而不是Vue.use(组件名,组件本身),写错了,天呐!修改版本为1.0.2
- 这里使用的是全局导入插件中的全部,再使用按需导入插件中的组件
import Vue from 'vue'
import App from './App.vue'
import LushuixiUi from 'lushuixi-ui';
Vue.config.productionTip = false
// Vue.use(LushuixiUi)
Vue.use(LushuixiUi.Button)
new Vue({
render: h => h(App),
}).$mount('#app')
这里有个问题,入口文件 src/index.js 中是通过 export default 暴漏的,暴漏出的只是一个对象,无法通过 import {} from '' 的方式导入,那么 element-ui 为什么可以通过这种方式按需导入(直接通过 import {Button} from 'lushuixi-ui'; Vue.use(Button)这种形式)?
百度了下,发现在使用 element-ui 插件时,实际是调用了 lib 目录下相应的 js 文件,而该目录按 babel-plugin-component 插件要求打包后存放最终代码的目录(lib中是最终打包的目标目录),将webpack配置成多入口,保证最终打包的目录结构符合 babel-plugin-component插件的要求,实现按需加载(该问题参考: segmentfault.com/a/119000001…
五、总结
(1)创建本地组件库; (2)发布到 npm; (3)在项目中引用该包。