【保姆级教程】使用vue2从零搭建自己的私有组件库

1,850 阅读5分钟

在实际开发中,我们除了常用的几种ui组件库外,可能还会有涉及到的公司定制化业务,需要我们自定义自己的组件库,并打包发布到私服npm上,以下为步骤:

  1. 创建项目开发并业务组件;
  2. 打包组件;
  3. 搭建私服npm;
  4. 发布组件到私服npm;
  5. 可能需要国际化(按需);
  6. 搭建组件库文档。

注意:因为涉及到部分版本信息,所以这里用到的npm版本7.24.0,node版本16.17.0

一、 创建项目

  1. 创建vue2项目。
vue create demo-ui
  1. 项目结构

image.png

在项目的根目录下创建conponents文件夹,如上图。

  1. 修改vue.config.js 新增pages属性,修改入口的配置,如下所示:
//vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  pages:{
        index:{
            entry:'src/main.ts',
            template:'public/index.html',
            filename:'index.html'
        }
    },
})
  1. components文件夹如下:

image.png

  • 建立css文件夹和lib文件夹
  • css文件夹用于存放样式文件

这里用到了sass,所以我们需要安装sass,版本如下:

"node-sass": "4.14.1",
"sass": "1.26.2",
"sass-loader": "^13.2.0",

我是用yarn安装的,命令如下:

yarn add  sass node-sass@4.14.1 sass-loader@13.2.0

同时新建css文件,文件结构还是如上图。
index.scss:

@import "./card.scss";

card.scss:

// card的相关css配置;
  • lib文件夹用于存放各个组件,并建立主index.js导出全部组件
//  lib/index.js
import Card from './card';

const components = {
  Card
}

const install  = function(Vue){
  if(install.installed) return;
  Object.keys(components).forEach(key =>{
    Vue.component(components[key].name,components[key])
  })
}

const API = {
  install
}
export default API;

export {
  Card
}
  1. 组件开发。 一个组件是一个单独的文件夹,在components/lib文件下建立对应的文件夹,比如card:
    建立card/src/main.vue和card/index.js两个文件,
    card目录如下:

image.png

/components/lib/card/main.vue内容如下:

<template>
    <div class="demo" :style="width ? {width: width + 'px'} : {}">
      <div class="demo-card-img" :style="imgHeight? {height:imgHeight+'px'}:{}">
          <img :src="imgSrc" alt="img" />
      </div>
      <div class="demo-card-summary" v-if="summary">
        {{summary}}
      </div>
      <div v-else class="demo-card-summary">
        <slot></slot>
      </div>
      <slot name="footer"></slot>
    </div>
  </template>
  
  <script>
  export default {
      name:'demo-card',
      props: {
        width: { //卡片宽度
          type:Number,
          default:0
        },
        imgSrc: { //卡片图片资源
          type:String,
          default:''
        },
        imgHeight: { //图片高度
          type:Number,
          default:0
        },
        summary: { //卡片概要
          type:String,
          default:''
        },
      }
  }
  </script>
  <style>
  </style>

components/lib/card/index.js内容如下:

import Card from './src/main.vue'
Card.install = function(Vue) {
    Vue.component(Card.name,Card)
}
export default Card

main.ts中引入(这里我用到的语法是ts)

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";

import '../components/css/card.scss'
import Card from  '../components/lib/card/index'
Vue.use(Card)

Vue.config.productionTip = false;

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

  1. App.vue中使用卡片组件
<template>
  <div id="app">
    <m-card
     imgSrc="logo.png"
     summary="这是一个自定义的demo组件"
    >
    <template v-slot:footer>
      <div class="footer">
        <div class="left">这是第一行</div>
        <div class="right">这是第二行</div>
      </div>
    </template>
    </m-card>
  </div>
</template>

<script>


