vue自定义封装组件,并发布到npm或nexus上

596 阅读2分钟

在日常工作中,会编写一些通用组件,但通用的组件常常需要在各个项目中使用,于是就有了打包发布自己的组件库的需求,这里参考了 ant-design-vue 的源码学着做了一个简单的示例。

ant-design-vue库的使用流程是这样的:在main.js中引入ant-design-vue包和样式文件,然后Vue.use就好了,在页面上就可以直接使用,所以这里也参考这样的使用方式来开发自己的组件库。

import Vue from "vue";
import App from "./App.vue";
// 引入 ant design
import Antd from "ant-design-vue";
// 引入 ant design 样式
import "ant-design-vue/dist/antd.less";

Vue.use(Antd);

new Vue({
  render: (h) => h(App),
}).$mount("#app");

这里用的是vue2.x、webpack4.x、less来做的,相关的使用和配置可参考对应版本的文档

1,创建项目

创建一个vue项目,用于预览vue组件的效果

vue create moss-ui

由于我这里要用到less,所以还得安装一些less-loader

yarn add less-loader@6.2.0 -D

2,编写组件(在根目录下新建一个components目录)

image.png

大致代码如下:

components/button/Button.vue

<template>
  <button class="xx-button">
    <slot></slot>
  </button>
</template>

<script>
export default {
  name: "xx-button",
};
</script>

components/button/Button.less

@import "../style/global.less";

.xx-button {
  color: #fff;
  background-color: @primary-color;
  padding: 10px;
  border: none;

  &:hover {
    background-color: lighten(@primary-color, 10%);
  }
}

components/style/global.less

@primary-color: #e55039;

components/style/index.less(引入所有组件的样式)

@import "../button/Button.less";
@import "../tag/Tag.less";

components/components.js(引入并导出所有的组件)

export { default as XxButton } from "./button/Button";
export { default as XxTag } from "./tag/Tag";

components/index.js(要打包的文件)

先引入所有的组件以及组件的样式文件,然后编写install函数(vue插件所需,可参考v2.cn.vuejs.org/v2/guide/pl…),在install函数中注册所有组件,最后导出install

import * as components from "./components";
import "./style/index.less";

const _components = Object.values(components);

function install(Vue) {
  _components.forEach((component) => {
    Vue.component(component.name, component);
  });
}

export default {
  install
};

到这里,组件就算是完成了,可以编写一个vue页面来预览下组件的效果。

main.js

import Vue from "vue";
import App from "./App.vue";
// 引入组件
import components from "../components";
// 引入组件样式
import "../components/style/index.less";

Vue.config.productionTip = false;

// 使用组件
Vue.use(components);

new Vue({
  render: (h) => h(App),
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <h1>moss-ui</h1>
    <div>
      <xx-button>button</xx-button>
    </div>
    <div>
      <xx-tag>tag</xx-tag>
    </div>
  </div>
</template>

image.png

3,打包组件

1,修改package.json文件

  • name 包名称
  • version 包版本号
  • private 为true的话上传不了到npm或nexus的
  • files 是需要上传的文件或目录,如果不写会把所有的代码都上传(lib是打包后的代码目录)
  • main 是指定使用的主程序文件(import MossUI from 'moss-ui' 的时候其实是会指向到这个文件来的)
  • vue-cli-service build --mode lib --target lib --name moss-ui --dest lib components/index.js 这句命令会将 components/index.js 文件打包到lib目录(相关参数可参考:cli.vuejs.org/zh/guide/cl…
{
  "name": "moss-ui", 
  "version": "1.0.0", 
  "private": false,
  "main": "lib/moss-ui.umd.min.js",
  "files": [
    "lib"
  ],
  "scripts": {
    "serve": "vue-cli-service serve --mode dev",
    "build": "vue-cli-service build --mode production",
    "lint": "vue-cli-service lint",
    "lib": "vue-cli-service build --mode lib --target lib --name moss-ui --dest lib  components/index.js"
  }
  .....
}  

2,执行yarn lib会生成打包后的文件

image.png

3,将main.js修改下,然后再预览效果,组件如预期显示了说明打包没问题了

import Vue from "vue";
import App from "./App.vue";
// 引入组件
import components from "../lib/moss-ui.umd";

// 使用组件
Vue.use(components);

new Vue({
  render: (h) => h(App),
}).$mount("#app");

上面的打包会把css也打包进去,如果我们需要独立提取出css文件来,那可以修改配置文件vue.config.js(没有则创建一个)

module.exports = {
  ......
  css: {
    extract: true, // 添加该配置会独立提取出css文件来
  }
}

修改配置后重新打包,可以看到css文件被提取出来了

image.png

但这样的css是将less编译后的,如果想要在项目中覆盖组件的全局变量就不行了,按ant-design-vue的用法是可以引入less文件,例如这样:

import "ant-design-vue/dist/antd.less";

那这里就需要在打包的时候把所有的less文件也拷贝到lib目录下, 这样使用的时候就能直接引入了,这里就需要使用到CopyWebpackPlugin插件了,这个插件vue-cli内置了,所以直接使用就可以了(具体使用可参考:v4.webpack.js.org/plugins/cop…

修改vue.config.js文件

  • from是需要被拷贝的文件路径,比如将components目录下所有的less文件拷贝出来
  • to是目的地文件路径,这里按源文件的路径、名称、后缀原样拷贝
  • toType这里要填写template,否则to中的变量会被解析成字符串
const CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {
  ......
  css: {
    extract: true,
  },
  chainWebpack: (config) => {
    config.plugin("copyWebpackPlugin").use(
      new CopyWebpackPlugin([
        {
          from: "components/**/*.less",
          to: "[path][name].[ext]",
          toType: "template",
        },
      ])
    );
  },
};

再重新打包后,目录下的所有less文件被拷贝出来了

image.png

修改main.js,效果如预期一样

import Vue from "vue";
import App from "./App.vue";
import components from "../lib/moss-ui.umd";
import "../lib/components/style/index.less";

Vue.config.productionTip = false;

Vue.use(components);

new Vue({
  render: (h) => h(App),
}).$mount("#app");

在项目中覆盖组件中的全局变量需要添加loaderOptions配置(参考:cli.vuejs.org/zh/config/#…

module.exports = {
  ......
  css: {
    extract: true,
    loaderOptions: {
      less: {
        lessOptions: {
          modifyVars: {
            "@primary-color": "#575fcf",
          },
          javascriptEnabled: true,
        },
      },
    },
  },
  ......
};

添加配置后再打包,效果如下:

image.png

发布组件

这样一个基本的组件就算开发完成了,那么就可以开始推送到npm或nexus上了,我这里以公司内网搭建的nexus为示例(npm注册地址:www.npmjs.com/signup)

1,注册账号

2,登录 npm login --registry=https://xxx.com/repository/npm-xxx,输入账号、密码、邮箱 image.png

3,推送 npm publish --registry=https://xxx.com/repository/npm-xxx image.png

大功告成,这样就可以在项目里去安装使用了

1,安装包 npm install moss-ui --registry=https://xxx.com/repository/npm-group

image.png

2,引入包,启动项目预览,效果如预期的一样一样

import Vue from "vue";
import App from "./App.vue";
import components from "moss-ui";
import "moss-ui/lib/components/style/index.less";

Vue.config.productionTip = false;

Vue.use(components);

new Vue({
  render: (h) => h(App),
}).$mount("#app");

最后奉上项目示例:github.com/leietal/mos…