自定义vue组件发布npm仓库

前言

使用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>

但是控制台报错
*import sdui from './libs/sdui.umd.min.js';
Vue.use(sdui)注册后报错:Cannot read properties of undefined (reading 'install')*
原因是因为 打包用的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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值