在npm上发布属于自己的Vue组件

917 阅读5分钟

写在前面

作为一个初级前端,还是要有点理想的,之前有想过开发一个vue组件上传到npm上以供大家使用,但是因为工作业务繁忙,一直鸽到现在才有时间做。

开发组件还是比较容易的,第一次弄的话,难点就在如何打包以便于vue的引入使用。

关于这点,我在网上搜罗了大部分文章,讲的都比较笼统,而且很多也没有标明开发环境和版本,导致开发的时候会遇到一些问题(没错,之前我是用vue-cli2搭建的环境,项目里面要配置webpack等配置都在config和build文件夹里面,但是网上大部分资料都是基于@vue/cli3开发的,对于webpack理解比较少的童鞋来说可能会有点难以理解)。

一、准备项目

就是一个轻量级的toast,所以就只基于vue就好了。

// 当前组件开发的脚手架版本
npm install @vue/cli3

二、启动服务

image.png

刚装好的环境发现启动报错,是需要去添加一个eslint的配置文件。

// 直接在根目录下新建一个 .eslintrc.js 文件就好,cv网上大部分默认配置
// https://eslint.org/docs/user-guide/configuring
module.exports = {
    root: true,
    parserOptions: {
        parser: 'babel-eslint'
    },
    env: {
        browser: true,
    },
    extends: [
        'plugin:vue/essential'
        // 'standard' // 这个加上的话太魔鬼了,我没加
    ],
    plugins: [
        'vue'
    ],
    rules: {
        'generator-star-spacing': 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
    }
}

三、准备代码

项目结构需要做一些修改,以前的src目录可以改成examples或者其他类似的名字,这算是一个使用示例。

然后新建一个packages或components的文件夹存放组件,如果你以后想开发多个组件库的话,就直接往这个文件夹里面加就好了。

这里先配置一下vue.config.js,因为vue/cli3隐藏了build和config文件,所以需要在这去进行配置。

// 这里是搬运的  大概就是修改项目启动的入口。
module.exports = {
  pages: {
    index: {
      entry: "examples/main.js",
      template: "public/index.html",
      filename: "index.html"
    }
  },
  chainWebpack: config => {
    config.module
    .rule('js')
    .include
    .add(__dirname + 'packages')
    .end()
    .use('babel')
    .loader('babel-loader')
    .tap(options => {
      return options;
    })
  }
}

接下来就是组件的开发

// packages文件夹组成
- packages
  - toast
    + iconfont // 所用到的字体图标
    + src // 如果还需要其他的依赖可以放这里面
    index.js
    toast.vue
// packages/toast/toast.vue
<template>
  <div class="toast" v-if="show">
    <i v-if="type == 'info'" class="iconfont-vue-toast icon-vue-toast-info"></i>
    <i v-if="type == 'success'" class="iconfont-vue-toast icon-vue-toast-success"></i>
    <i v-if="type == 'danger'" class="iconfont-vue-toast icon-vue-toast-dangerous_1"></i>
    <i v-if="type == 'error'" class="iconfont-vue-toast icon-vue-toast-error"></i>
    {{ msg }}
  </div>
</template>

//<style>样式就不展示了</style>
// packages/toast/index.js
import toast from './toast.vue'
import './iconfont/iconfont.css'
export default (Vue) => {
  const ToastComp = Vue.extend(toast)
  const typeCate = ['info', 'success', 'danger', 'error']
  function showToast(data) {
    if (!data.duration) data.duration = 2.5e3
    if (!data.type || !typeCate.includes(data.type)) data.type = 'info'
    const toastDom = new ToastComp({
      data() {
        return {
          show: true,
          msg: data.msg,
          type: data.type
        }
      }
    }).$mount(document.createElement('div'))
    document.body.appendChild(toastDom.$el)
    setTimeout(() => {
      toastDom.show = false
    }, data.duration)
  }
  Vue.prototype.$toast = showToast
}

toast组件用到的代码就这点了。

测试环节

在之前的examples(src)文件夹下的main.js进行引入测试。

// examples/main.js
import toast from "/packages/toast/index"
Vue.use(toast)

// examples/app.vue
mounted() {
  this.$toast({ type: 'success', msg: '测试文字' });
}

image.png image.png