export default {
  name: 'App',
  components: {
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

执行yarn serve启动vue项目,查看组件效果,卡片显示如下:

image.png

二、组件库打包 这里用到的是webpack和gulp打包。

  1. 根目录下创建文件webpack.components.js
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const glob = require('glob')
const list = {}
async function makeList(dirPath,list){
    const files = glob.sync(`${dirPath}/**/index.js`)
    for(let file of files) {
        const component = file.split(/[/.]/)[2]
        list[component] = `./${file}`
    }
}
makeList('components/lib',list)
module.exports = {
  entry:list,
  mode:'development',
  output: {
      filename:'[name].umd.js',
      path:path.resolve(__dirname,'dist'),
      library:'rui',
      libraryTarget:'umd'
  },
  plugins: [
      new VueLoaderPlugin()
  ],
  module:{
      rules: [
          {
              test:/\.vue$/,
              use: [
                  {
                      loader: 'vue-loader'
                  }
              ]
          },
          {test:/\.css$/, use: ['css-loader']},
          {test:/\.scss$/, use: ['css-loader','sass-loader',]},
          {test:/\.(jpg|png|gif|bmp|jpeg)$/, loader: 'url-loader'},
          {test:/\.(ttf|eot|svg|woff|woff2)$/,use: 'url-loader'}
      ]
  }
}
  1. package.json中添加打包命令
"build:js": "webpack --config ./webpack.components.js"

image.png 4. 执行打包命令,将js打包为umd模块

yarn build:js

效果如下图:
image.png
执行后如果提示需要安装webpack-cli,输入yes安装即可。
index.umd.js提供整个组件库的引入使用;
card.umd.js可提供组件库的按需引入。

如果webpack打包js报错vue-loader.....,则安装对应的依赖:

 yarn add vue-loader@15.9.8
 yarn add vue-template-compiler@2.7.14

注意 vue-template-compiler@2.7.14 这儿的版本需要和vue的版本一致,可通过vue -v来获取当前版本,若安装的不一致,也会报错提示你的版本应该是多少。

  1. 使用gulp打包css文件。
  • 根目录新建gulpfile.js

安装gulp相关的依赖,

yarn add gulp gulp-sass gulp-minify-css
//gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass')( require ( 'sass' ) )  //sass转成css
const minifyCSS = require('gulp-minify-css') //压缩
gulp.task('sass',async function(){
    return gulp.src('components/css/**/*.scss')
    .pipe(sass())
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist/css'))
})
  • package.json添加打包命令
"build:css": "npx gulp sass",
  • 执行打包命令,将css打包
yarn build:css

若打包时sass报错,则删掉重新安装sass。

正确时输入如下:

image.png

也可整合js和css打包命令

    "build:lib": "npm run build:js && npm run build:css"

执行yarn build:lib,一键打包js和css文件,
控制台输出如下:

image.png

三、搭建自己的私服npm
使用verdaccio搭建npm私服,发布组件库。verdaccio官方文档

1、安装和配置

yarn global add verdaccio 

成功后启动:

verdaccio

这里要注意第一行打印的信息,这个yaml文件就是verdaccio的配置文件,后面我们需要修改该文件进行相关配置。

image.png

2、启动成功后,直接在浏览器输入服务器的ip地址 + 最后一行打印出的端口号,看到这样的页面就说明安装成功了。如果访问不了可能是因为服务器防火墙没关,可以检查下防火墙。

image.png

3、修改配置文件 config.yaml

用记事本打开config.yaml,修改两个位置:

  • 把listen改成自己的域名地址;
  • ax_users 设为 -1,禁止注册用户,一般情况下都应该由管理员派发账号,禁用后再添加用户会直接报错

如下图:

image.png

image.png

注意 listen不要换行,不然会失败。

禁用后我们可以通过这个网站 添加账号密码,然后分发给对应的人

image.png

复制红框内生成的密码,创建htpasswd文件并将密码copy进去。

image.png

四、发布到私服npm。
1、package.json文件修改

"private": false,//这里要设置成false
  "description": "自定义组件demo",
  "main": "./dist/index.umd.js",//指定入口文件
  "keywords": [ // 关键字,方便搜索
    "vue",
    "typescript",
    "demo-ui",
    "demoui",
    "element-ui"
  ],
  "author": "admin", //作者
  "files": [ //指定发布的文件目录
    "dist",
    "components"
  ],

2、安装nrm并切换npm源到我们私有的仓库地址
这里使用到了nrm来管理npm registry

yarn add global nrm
// 添加自定义的源 源就是启动verdaccio时打印出来的地址
nrm add demo-ui http://1xx.xx.xx:xxxx/

// 查看所有可用的源
nrm ls 

// 切换源到我们的私有仓库
nrm use demo-ui

安装nrm或者使用的时候若报错 code: 'ERR_REQUIRE_ESM'

const open = require('open');
             ^
Error [ERR_REQUIRE_ESM]: require() of ES Module D:\nodejs\node_global\node_modules\nrm\node_modules\open\index.js from D:\nodejs\node_global\node_modules\nrm\cli.js not supported.
Instead change the require of index.js in D:\nodejs\node_global\node_modules\nrm\cli.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (D:\nodejs\node_global\node_modules\nrm\cli.js:9:14) {
  code: 'ERR_REQUIRE_ESM'

若报错如下:
an error occured: Error: EACCES: permission denied, open '/Users/kl/.nrmrc'
则用sudo执行命令,获取权限。

则打开该文件将require改为import重新保存后可成功运行。
3、如果没有创建账户的,可以先创建账户

npm adduser --registry http://1xx.xx.xx:xxxx/

4、然后发布包

npm publish --registry http://1xx.xx.xx:xxxx/

发布成功后,再访问私有仓库地址,就会发现自己的包已经发了上去。

image.png

  1. 具体使用: 新项目中yarn add demo-ui即可。
//全局引用
import xxx from 'demo-ui';
import 'demo-ui/dist/css/index.css';
Vue.use(xxx)


//按需引用
import {Card} from 'demo-ui';
import 'demo-ui/dist/css/card.css';
Vue.use(Card)