创建vue组件库并发布到npm

1,815 阅读2分钟

创建vue组件库

例子中我们采用webpack来构建自己的工程

创建package.json文件,加入需要引用的依赖包

{
  "name": "xxxx",
  "description": "xxxx",
  "version": "1.0.0-beta.3",
  "author": "Tinylj(lujin.pt@163.com)",
  "license": "MIT",
  "private": false,
  "main": "dist/xxx.js",
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot --config build/webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.prod.js"
  },
  "dependencies": {
    "vue": "^2.5.11",
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.11",
    "style-loader": "^0.23.1",
    "file-loader": "^1.1.4",
    "less": "^2.7.3",
    "less-loader": "^4.1.0",
    "url-loader": "^1.1.2",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-dev-server": "^2.9.1",
    "webpack-merge": "^4.1.0"
  },
  "files": [
    "dist"
  ]
}

version中是我们需要发布到npm的版本号。 files中是我们需要上传到npm的文件夹目录,如果我们不想开源,则只需要上传webpack打包之后的dist文件夹 配置对应的webpack.common.js,webpack.dev.js以及webpack.prod.js,这里webpack的知识点就不详细展开了。 随后在src文件夹中和我们平常书写一个vue组件一样。

书写一个组件,并输出他

创建一个组件,这个组件是一个定制化的Input输入框,支持各种属性的变化,事件,状态等。src/packages/input/src/main.vue

<template>
    <span class="lh-input" :class="[state ? `lh-input-${state}` : '',disabled ? 'lh-input-disabled' : '',size]">
      <input
        class="lh-input-cornInput"
        :value="inputValue"
        :type="type"
        :name="name"
        :placeholder="placeholder"
        v-bind:required = "required?true:false"
        :min="min"
        :max="max"
        :pattern="pattern"
        :title="title"
        :minlength="minlength"
        :maxlength="maxlength"
        :disabled="disabledVal"
        :readonly="readonly"
        :autofocus="autofocus"
        @focus="handleFocus"
        @blur="handleBlur"
        @input="handleInput"
        @change="handleChange"
      >
      <i class="lh-input_icon" :class="lhInputIcon" v-if="state">
          <i class="lh-input_icon_img"></i>
          <div class="lds-css ng-scope"><div style="width:100%;height:100%" class="lds-dual-ring"><div></div></div></div>
      </i>
    </span>
</template>

<script>
    /**
     * lhInput
     * @module components
     * @param  {String}        size  - size大小。 mini有特殊样式
     * @param  {Boolean}       readonly   - 是否只读
     * @param  {Boolean}       disabled   - 是否禁用
     * @param  {Boolean}       autofocus   - 是否自动聚焦
     * @param  {String}        type    - 输入框类型【text,password】
     * @param  {String,Number} value   - 输入框内容
     * @param  {String}        placeholder       - 提示语
     * @param  {Number}        maxlength       - 最大长度
     * @param  {Number}        minlength       - 最小长度
     * @param  {Number}        max       - 最大值
     * @param  {Number}        min       - 最小值
     * @param  {String}        state      - 状态【success,error,warn,loading】
     *
     *
     * @param   {Function}  blur 输入框失去焦点事件
     * @param   {Function}  focus 输入框获得焦点触发事件
     * @param   {Function}  change 输入框内容改变事件
     */
    export default {
        name: 'lhInput',
        componentName: 'lhInput',
        props: {
            type: {
                type: String,
                default: 'text'
            },
            size: {
                type: String,
                default: ''
            },
            pattern: {type: String},
            title: {type: String},
            required:{type:[Boolean,String],default:false},
            name: String,
            value: [String, Number],
            placeholder: String,
            state: String,
            readonly: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            autofocus: {
                type: Boolean,
                default: false
            },
            maxlength: [Number,String],
            minlength: [Number,String],
            max: Number,
            min: Number
        },
        data() {
            return {
                inputValue: this.value,
            }
        },
        methods: {
            handleFocus(event) {
                this.$emit('focus', event); //这里触发一个event,外界就可以用 @标记吗?
            },
            handleBlur(event) {
                this.$emit('blur', event);

            },
            handleInput(event) {
                var value = event.target.value
                this.$emit('input', value)
                this.$emit('change', value)
            },
            handleChange(event) {
                // var value = event.target.value
                // this.$emit('change', value)
            },
        },
        computed: {
            lhInputIcon() {
                var name = this.state;
                return name ? `lh-icon-${name}` : ''
            },
            disabledVal() {
                var val = this.disabled || this.state === 'loading';
                return val
            }
        },
        watch: {
            value(val) {
                if (val === this.inputValue) return;
                this.inputValue = val
            },

        },
        mounted: function () {


        },
    };
</script>

输出这个main.vue文件 src/packages/input/index.js

import lhInput from './src/main.vue';

/* istanbul ignore next */
lhInput.install = function(Vue) {
  Vue.component(lhInput.name, lhInput);
};
export default lhInput;

支持npm install 以及构建npm build指向的inde.js

src根目录下创建src/index.js

import lhInput from './packages/input/index';
const components = [
  lhInput,
  // ...如果还有的话继续添加
]
const install = function (Vue, opts = {}) {
  components.map(component => {
    Vue.component(component.name, component);
  })
}
/* 支持使用标签的方式引入 */
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}
export default {
  install,
  lhInput,
}

经过以上几个步骤,我们已经简单的构建了一个可以发布到npm并支持标签引用的webpack+vue工程。 发布到npm之后,可以被其他工程引入,刚才的input组件也可以直接以 的方式直接引用到工程里。

延伸阅读 如何对组件库进行调试

我们大概率不会每次调试组件都把组件再发布到npm用其他工程引用的方式来调试,而是本地webpack-dev-server来启动。 那么我们则需要把npm run dev 和 npm run build分开。

src根目录下创建src/main.js 使用npm run dev指向这个入口文件。

import Vue from 'vue';
import App from './App.vue';
// import 'babel-polyfill';
import router from './router';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import '../static/css/theme-common/main.less';
new Vue({
  router,
  render: h => h(App)
}).$mount('#app');

延伸阅读 如何构建主题包

没人看,下次再讲

npm

什么是npm

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用。 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。 再看一个官网的解释: Essential JavaScript development tools that help you go to market faster and build powerful applications using modern open source code.

如何发布一个自己的npm包

1:创建一个npm的账号

2:npm run build 内容打包到dist文件夹。

3:npm login 登录自己的账号

4:npm publish 发布到npm 上。