前言
使用Vue框架做前端开发,组件封装是一个很常规的操作。随着时间的积累,组件也会越来越多,配合vuepress可以解决组件文档的统一化,但依然解决不了组件的跨项目复用问题。一个公司中不可能只基于一个框架或项目开发,不同的业务或模块会另起项目,这时,如果是把项目的复用组件通过复制的方式引入另一项目,就显得麻烦,而且如果组件升级或修复bug,不能实时同步。 如何解决组件的跨项目复用,是每个团队都会面临的问题。就常见的就是把组件上传到npm仓库,这样不同的项目需要时直接从npm仓库中安装使用,如果组件升级或修复问题,其他项目同步更新就可以。如果不想公开,可以部署本地私有仓库,实现团队内共享。
前端组件发布到npm仓库,配合vuepress组件文档,可以解决前端组件的跨项目复用,提高前端效能
一、环境准备
1. 创建组件目录
使用vue cli 创建一个新项目,这里不做详细介绍,可参考Vue CLI
项目目录!如下:
2. 创建package组件
package目录添加视图my-card组件index.vue,并创建index.js负责对外提供install方法,
index.vue代码示例:
<template>
<div
class="m-card"
:style="
width
? {
width: width + 'px',
}
: {}
"
>
<div class="m-card-img">
<img
:src="imgSrc"
:style="
imgHeight
? {
height: imgHeight + 'px',
}
: {}
"
/>
</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: "MyCard",
props: {
width: {
//卡片宽度
type: Number,
default: 500,
},
imgSrc: {
//卡片图片资源
type: String,
default: "",
},
imgHeight: {
//图片高度
type: Number,
default: 100,
},
summary: {
//卡片概要
type: String,
default: "哈哈哈哈哈",
},
},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.m-card {
margin: auto;
}
</style>
index.js
import MyCard from './index.vue';
// 给组件定义install方法
MyCard.install = Vue => {
Vue.component(MyCard.name, MyCard)
}
export default MyCard;
3. install方法
Vue.js 的插件应该暴露一个 install方法。这个方法的第一个参数是Vue 构造器,第二个参数是一个可选的选项对象。这里Vue官方对Vue插件的规范要求。
我们的组件想要被Vue.use引入,就必需提供install方法。
在package主目录下增加index.js
import MyCard from './my-card';
import MySelect from './my-select';
const components = [
MyCard,
MySelect
]
const install = function (Vue) {
if (install.installed) return;
console.log("components", components)
components.forEach(component => {
Vue.component(component.name, component)
});
// Object.keys(components).forEach(key => {
// Vue.component(components[key].name, components[key])
// })
console.log("components", components)
}
export default {
// 所有的组件必须有一个install的方法,才能通过Vue.use()进行按需注册
install,
...components,
}
到此,组件的准备工作已经完成,本地验证一下效果
直接在App.vue中引入组件即可
App.vue代码如下:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
<MyCard :summary="summary" :imgSrc="img">
<div slot="footer">
<el-button>小测试</el-button>
</div>
</MyCard>
</div>
<router-view />
</div>
</template>
<script>
import { MyCard, MySelect } from "./package/index.js";
export default {
components: {
MyCard,
MySelect,
},
data() {
return {
summary: "这是一个卡片小案例",
img: require("@/assets/logo.png"),
};
},
};
</script>
<style lang="scss">
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
二、组件打包
1.配置打包命令
在package.json中增加打包命令
“package”: “vue-cli-service build --target lib ./src/package/index.js --name sdui --dest sdui”
说明:
target lib 关键字 指定打包的目录
name 打包后的文件名字
dest 打包后的文件夹的名称
执行打包命令:npm run package
打包完成后,会生成我们指定的sdui文件目录,里面存放的就是打包后的文件。
2. 初始化package.json
{
"name": "zhang-sdui",
"version": "1.0.5",
"description": "vue 组件发布npm示例",
"main": "zhang-sdui.common.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"vue组件",
"npm发布"
],
"author": "",
"license": "ISC"
}
3. 增加README.md文件
# 项目组
## MyCard
卡片
### 代码
<my-card :summary="summary" :imgSrc="img">
<div slot="footer">
<button class="btn">查看</button>
</div>
</my-card>
#### Attributes
| 参数 | 说明 | 类型 | 是否必要 | 默认值 |
| --------- | ------------ | ----------- | -------- | ------ |
| width | 卡片宽度 | Number | false | 500 |
| imgSrc | 图片资源路径 | String | true | - |
| imgHeight | 图片高度 | Number | false | 100 |
| summary | 卡片概要 | String/Slot | false | - |
| footer | 卡片底部 | Slot | false | - |
三、打包后本地测试
先本地测试一下,没有问题了在打包上传到npm
main.js引用 sdui 文件下的umd.js 和css.js
app.vue 引用my-card
import sdui from './libs/sdui.umd.min.js';
import './libs/sdui.css';
Vue.use(sdui)
<my-card :summary="summary" :imgSrc="img">
<div slot="footer">
<button class="btn">查看</button>
</div>
</my-card>
但是控制台报错
原因是因为 打包用的export default ,umd文件内是 module.exports
那么解决
安装依赖 babel
vue add babel
根目录配置 babel.config.js
module.exports = {
presets: [
[
'@vue/cli-plugin-babel/preset'
]
]
}
然后在再根目录配置 vue.config.js
module.exports = {
chainWebpack: config => {
if (process.env.NODE_ENV === 'production' && process.env.VUE_APP_TARGET === 'lib') {
config.output
.library('sdui')
.libraryTarget('umd')
.umdNamedDefine(true);
// 如果需要兼容commonjs和es module,可以添加如下配置
config.externals({
vue: 'vue'
});
// 调整输出目录
config.output.path.resolve(__dirname, 'sdui');
}
},
transpileDependencies: [],
};
这样就完美解决了
四、发布到npm
1.npm账号
如果没有npm账号,需要先注册一个账号
2 发布
再次确认一下当前终端地址是不是组件打包的目录,如果是项目主目录,发布的时候,会把事个项目发到npm仓库,导致组件不能正确的被引用和使用
首先登录npm
npm login
会要求输入用户名、密码、邮箱,登录成功后就可以发布了
登录成功后会提示
Logged in as account on https://registry.npmjs.org/.
执行npm publish发布组件到npm
需要注意:package.json里的name属性必须唯一,如果npm上已存在,是不让发布的,所以发布前最好在npm上查一下自已的包包是否已被占用
登录 npmjs.com,查看自己的包,如下
五、使用组件
执行 npm i zhang-sdui 安装组件
在main.js中添加引用
import sdui from 'zhang-sdui';
import 'sdui/sdui.css'
Vue.use(sdui);
<my-card :summary="summary" :imgSrc="img">
<div slot="footer">
<button class="btn">查看</button>
</div>
</my-card>