没问题的话就可以准备打包配置了。

// package.json
{
  "name": "vue-toast", // 项目的名字 要发布的话,这里会修改,天坑,后面讲
  "description": "基于 Vue 的轻量级toast", // 简单的描述
  "main": "lib/vueToast.umd.min.js", // 打包后的主体文件,也算是import需要导入的文件
  "keywords": ["vue-toast", "toast-vue"],
  "version": "0.1.0", // 版本号
  "private": false, // 要发布的话,这里必须改成false哟
  "scripts": {...},
  "dependencies": {...},
  "devDependencies": {...}
}

直接利用package.json里面build选项进行构建打包,添加一行代码进行自定义输出。

// package.json
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
  + "build:test": "vue-cli-service build --target lib --name vueToast --dest lib ./packages/toast/index.js",
    "lint": "vue-cli-service lint"
  }

之后运行npm run build:test进行打包测试,发现可以按照要求打包并输出成自定义的格式。

image.png

打包后在根目录下会出现lib文件夹,然后在examples里面的main.js引入打包好的文件

import Vue from 'vue'
import App from './App.vue'

import toast from '../lib/vueToast.umd'

Vue.config.productionTip = false

Vue.use(toast)

window.hv = new Vue({
  render: h => h(App)
}).$mount('#app')

启动项目进行测试

image.png

诶,很尴尬,toast的样式丢失了。从打包后的文件里面查看了一下,发现是因为css文件和js文件并没有关联上,想的是引入了js文件,没有引用到css文件导致的。但是每次又要引入两个文件就很烦,网上搜罗了一下,发现还真有办法解决。

在vue.config.js里面添加

// vue.config.js
module.exports = {
  pages: {...},
+ css: {
+   extract: false
+ }
}

这样打包出来的组件,css就和js嵌入到一起的。

image.png

将就刚刚的网页进行测试,发现css已经渲染上了,那就万事大吉。

image.png

四、NPM发布

如果没有npm账号的话,需要先去注册一个账号哟,具体注册流程就不展示了。

如果之前有登录过的童鞋可以通过npm whoami 查看当前的登录情况。

在登录之前,如果有设置过淘宝镜像的童鞋,需要把镜像地址切换回来。

npm config set registry https://registry.npmjs.org/
# 切换回来后,进行登录
npm login # 回车
Username: [yourname] # 回车确定
Password:          # 密码不会显示,尽管输就好了 回车确定
Email: (This IS pubilc)xxxxxxxx@xx.com # 回车确定
Logged in as [yourname] on http://registry.npmjs.org/. # 这里就是提示登录成功了。

发布前需要在根目录下新建一个.npmignore文件用来忽略不需要发布的文件(夹)。

# 忽略目录
examples/
packages/
public/

# 忽略指定文件
vue.config.js
babel.config.js
*.map

接下来就是发布了。

npm publish

image.png

如果你取名比较特殊,多半能给直接发布成功,但是如果你想使用的名字被别人使用了,那么就不能发布(如上图),需要更换名字,或者使用组织仓库。

现在去创建一个组织仓库。

打开npmjs官网,登录

image.png

头像点击后,可以选择Packages选项,进入包页面再进行选择 Add Organization操作,或者直接点击+ Add Organization。

image.png

预算充足的童鞋可以购买付费版,当然也可以使用免费版。可以直接使用你当前的用户名当做组织名(最下面),也可以自定义(上面的input里面输入你想创建的name),然后下一步创建就好了。

创建好了之后,可以在Packages页面,左侧导航栏看到你创建的组织。这个时候我们就可以回到vscode继续发布了。

这里发布到组织的话,需要修改到package.json

// package.json
{
  "name": "@xxx/vue-toast", // @xxx就是你的组织名,斜杠后面的就是包名
   ...
+ "publishConfig": {
+   "access": "public"
+ },
  "scripts": {...},
  "dependencies": {...},
  "devDependencies": {...}
}

这个时候再进行发布,就可以成功发布到你当前组织的仓库了,别人也是可以下载使用的。

npm publish

别人需要使用的话,就npm install @xxx/name --save就可以了。

源码:github.com/SsikRoEsor/…

来自初级前端的第一次尝试,如有没写好的地方,请多指教(轻点喷😅😅)。